CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (push) Successful in 5s
masterplan-lock / check (pull_request) Successful in 4s
CI (SIAX Cloud) / security (pull_request) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / integration (pull_request) Successful in 9m49s
CI (SIAX Cloud) / quality (pull_request) Successful in 10m1s
The runbook still described Vercel and an unprovisioned Coolify app. It now documents the verified chain (ci -> release attestation -> cd -> Coolify), the proven manual dispatch, the verification endpoints and the rollback.
85 lines
3.3 KiB
Markdown
85 lines
3.3 KiB
Markdown
# Runbook: Deploy — 0pt
|
|
|
|
> Status 2026-11-02: **live on the SIAX fleet (Coolify)** at `https://0pt.app`.
|
|
> The automatic chain and the manual path are both verified: a signed image is
|
|
> attested, Coolify is called, the container restarts on the new commit, and
|
|
> `/api/version` reports it.
|
|
|
|
## Pipeline (automatic)
|
|
|
|
```
|
|
git push main
|
|
├─ ci.yml quality (typecheck, contrast, tests, build)
|
|
│ integration (live OpenSearch + ClickHouse)
|
|
│ security (Trivy, blocking)
|
|
├─ security.yml push/PR/weekly scan
|
|
├─ release.yml build + SBOM + blocking vuln scan + cosign attest + push
|
|
│ → git.cloud.siax.io/sax3l/0pt:sha-<12>
|
|
└─ cd.yml waits for THIS commit's attestation, verifies it against
|
|
cosign.pub, then POSTs to Coolify
|
|
prod-smoke.yml every 30 min: ready + db/stripe + running commit == main
|
|
```
|
|
|
|
- One run per ref (`concurrency`); `push` is main-only, PRs are covered by the
|
|
`pull_request` event. Deploys have their own non-cancelling group so two
|
|
runs never race the same app.
|
|
- Dependency caches: pnpm store (Node jobs), npm (doc0/n0d), pip (0pt-motor).
|
|
|
|
## Manual deploy (proven)
|
|
|
|
Trigger the same, signed path — do not POST to Coolify directly unless the
|
|
pipeline itself is broken:
|
|
|
|
```bash
|
|
curl -X POST -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \
|
|
-d '{"ref":"main"}' \
|
|
https://git.siax.io/api/v1/repos/admin/0pt/actions/workflows/cd.yml/dispatches
|
|
```
|
|
|
|
Emergency only (bypasses the attestation gate; still builds the branch head):
|
|
|
|
```bash
|
|
curl -X POST -H "Authorization: Bearer $COOLIFY_API_TOKEN" -H "Content-Type: application/json" \
|
|
-d '{"uuid":"<COOLIFY_APP_ID>"}' https://cloud.siax.io/api/v1/deploy
|
|
```
|
|
|
|
## Verify a deploy
|
|
|
|
```bash
|
|
curl -s https://0pt.app/api/ready # {"ready":true,"db":"ok","stripe":"ok",...}
|
|
curl -s https://0pt.app/api/health # liveness envelope
|
|
curl -s https://0pt.app/api/version # {"commit":"<sha>"}
|
|
```
|
|
|
|
`commit` must equal the current `main` SHA. `prod-smoke.yml` enforces exactly
|
|
that every 30 minutes; a green deploy is never confused with a current service.
|
|
|
|
## Rollback
|
|
|
|
Coolify builds from the branch head, so a rollback is a normal revert:
|
|
|
|
```bash
|
|
git revert --no-edit <bad-sha> && git push origin main
|
|
```
|
|
|
|
That runs the same chain and deploys the reverted tree. Coolify's own
|
|
"redeploy previous deployment" is the break-glass alternative.
|
|
|
|
## Configuration (names only — values live in Coolify/Infisical)
|
|
|
|
- Coolify app: `dockerfile` build pack, repo `git.siax.io/sax3l/0pt`, branch
|
|
`main`, health check `/api/health`, domains `0pt.app` + `api.0pt.app`.
|
|
- Repository variable: `COOLIFY_APP_ID`.
|
|
- Repository secrets: `COOLIFY_TOKEN`, `REGISTRY_USER`, `REGISTRY_TOKEN`,
|
|
`COSIGN_PRIVATE_KEY`, `COSIGN_PASSWORD`, `SIAX_CI_TOKEN`.
|
|
- App env: `DATABASE_URL`, `STRIPE_SECRET_KEY`, `AUTH_SECRET`… see `.env.example`
|
|
for the full, documented list (DOC0, INF0/decision Ollama, OpenFGA/project
|
|
grants, model policy, credit price book, OIDC).
|
|
|
|
## Known limitation
|
|
|
|
Coolify rebuilds from source; `/api/v1/deploy` has no digest parameter, so the
|
|
verified digest is recorded as provenance for the deploy rather than pinned as
|
|
the running bytes. True digest pinning would require a Coolify `dockerimage`
|
|
resource — an infrastructure decision, not a CI-YAML change.
|