fix: peer access to /api/services/active and unconditional Caddy startup regen
Unit Tests / test (push) Successful in 7m23s
Unit Tests / test (push) Successful in 7m23s
- Add _PEER_READABLE_PATHS allowlist in enforce_auth so peer-role sessions can read /api/services/active; fixes My Services showing 'not installed' for cell members when services are installed - Move Caddy regeneration before the early-return in reapply_on_startup so the Caddyfile is always rebuilt from current identity on startup, even when no store services are installed; fixes ERR_SSL_PROTOCOL_ERROR after a cell rename (Caddyfile retained old wildcard domain) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -187,6 +187,13 @@ def enforce_setup():
|
|||||||
return jsonify({'error': 'Setup required', 'redirect': '/setup'}), 428
|
return jsonify({'error': 'Setup required', 'redirect': '/setup'}), 428
|
||||||
|
|
||||||
|
|
||||||
|
# Read-only endpoints accessible to peer-role sessions (not just admin).
|
||||||
|
# Add paths here when peers need to read shared cell state.
|
||||||
|
_PEER_READABLE_PATHS = frozenset({
|
||||||
|
'/api/services/active',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def enforce_auth():
|
def enforce_auth():
|
||||||
"""Enforce session-based authentication and role-based access control.
|
"""Enforce session-based authentication and role-based access control.
|
||||||
@@ -238,6 +245,8 @@ def enforce_auth():
|
|||||||
if path.startswith('/api/peer/'):
|
if path.startswith('/api/peer/'):
|
||||||
if role != 'peer':
|
if role != 'peer':
|
||||||
return jsonify({'error': 'Forbidden'}), 403
|
return jsonify({'error': 'Forbidden'}), 403
|
||||||
|
elif path in _PEER_READABLE_PATHS:
|
||||||
|
pass # both admin and peer may read these endpoints
|
||||||
else:
|
else:
|
||||||
if role != 'admin':
|
if role != 'admin':
|
||||||
return jsonify({'error': 'Forbidden'}), 403
|
return jsonify({'error': 'Forbidden'}), 403
|
||||||
|
|||||||
@@ -407,6 +407,19 @@ class ServiceStoreManager(BaseServiceManager):
|
|||||||
from firewall_manager import apply_service_rules
|
from firewall_manager import apply_service_rules
|
||||||
|
|
||||||
installed = self.config_manager.get_installed_services()
|
installed = self.config_manager.get_installed_services()
|
||||||
|
|
||||||
|
# Always regenerate the Caddyfile so a cell rename or fresh install
|
||||||
|
# produces the correct domain even when no store services are installed.
|
||||||
|
try:
|
||||||
|
caddy_routes = [
|
||||||
|
r.get('caddy_route')
|
||||||
|
for r in (installed or {}).values()
|
||||||
|
if r.get('caddy_route')
|
||||||
|
]
|
||||||
|
self.caddy_manager.regenerate_with_installed(caddy_routes)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f'reapply_on_startup: caddy regenerate failed: {e}')
|
||||||
|
|
||||||
if not installed:
|
if not installed:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -419,17 +432,6 @@ class ServiceStoreManager(BaseServiceManager):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f'reapply_on_startup: apply_service_rules({svc_id}) failed: {e}')
|
logger.warning(f'reapply_on_startup: apply_service_rules({svc_id}) failed: {e}')
|
||||||
|
|
||||||
# Regenerate Caddyfile
|
|
||||||
try:
|
|
||||||
caddy_routes = [
|
|
||||||
r.get('caddy_route')
|
|
||||||
for r in installed.values()
|
|
||||||
if r.get('caddy_route')
|
|
||||||
]
|
|
||||||
self.caddy_manager.regenerate_with_installed(caddy_routes)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f'reapply_on_startup: caddy regenerate failed: {e}')
|
|
||||||
|
|
||||||
# Bring up per-service compose stacks
|
# Bring up per-service compose stacks
|
||||||
if self.service_composer is not None:
|
if self.service_composer is not None:
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user