Both committed inventories went stale behind the walkthrough work, so the
two ratchets that pin them failed on dev:
test_api_surface_inventory::test_committed_surface_matches_served_surface
test_migration_inventory::test_the_committed_inventory_matches_the_measured_state
API_SURFACE picks up GET and PUT /walkthroughs/definitions, the endpoints the
Walkthrough Studio contribution contract added. MIGRATION_INVENTORY moves the
hand-shaped {'error': ...} census 1141 -> 1142 against an unchanged ceiling of
1150; the routes above are the new sites and the ceiling still holds.
Regenerated, not hand-edited:
SERVERKIT_UPDATE_API_SURFACE=1 pytest tests/test_api_surface_inventory.py
python scripts/generate-migration-inventory.py
Version Bump failed only as a dependent of Backend CI ("Sibling CI failed;
VERSION will not advance") and needs no change of its own.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The About tab could only detect a new release and link to it; applying the
update meant SSH and scripts/update.sh. Wire that script to the UI:
- panel_update_service launches update.sh via systemd-run in its own
transient unit — a plain subprocess child would be killed when the
updater restarts the panel's own systemd unit. Status is stateless
(transient-unit state + the updater's own update-*.log) so it survives
the mid-update backend restart.
- Capability gates keep the button honest: root systemd installs only.
Docker installs get the docker compose pull instructions; dev servers
and hosts without systemd-run get a reason instead of a button.
- GET/POST /api/v1/system/update (admin_required, confirm-gated,
audited). API surface doc regenerated.
- About tab gains Update Now with inline confirm, live log tail while
the update runs, a restarting phase that tolerates the panel being
briefly unreachable, and success/rollback/timeout outcomes. New
aboutTab locale keys in en + es.
The heavy lifting (blue/green switch, migrations, health check,
automatic rollback) stays in update.sh, which is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
API surface regenerated (the flagship-seeded cloudflare zone routes no
longer boot with a lean panel); the frontend route contract gains an
explicit EXTRACTED_EXTENSION_PREFIXES excuse list for the /git, /email and
/cloudflare prefixes core clients probe fail-soft.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Controller-boundary baseline drops the three api/security.py crossings that
moved to serverkit-image-scan; API surface sheds the 18 Gitea operations;
migration inventory regenerated by preflight; test-count floor raised
4735 -> 4799 (SERVERKIT_CLEAN_COLLECT).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 1791-line security omnibus splits along tool lines and the install-gated
surfaces leave core for five standalone extensions - serverkit-clamav
(ClamAV+YARA scanning, quarantine, scan jobs), serverkit-fail2ban
(management UI; probes stay core on Fail2banJailService), serverkit-lynis,
serverkit-auto-updates, and serverkit-image-scan (headless CVE/SBOM
scanning; models stay core per the plan 52 D1 data seam). Each mounts its
routes back at the same /api/v1/security prefix when installed, so route
shapes never change; absent extensions mean plain 404s, no dead UI.
Core keeps the zero-host-package baseline: status/config, legacy integrity,
suspicious activity/events, SSH keys, IP lists, the audit (fail2ban check
now probes via the jail service; updates check was already self-contained),
scoped FIM, and the scan/alert logs + notification helpers extensions write
through. Job handlers for security.malware_scan/lynis_scan/image_scan now
come exclusively from the extensions' manifest jobs key.
Security page becomes core-tabs-only; extension tabs contribute into the
security tab group (3a groupId). Overview posture drops the hardcoded
ClamAV rows and offers the Marketplace when no security extension is
installed. Upgrade parity: run_registry_auto_install() installs each
extension from the registry once, gated on the host tool actually being
present, fail-soft until the registry entry is published.
Wizard round 2 (Ph5): a security-posture chooser (minimal/recommended/
hardened) on the Summary step, catalog-resolved so unpublished slugs never
render dead installs; persisted as onboarding_security_posture.
Moved test suites re-home to the extension repos; panel keeps
test_security_suite_extraction.py (18 proving tests: absent-shape 404s,
lean summary, jail-service probes, migration gates, posture wiring).
docs/API_SURFACE.md regenerated (34 operations moved out).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The seven /connections/providers operations shipped in 939c77b6 without
the surface pin being regenerated; the diff is exactly those routes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
OpenAPIService.generate_spec() existed but nothing snapshotted it, so a
route rename/removal/method change shipped invisibly to API-key
consumers, the CLI, and agents. docs/API_SURFACE.md now pins the sorted
METHOD /path inventory (1418 operations) with the same
regenerate-and-review contract as docs/MIGRATION_INVENTORY.md: an
intentional surface change regenerates the doc in the same commit
(SERVERKIT_UPDATE_API_SURFACE=1 pytest
tests/test_api_surface_inventory.py) so the diff is the review.
Method+path only on purpose — summaries and schemas churn without
breaking anyone. Named *_inventory so preflight's globs run it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>