You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
coordinate production routing as a two-hop project-VM → control-plane transaction
snapshot the project route before deploy, prepare and locally health-check the desired project topology first, then update the control-plane route, and stamp state only after project commit
probe the complete control-plane TLS → configured upstream → project route locally before commit, without public DNS
require HTTP 200 and exact production version/tag/SHA/environment identity for every static deploy (releaseTag ?? sha)
keep the old project route live during host renames and roll back both hops on prepare, CP update, reachability, 502, or identity failure
restore static active-route metadata and prove the snapshotted old host/scheme before removing a failed candidate
run the two-hop transaction for every cp-http80 deploy, including unchanged Caddy configuration and same-SHA configuration drift
make new-SHA/tag CI or deploy failures leave both routing hops and deploy/release state unchanged
preserve staticRoot and its owning worktree across two-hop route transitions and cleanup
enforce injection-safe app names/IDs at manifest, registration, and generated-script boundaries
Why
Production links require both Caddy hops and the deployed release to agree. Configuration validation alone cannot prove that the control plane can reach the project VM or that the routed static release has the intended identity. Deploy/tag bookkeeping now advances only after the exact path that will serve the client has passed its local end-to-end probe.
Transaction order
CI/preflight succeeds.
Snapshot the project-VM route, static active-route metadata, and the base Caddyfile for static release apps.
Deploy and health-check the candidate release when the SHA changed.
Prepare and health-check the desired project-VM topology while retaining the prior route during address changes.
Atomically reconcile and validate the control-plane route.
Probe https://<mainHost>/... through CP 127.0.0.1:443 with --resolve, preserving production TLS SNI and Host; use the documented internal-TLS insecure policy. Static probes require exact version, tag, SHA, and production environment.
Commit the project route, clean the prior static release, then persist the route fingerprint/deployed SHA/release state.
Prepare, deploy, CP update, reachability, non-200, or identity failure restores the CP snippet and project snapshot and leaves state unstamped. Static deploy rollback probes the snapshotted old route and removes the failed worktree only after successful restoration. CI failure never begins a route transaction. A project commit failure remains unstamped and resumable without withdrawing the already-functional transition route.
Safety
never merges, tags, deploys, or edits production as part of this PR
the end-to-end probe is CP-local and bypasses public DNS and proxy environment variables
Caddy snippets are staged, validated, atomically renamed, and restored on failure
per-app hashed transaction/transition paths keep apps on a shared VM independent
unsafe app identity payloads fail closed before reaching Caddy, shell, systemd, or path generation
BLOCKED / DO NOT MERGE this mixed head (5d30b46). Independent exact-head review found release blockers despite green CI and the earlier automated gate: unsafe root-helper reads/writes of app-controlled state (including symlink/TOCTOU), missing safe adoption of existing TEMP control-plane routes, stale bootstrap-frozen helper config after manifest drift, missing central appUser validation, same-SHA ownership mismatch, and over-broad generic :80 legacy migration. We are splitting the work into narrow PRs: firewall wiring; Linux app-user validation; control-plane/admin routing; then shared-VM execution boundary. This PR remains draft as evidence/source material only until the safe routing slice replaces it. No live rollout should use this head.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
releaseTag ?? sha)cp-http80deploy, including unchanged Caddy configuration and same-SHA configuration driftstaticRootand its owning worktree across two-hop route transitions and cleanupWhy
Production links require both Caddy hops and the deployed release to agree. Configuration validation alone cannot prove that the control plane can reach the project VM or that the routed static release has the intended identity. Deploy/tag bookkeeping now advances only after the exact path that will serve the client has passed its local end-to-end probe.
Transaction order
https://<mainHost>/...through CP127.0.0.1:443with--resolve, preserving production TLS SNI and Host; use the documented internal-TLS insecure policy. Static probes require exact version, tag, SHA, and production environment.Prepare, deploy, CP update, reachability, non-200, or identity failure restores the CP snippet and project snapshot and leaves state unstamped. Static deploy rollback probes the snapshotted old route and removes the failed worktree only after successful restoration. CI failure never begins a route transaction. A project commit failure remains unstamped and resumable without withdrawing the already-functional transition route.
Safety
Validation
bunx tsc --noEmitbun test— 1,881 pass, 0 fail, 7,219 assertions across 85 files on headf4fac13e18171c4caf63b4ff3f1b9bbc371bcc91cp-http80→tlsstatic failure rollback, proving old-route re-probe and failed-candidate cleanup orderingbash -n; generated route passes the installed Caddy validator