Phase 1: first-run setup wizard, bash installer, Docker profiles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-09 08:05:38 -04:00
parent 6dbd0dff46
commit cf1b9672f4
12 changed files with 1754 additions and 16 deletions
+28 -2
View File
@@ -40,7 +40,7 @@ from managers import (
network_manager, wireguard_manager, peer_registry,
email_manager, calendar_manager, file_manager,
routing_manager, vault_manager, container_manager,
cell_link_manager, auth_manager,
cell_link_manager, auth_manager, setup_manager,
firewall_manager, EventType,
)
# Re-exports: tests do `from app import CellManager` and `from app import _resolve_peer_dns`
@@ -158,6 +158,28 @@ def enrich_log_context():
'user': user
})
@app.before_request
def enforce_setup():
"""Block API requests until the first-run wizard has been completed.
The setup routes, /health, and all non-/api/ paths are always allowed
through. Any other /api/* request while setup is incomplete receives
a 428 with a redirect hint to /setup.
Skipped entirely when app.config['TESTING'] is True so unit tests remain
unaffected without needing to mark setup as complete.
"""
if app.config.get('TESTING'):
return None
path = request.path
if (path.startswith('/api/setup') or
path == '/health' or
not path.startswith('/api/')):
return None
if not setup_manager.is_setup_complete():
return jsonify({'error': 'Setup required', 'redirect': '/setup'}), 428
@app.before_request
def enforce_auth():
"""Enforce session-based authentication and role-based access control.
@@ -232,7 +254,7 @@ def check_csrf():
if request.method not in ('POST', 'PUT', 'DELETE', 'PATCH'):
return None
path = request.path
if not path.startswith('/api/') or path.startswith('/api/auth/'):
if not path.startswith('/api/') or path.startswith('/api/auth/') or path.startswith('/api/setup/'):
return None
# peer-sync uses IP+pubkey auth — no session, no CSRF token possible
if path.startswith('/api/cells/peer-sync/'):
@@ -409,6 +431,10 @@ service_bus.register_service('container', container_manager)
# Register auth blueprint
app.register_blueprint(auth_routes.auth_bp)
# Register setup blueprint (no auth required — runs before any account exists)
from routes.setup import setup_bp
app.register_blueprint(setup_bp)
# Register service blueprints (routes extracted from this file)
from routes.email import bp as _email_bp
from routes.calendar import bp as _calendar_bp