94de4acef50f4bbc997ad44495414c56337ab16d
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5a0429d46b |
fix(ci): add SBOM+sign release chain and gate Coolify redeploy on it
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / security (push) Successful in 13s
CI (SIAX Cloud) / quality (push) Successful in 32s
Security Scan (SIAX Cloud) / security (push) Successful in 52s
CI (SIAX Cloud) / integration (push) Successful in 1m35s
0pt had no SBOM/sign/digest chain at all (re-confirmed live before this change: no cosign/syft/sbom hit anywhere under .gitea/workflows/, only doc mentions in CHANGELOG.md/docs/architecture/ARCHITECTURE.md). Applies the same two-part pattern already proven on sax3l/cl0ud and sax3l/st0re (fix/wire-signed-digest-to-deploy, 2026-09-14): 1. .gitea/workflows/release.yml (new): builds the image, pushes it to git.cloud.siax.io/sax3l/0pt:sha-<12>, SBOMs it (syft), signs it (cosign, key-based), verifies the signature in the same run, and commits source-bundle/production-evidence records back to the repo. 2. .gitea/workflows/cd.yml: the `deploy` job now polls the registry for this exact commit's release-chain image and cosign-verifies it (against the committed cosign.pub) before calling Coolify's deploy endpoint -- fails closed (10 min timeout) if release.yml never produced a verifiable artifact for this sha. Added AFTER the existing guard step, which still fails closed first on 0pt's real, pre-existing blocker: no Coolify Application is provisioned for 0pt yet (COOLIFY_APP_ID is a literal placeholder). This gate is wired ahead of that so it's already in place the day the app is provisioned, instead of a second follow-up change. Honest limitation carried over from cl0ud/st0re/h0st: once provisioned, 0pt's Coolify Application is expected to use the `dockerfile` build pack (per siax.config.json), so Coolify would still perform its own independent docker build rather than pulling the signed image, and /api/v1/deploy has no digest parameter to pin against -- true digest-pinning needs a production Coolify resource-type decision, out of CI-YAML scope. This gate proves a signed, verified build of the exact commit exists before authorizing any deploy call; it does not prove byte-identical output from Coolify's own rebuild. cosign.pub is a fresh, 0pt-specific keypair generated offline for this change. NOT YET SET on sax3l/0pt (release.yml/cd.yml's gate will fail closed until present): REGISTRY_USER, REGISTRY_TOKEN, COSIGN_PRIVATE_KEY, COSIGN_PASSWORD, SIAX_CI_TOKEN repo secrets. Validated without live Coolify/registry access: YAML-parsed all 2 files, bash -n syntax-checked all 19 embedded run: blocks, and dry-ran the actual verification logic -- the RepoDigests filter and bounded poll-retry loop against mocked scenarios, plus a real cosign sign+verify round-trip (offline signing-config, local throwaway registry container) proving the gate's cosign verify command genuinely passes on the correct key/digest and fails closed on a wrong key and on an unsigned image. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
d7a1c4d5e1 |
docs: the Coolify deploy hook is LIVE — six docs still say it is a placeholder
CI (SIAX Cloud) / security (push) Successful in 31s
CI (SIAX Cloud) / integration (push) Successful in 42s
Security Scan (SIAX Cloud) / security (push) Successful in 44s
CI (SIAX Cloud) / quality (push) Successful in 1m6s
CI (SIAX Cloud) / security (pull_request) Successful in 30s
CI (SIAX Cloud) / integration (pull_request) Successful in 37s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 26s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m2s
Six documents on main assert that no Coolify app has been provisioned for 0pt and
that cd.yml's COOLIFY_APP_ID is a literal placeholder whose guard fails the job on
purpose. That is no longer true, and the gap is not cosmetic: it means a merge to
main silently ships to production while the repo's own docs promise it cannot.
Measured, not assumed:
* repo Actions secret COOLIFY_TOKEN exists, created 2026-08-31T11:34:34Z
(GET /api/v1/repos/sax3l/0pt/actions/secrets)
* repo Actions variable COOLIFY_APP_ID exists with a real 24-character value,
not the "TODO-no-coolify-app-provisioned-yet" literal
(GET /api/v1/repos/sax3l/0pt/actions/variables)
* both guards in .gitea/workflows/cd.yml therefore pass; on the push to main at
|
||
|
|
dc6aaa0e10 |
fix(data-os): P014 — close tenant-isolation + idempotency gaps, execute real restore drill
CI (SIAX Cloud) / quality (push) Successful in 51s
Security Scan (SIAX Cloud) / security (push) Successful in 26s
CI (SIAX Cloud) / security (push) Successful in 28s
CI (SIAX Cloud) / integration (push) Successful in 1m1s
CI (SIAX Cloud) / integration (pull_request) Successful in 30s
CI (SIAX Cloud) / security (pull_request) Successful in 24s
CI (SIAX Cloud) / quality (pull_request) Successful in 48s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 22s
Tenant isolation (security-critical): every app/api/0pt/** route reading
tenant_id from client-controlled query/body never cross-checked it against
the token middleware.ts already verified (x-0pt-verified-tenant). Adds a
shared assertTenantMatchesVerified guard and wires it into all 20+ affected
routes. Also closes two full-leak-by-omission bugs found in this pass
(documents/capture and lakehouse/mappings GETs returned every tenant's rows
when tenant_id was simply omitted) and two "no tenant check at all" reads
(rate-policies/[id], lakehouse/mappings/[id]) reachable by ID alone.
Duplicate-delivery idempotency (correctness-critical): POST /api/orders now
honors Idempotency-Key (sql/006, replay-or-409-on-conflict, Postgres +
in-memory); the Python orchestrator's POST /orders/{id}/run — the actual
delivery trigger — is now idempotent under an asyncio lock, closing a real
concurrent-request race, not just the sequential-retry case.
Engine-duplication resolution: adaptive_router.py's docstring wrongly
invited a bypass ("see b0ts for scraping") contradicting the product's own
compliance stance; corrected, and given real (additive, not escalating)
block-signal tracking so a rate-limited/blocked source is excluded from the
plan instead of hammered. Also fixes a previously-undiscovered production
bug: the Python engine's only call into the TS quality bridge
(X-Internal-Token) was unconditionally 401'd by middleware.ts, which never
checked that credential — the advisory quality bridge was unreachable in any
environment enforcing auth.
Restore drill: executed for real against throwaway Docker Postgres
containers (not simulated). Found and fixed two real blockers along the way:
sql/004 referenced opt_datasets, which no migration ever created (chain was
never actually runnable end to end); lib/db.ts hardcoded ssl:"require",
making any non-TLS Postgres (incl. compose.dev.yaml's own local-dev
container) unreachable. After both fixes: full migration chain applies
cleanly, pg_dump/pg_restore round-trip is byte-identical (row counts +
content checksums), and real application code (lib/orders-store.ts,
SourceRegistryService's Postgres repository) reads the restored data back
correctly, including cross-tenant isolation still holding.
82 new tests (55 TS + 27 Python), all passing; full existing suite (291 TS +
55 Python) still green; typecheck clean on every changed/added file.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
8db56f1b4c | docs: FAS 9 - README/SECURITY updates, CONTRIBUTING, AGENTS, runbooks (deploy/incident/backup-restore/oncall), SLO, prompts |