Ground-truth map of the release pipeline (verified from the actual files, not docs). Mapped in LayerView under flow release-deploy.
| Repo | Owner | Role |
|---|---|---|
vpn-astro | spp-ben | Site + content. What the editor and CI build from. |
vpn-editor | spp-ben | Editor worker (editor.vpn.com) — dispatches deploys |
vpn-workers | theofficialvpn | 5 edge workers serving www.vpn.com |
(Older docs said theofficialvpn/vpn-astro — wrong; corrected.)
| Builds from | Used by | |
|---|---|---|
CI (.github/workflows/deploy-i18n.yml) | GitHub main (fresh checkout) | editor buttons, translation jobs |
Local scripts (deploy.sh / promote.sh) | your local working tree | operator at a terminal |
Both run the same gates via scripts/build.sh (api-contract, internal-link, content-quality, seo-audit, key-leak, translation-qa, stale-translations, a11y). Never inline a subset — that's a gate-bypass.
⚠️ The rule (now ENFORCED, not just warned): staging may only be deployed from pushed git state. deploy.sh auto-pushes main (or hard-fails) before deploying to staging — there is no yes | bypass anymore. This guarantees origin/main always equals what's on staging, so the editor's Sync to Production (which rebuilds origin/main via CI) can never ship a stale main.
Why this is enforced — incident 2026-06-17. Staging was deployed repeatedly from a local working tree via
deploy.shwhile the commits were never pushed (origin/mainfell 8 behind). A Sync to Production from the editor then rebuilt the staleorigin/mainand shipped the old, superseded pricing design to www.vpn.com while staging showed the correct one. Root cause: staging was fed from a laptop, not git; the soft warning was bypassed. Fix:deploy.shnow pushes-or-fails (commit onmain).Residual (accepted): the guard is a script convention. A manual
npx wrangler pages deploy dist --project-name=vpn-staging(bypassingdeploy.sh) would skip it, andpromote.shstill only warns. Plan #89 (CF Pages branch deploys + ff-merge, infra-level parity) is PARKED — the singlemainbranch is sufficient for the sequential edit→staging→sync workflow, and the push guard closes the actual hole. Revisit only if concurrent in-flight changes ever need staging isolation.
staging.vpn.com is the source of truth. If it looks right, Sync. You never look at git.
Everything (editor content edits + operator code pushes) lands on main and is deployed to staging.vpn.com as part of the same action — so the staging site always equals what "Sync to Production" will ship. Sync rebuilds main → prod becomes an exact copy of staging. Keeping the staging site honest (a deploy on every main change) is the tooling's job, not the reviewer's.
editor /api/deploy ─┐
editor /api/deploy/i18n ├─ repository_dispatch → CI → build.sh → staging.vpn.com (vpn-staging)
translation DO finalize │
workflow_run (after Translate)┘
editor /api/deploy/sync-prod ── dispatch {target: production} → CI → www.vpn.com (vpn-astro)
operator: bash scripts/deploy.sh ── local build → staging.vpn.com
operator: bash scripts/promote.sh ── reuse verified dist → www.vpn.com
git push ───────────────────────────────────────────────→ triggers NOTHING (no push trigger)
client_payload.target=production (editor Sync to Production) or the manual promote.sh.| Task | Command / action |
|---|---|
| Deploy to staging (local) | bash scripts/deploy.sh (push first) |
| Deploy to staging (editor) | editor.vpn.com → Deploy |
| Promote staging → prod (local) | bash scripts/promote.sh (reuses staging-verified dist) |
| Promote → prod (editor) | editor.vpn.com → Sync to Production (rebuilds GitHub main via CI) |
| Roll back prod | bash scripts/rollback.sh |
| Emergency prod (bypass staging) | bash scripts/deploy.sh --emergency (rare) |
Canonical prod path: the editor's Sync to Production (always builds the reviewed, pushed GitHub source via CI). Because deploy.sh now pushes-or-fails, origin/main is always current → this path is safe. promote.sh is the operator fallback — it still only warns on out-of-sync (not auto-push), so prefer the editor for prod.
concepts/ deploys independently to concepts.vpn.com (CF Pages project vpn-concepts) via cd concepts && npm run deploy. Off the staging→prod pipeline entirely; not part of this flow.