Deployment and CI/CD¶
Every production change follows the same source-to-release path. The tested artifact is the artifact deployed; the remote host does not install Node dependencies or rebuild source.
Pipeline¶
flowchart LR
Commit[Commit or pull request] --> Quality[Format, lint, type-check, tests]
Commit --> Security[Secret and dependency audit]
Commit --> CodeQL[CodeQL analysis]
Quality --> Build[Production build and size budget]
Build --> Lighthouse[Mobile Lighthouse]
Security --> Gate{CI successful?}
Lighthouse --> Gate
Gate -->|main push| Package[Tested release artifact]
Package --> Deploy[Atomic VPS deployment]
Deploy --> Verify[Local and public health checks]
Verify --> WikiSync[Generate release notes and sync wiki]
WikiSync --> WikiCI[Strict MkDocs build and link check]
WikiCI --> Pages[GitHub Pages custom domain] Continuous integration stages¶
| Stage | Gate |
|---|---|
| Source safety | Reject live feeder UUIDs, absolute Mac user paths, private-key markers, and GitHub-token formats |
| Formatting | oxfmt --check |
| Static quality | oxlint and TypeScript tsc --noEmit |
| Reliability | Python backend unit and HTTP-boundary tests |
| Build | Reproducible pnpm install --frozen-lockfile and production Vinext build |
| Performance | Whole-site, JavaScript/CSS, and single-asset budgets |
| Browser quality | Public mobile Lighthouse performance, accessibility, best-practice, LCP, and CLS thresholds |
| Secrets | Gitleaks scans complete Git history |
| Dependencies | Production audit on every change and dependency review on pull requests |
| Static security | Scheduled and change-triggered CodeQL with extended JavaScript/TypeScript and Python queries |
Dependabot checks npm and GitHub Actions weekly. Every third-party action is pinned to an immutable commit SHA.
Production release¶
sequenceDiagram
participant GH as GitHub Actions
participant Host as Linux host
participant Sup as Relay supervisor
participant App as New relay
GH->>Host: Upload tested archive and deploy script
Host->>Host: Extract releases/COMMIT
Host->>Host: Validate required files
Host->>Host: Atomically update current symlink
Host->>Sup: Restart relay supervisor
Sup->>App: Start from current release
Host->>App: GET loopback /
alt healthy
Host-->>GH: Deployment succeeded
GH->>App: Verify public dashboard and health API
else unhealthy
Host->>Host: Restore previous symlink
Host->>Sup: Restart previous relay
Host-->>GH: Deployment failed
end Application state lives outside every release, so rollback does not replace the history database, accepted snapshots, relay token, or tunnel configuration. Five release directories are retained.
Required GitHub configuration¶
The main repository holds these Actions secrets:
| Secret | Purpose |
|---|---|
VPS_HOST | Deployment host name or address |
VPS_USER | Unprivileged deployment account |
VPS_HOST_KEY | Pinned SSH known-host entry |
VPS_DEPLOY_KEY | Dedicated private key accepted only by the server account |
WIKI_DEPLOY_KEY | Private half of a write-enabled deploy key scoped to the wiki repository |
The relay bearer token, Cloudflare tunnel token, and receiver UUID are not GitHub Actions secrets because a code release does not need them.
Wiki publication¶
wiki-site/ in the main repository is canonical. After a successful production deploy, the release workflow copies that directory into antenna_observatory_wiki, writes release notes from the deployed Git commit, and pushes with the wiki-only deploy key. The wiki repository then builds with strict warnings and deploys to GitHub Pages.