approval-engine/deploy/README.md

40 lines
2 KiB
Markdown
Raw Normal View History

# Deployment gates
The checked-in StatefulSet is a reviewed release input, not evidence of a live
Reconcile the release record; guard the image pin with tests The publication at b51d174 pinned the manifest and appended a note, but left three documents asserting the opposite. docs/image-scan-2026-09-06.md said "It has not been pushed" in its Outcome block at the top while recording the successful push at the bottom; its "Release status" section still said no release digest existed and the manifest carried REPLACE_WITH_RELEASE_DIGEST; and deploy/README.md still instructed an operator to replace a placeholder that is now a real digest -- an instruction to undo the pin. This is the derived-artifact staleness this repo argued for a rule about in v0.8 §12 and then produced in its own release evidence, in the file another repository would read to confirm what shipped. Superseded sections are now marked in place with what replaced them rather than deleted, since they record why the base changed and why the release was held. The scan doc carries a status marker naming which parts state current state, including that a clean scan is point-in-time and ages as advisories are published. The workplan gains the publication entry it never got, and a re-check of T03's full acceptance: a published image reads like a finished task, but the digest was one of five requirements. Nothing is deployed -- the namespace is empty and no secrets exist -- and production serve refuses to start without authenticated audit delivery, so a rollout today would fail closed and prove nothing. T03 stays wait on T01's registrations and the audit credential. Also corrects an earlier caution in the workplan that the digest was "a local image id, not a release digest". That was wrong: with the containerd/OCI store the build id is the manifest digest, and the registry resolves it. tests/test_deploy_manifest.py holds the pin mechanically instead of by review: both image references exist, are digest-pinned rather than tagged, are identical, and no placeholder remains. The identity check matters because the init container migrates the database the server then serves -- two different digests there is a split-brain migration. Verified the guard fails on the drift it targets, not only that it passes today. 116 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PM5HnEAhokxdfcPqBNpT7D Assistant: claude-code Assistant-Model: opus Assistant-Process: 715850@bnt-lap001 Assistant-Session: eb557e93-7cb1-45d0-9e57-7d15b3edc60e
2026-09-07 09:04:34 +02:00
deployment. SQLite is intentionally limited to one replica, `ReadWriteOnce`
storage, and an `OnDelete` update: never start two writers against a copied
database.
**Image: pinned, published, not rolled out.** Both `image:` references already
carry the immutable release digest
`sha256:73333f5ceb55e48192e3095cb2e2a741cdc6ff0be2f18128301072b4a6b6eb9d`
(registry tag `0.1.0`, OCI index; linux/amd64 manifest `sha256:2064d537…`),
pinned at `b51d174`. There is no placeholder left to replace. Both references
MUST stay identical and MUST stay digests — a tag here would let the init
container and the server run different code against one database.
Gates 1 and 2 below are the outstanding ones; nothing is deployed today.
Before applying:
1. Register the exact `approval-engine` audience, caller scopes, and service
clients in KeyCape. Confirm the in-cluster JWKS endpoint and configured
issuer match the manifest.
2. Register `approval-engine` as an audit-core sender, add matching audit-core
ingress, and provision `approval-engine-audit` through the credential owner.
The Secret must contain key `audit-token`; never commit its value.
Reconcile the release record; guard the image pin with tests The publication at b51d174 pinned the manifest and appended a note, but left three documents asserting the opposite. docs/image-scan-2026-09-06.md said "It has not been pushed" in its Outcome block at the top while recording the successful push at the bottom; its "Release status" section still said no release digest existed and the manifest carried REPLACE_WITH_RELEASE_DIGEST; and deploy/README.md still instructed an operator to replace a placeholder that is now a real digest -- an instruction to undo the pin. This is the derived-artifact staleness this repo argued for a rule about in v0.8 §12 and then produced in its own release evidence, in the file another repository would read to confirm what shipped. Superseded sections are now marked in place with what replaced them rather than deleted, since they record why the base changed and why the release was held. The scan doc carries a status marker naming which parts state current state, including that a clean scan is point-in-time and ages as advisories are published. The workplan gains the publication entry it never got, and a re-check of T03's full acceptance: a published image reads like a finished task, but the digest was one of five requirements. Nothing is deployed -- the namespace is empty and no secrets exist -- and production serve refuses to start without authenticated audit delivery, so a rollout today would fail closed and prove nothing. T03 stays wait on T01's registrations and the audit credential. Also corrects an earlier caution in the workplan that the digest was "a local image id, not a release digest". That was wrong: with the containerd/OCI store the build id is the manifest digest, and the registry resolves it. tests/test_deploy_manifest.py holds the pin mechanically instead of by review: both image references exist, are digest-pinned rather than tagged, are identical, and no placeholder remains. The identity check matters because the init container migrates the database the server then serves -- two different digests there is a split-brain migration. Verified the guard fails on the drift it targets, not only that it passes today. 116 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PM5HnEAhokxdfcPqBNpT7D Assistant: claude-code Assistant-Model: opus Assistant-Process: 715850@bnt-lap001 Assistant-Session: eb557e93-7cb1-45d0-9e57-7d15b3edc60e
2026-09-07 09:04:34 +02:00
3. For a new release only: `make image-release` (build, scan, push — the scan
gate fails the build on any CRITICAL or HIGH, so a failing scan blocks the
push), then pin both `image:` references to the returned registry digest and
run `make deploy-dry-run`. The current digest is already pinned; skip to 4
unless you are cutting a new image.
4. Take a verified backup. Roll out by deleting the sole pod, then prove
readiness, restart persistence, outbox drain, heartbeat, and restore.
5. Enable a caller namespace only by applying label
`railiance.io/approval-engine-client=true`; JWT scope checks remain the inner
boundary.
The audit-core receiver-side registration, cadence findings, and accepted-count
reconciliation are tracked by `AUDIT-WP-0009-T04/T06/T09` and cannot be closed
from this repository.