Phase 4: service store — manifest validation, install/remove, Store UI

- ServiceStoreManager: manifest allowlist (git.pic.ngo/roof/*), volume
  denylist, ACCEPT-only iptables rules, ${SERVICE_IP}-only dest_ip
- IP allocator: pool 172.20.0.20-254, skips CONTAINER_OFFSETS VIPs
- Compose overlay: docker-compose.services.yml auto-included via DCF
- Flask blueprint at /api/store: list, install, remove, refresh
- Store.jsx: full install/remove UI with spinners and toast notifications
- 95 new unit tests for ServiceStoreManager (all passing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-09 10:19:39 -04:00
parent f77d7fabcd
commit 0a21f22076
14 changed files with 2190 additions and 12 deletions
+9 -1
View File
@@ -42,7 +42,7 @@ from managers import (
routing_manager, vault_manager, container_manager,
cell_link_manager, auth_manager, setup_manager,
caddy_manager,
ddns_manager,
ddns_manager, service_store_manager,
firewall_manager, EventType,
)
# Re-exports: tests do `from app import CellManager` and `from app import _resolve_peer_dns`
@@ -374,6 +374,11 @@ def _apply_startup_enforcement():
sync_summary = cell_link_manager.replay_pending_pushes()
if sync_summary.get('attempted'):
logger.info(f"Startup permission sync: {sync_summary}")
# Service store: re-apply firewall/caddy rules for installed services
try:
service_store_manager.reapply_on_startup()
except Exception as _sse:
logger.warning(f"service_store reapply_on_startup failed (non-fatal): {_sse}")
except Exception as e:
logger.warning(f"Startup enforcement failed (non-fatal): {e}")
@@ -465,6 +470,9 @@ app.register_blueprint(_services_bp)
app.register_blueprint(_peer_dashboard_bp)
app.register_blueprint(_config_bp)
from routes.service_store import store_bp
app.register_blueprint(store_bp)
# Re-export config helpers so existing test imports/patches keep working
from routes.config import (
_set_pending_restart, _clear_pending_restart,