Package protected review runtime and prepare deployment admission
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
parent
bb5b607bbd
commit
bda9381f07
20 changed files with 3534 additions and 7 deletions
184
deploy/README.md
Normal file
184
deploy/README.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
# Review service deployment candidate
|
||||
|
||||
`INFD-WP-0001-T08` owns this packet. It prepares the existing
|
||||
`decisions.coulomb.social` origin for the review service. **No image publication,
|
||||
production configuration, credential provisioning or cluster apply is performed
|
||||
by the build, renderer or tests.** The origin is still the Railiance Apps nginx
|
||||
placeholder. Native policy, custody, registration and service admission remain
|
||||
required before cutover.
|
||||
|
||||
## Artifact and local proof
|
||||
|
||||
```sh
|
||||
make image-build IMAGE=informed-decision:local
|
||||
python tools/smoke_container.py --image informed-decision:local --receipt /tmp/infd-container-proof.json
|
||||
```
|
||||
|
||||
`Containerfile` uses the digest-pinned Alpine base already used by Approval
|
||||
Engine, installs the hashed `requirements.lock`, then installs the built wheel
|
||||
without dependency resolution. The image contains no pip or build installer.
|
||||
Its user/group is 10001; runtime deployments must use a read-only root filesystem
|
||||
and drop capabilities. Rebuild the wheel before building the image. Refresh
|
||||
dependency pins deliberately with `uv pip compile pyproject.toml --python-version
|
||||
3.12 --generate-hashes --output-file requirements.lock`, then repeat checks and
|
||||
the image scan. A successful local build is not a published registry digest.
|
||||
|
||||
The dated evidence pins the exact wheel/image/runtime-file hashes and scanner.
|
||||
The local image passed 11 container checks and a HIGH/CRITICAL Trivy scan with
|
||||
zero findings. The scanner also emitted an Alpine lifecycle-list warning; the
|
||||
receipt retains it. This scan is evidence about the selected severities and
|
||||
database at that time, not a general security attestation.
|
||||
|
||||
The smoke harness creates and removes its own labeled containers/volumes. It
|
||||
uses `--network none`, publishes no port and mounts only synthetic configuration
|
||||
and credentials. It tests the installed entrypoint, private file ownership,
|
||||
anonymous refusal, unhealthy audit readiness, exclusion of a second writer,
|
||||
consistent backup, restart, and restore onto another volume. A synthetic
|
||||
unresolved submission and its undelivered evidence survive unchanged. No native
|
||||
issuer, PDP, Approval Engine or Audit Core is contacted. Actual component/browser
|
||||
contracts have separate receipts from the previous integration milestone.
|
||||
|
||||
The lifecycle check caught the initial PID-1 process requiring Docker's forced
|
||||
kill (exit 137). The container now handles SIGTERM through Waitress shutdown and
|
||||
the audit pump's stop path; the final image exits cleanly within the tested
|
||||
15-second window. Kubernetes allows 45 seconds. Forced termination still cannot
|
||||
justify retrying an unresolved approval entry.
|
||||
|
||||
## Private storage and projected configuration
|
||||
|
||||
The deployment uses a single replica with **Recreate**, a ReadWriteOnce PVC and
|
||||
an OS lock held for the life of the serving process. Do not add replicas, a
|
||||
rolling surge or another writer: sessions are process-local and this store is a
|
||||
local-filesystem design. The lock rejects accidental concurrent service starts;
|
||||
it is not an admission of network-filesystem locking semantics.
|
||||
|
||||
Kubernetes projected ConfigMaps are root-owned and symlinked. The container
|
||||
entrypoint reads at most 16 KiB from `/configuration/runtime.json`, requires
|
||||
`evidence_db=/data/private/review.sqlite`, and copies the configuration into
|
||||
owned ephemeral storage at `/run/informed-decision/private/runtime.json` (0600).
|
||||
It creates `/data/private` as the process user with mode 0700 and refuses unsafe
|
||||
existing ownership/modes. It does not silently chmod or take over existing data.
|
||||
The evidence database remains 0600. Credential callbacks read rotating projected
|
||||
files directly; bearer tokens are never copied into SQLite or the config snapshot.
|
||||
|
||||
The pod uses fsGroup 10001 with `OnRootMismatch`. Its storage driver must make
|
||||
the volume root writable by that group while preserving the private child's
|
||||
ownership/modes on later mounts. A restored volume whose root triggers a
|
||||
recursive permission rewrite needs owner repair before admission, not relaxed
|
||||
store checks. The local-path class exists on Railiance; its backup/retention and
|
||||
restore admission are still the platform owner's work.
|
||||
|
||||
The normal workstation entrypoint continues listening on 127.0.0.1. The container
|
||||
entrypoint explicitly selects 0.0.0.0; the public issuer/callback remain fixed,
|
||||
and Host/forwarded headers cannot alter them.
|
||||
|
||||
## Render the review packet
|
||||
|
||||
Copy `admission.example.json` outside Git and replace its intentionally invalid
|
||||
placeholders with the published image manifest digest, admitted PDP endpoint and
|
||||
package/version/digest, exact PDP pod label, observed/admitted issuer IPs and
|
||||
storage class. The renderer accepts no inline token or broad egress CIDR.
|
||||
|
||||
```sh
|
||||
python tools/render_deployment.py --input /operator/review-inputs.json --output /tmp/infd-candidate.json
|
||||
kubectl --kubeconfig /operator/railiance-kubeconfig apply --dry-run=server -f /tmp/infd-candidate.json
|
||||
```
|
||||
|
||||
Rendering and server dry-run do not admit the values supplied. The renderer
|
||||
produces eight review objects: service account, PVC, immutable configuration,
|
||||
Recreate Deployment, Service, the review pod's NetworkPolicy, and two exact
|
||||
counterparty ingress proposals. It creates no Secret, RBAC grant, Namespace,
|
||||
Ingress or policy assignment. The service retains the existing name/port and
|
||||
selects the review component. The Deployment keeps the existing immutable
|
||||
selector so the same origin can be replaced under a reviewed cutover.
|
||||
|
||||
The incoming Traefik peer is namespace AND pod label. Egress permits DNS,
|
||||
exact Approval/Audit/PDP peers, exact public KeyCape addresses on 443, and the
|
||||
observed Traefik websecure peer on 8443 for enforcement after Service DNAT.
|
||||
Railiance metadata on 2026-09-11 confirmed the Traefik label/8443 port and
|
||||
`kc.coulomb.social -> 92.205.62.239`. These observations do not prove the CNI
|
||||
path; test the actual issuer token/JWKS reachability after admission. The shared
|
||||
HTTPS router is an L3/L4 boundary, not a hostname authorization policy; the
|
||||
client itself pins the issuer and refuses redirects.
|
||||
|
||||
Approval Engine's existing caller policy permits Secrets Engine or namespaces
|
||||
carrying its client label. That does not admit this review pod. The packet adds
|
||||
an **owner-reviewed proposal** ANDing namespace, app label and component rather
|
||||
than labelling the whole namespace as an approved caller. Flex Auth receives a
|
||||
similarly exact peer proposal. Audit Core already owns its prepared Informed
|
||||
Decision ingress under `AUDIT-WP-0009-T11`; do not create a competing copy.
|
||||
|
||||
Seven of eight objects passed server dry-run in their actual namespaces. The
|
||||
Approval Engine peer failed because namespace `approval-engine` is absent.
|
||||
The identical policy shape passed with only its metadata namespace/name mapped
|
||||
to an existing namespace for schema validation. That does not close the missing
|
||||
owner deployment. Schema checks used fixture policy pins and an unpublished image
|
||||
reference; their rendered output is not an admitted production configuration.
|
||||
|
||||
## Serving health and acceptance readiness
|
||||
|
||||
Startup, Kubernetes readiness and liveness use `/healthz`. An audit dependency
|
||||
outage must not restart the writer or remove the service's refusal/recovery
|
||||
pages from the origin. `/readyz` separately reports recent audit delivery health,
|
||||
and the application refuses accept while it is unhealthy. Monitor `/readyz`
|
||||
and pending/blocked outbox counts explicitly; Kubernetes `Ready=True` alone is
|
||||
not deployment acceptance or native policy proof. A healthy process can still
|
||||
refuse every action when policy/custody has not been admitted.
|
||||
|
||||
## Native admission and cutover
|
||||
|
||||
Use the existing owners and records:
|
||||
|
||||
1. Flex Auth/Informed Decision admit the exact request package, assignments and
|
||||
caller `informed-decision=system:serviceaccount:informed-decision:review`.
|
||||
The projected token's audience is `flex-auth`; no browser token substitutes.
|
||||
The service account spelling is a candidate until this return is recorded.
|
||||
2. Platform/Audit Core complete `AUDIT-WP-0009-T11`: the candidate expects
|
||||
`informed-decision-audit` with key `token`, projected read-only. Its sender is
|
||||
exact `informed-decision`, tenant `tenant:platform`, write-only, load-bearing,
|
||||
redact. Run `warden route find/show` before any credential request. Rendering
|
||||
the Secret reference provisions nothing and confirms no custody name.
|
||||
3. Approval Engine admits its namespace/service and the exact review caller;
|
||||
KeyCape rolls out the already published browser registration. Railiance Apps
|
||||
admits image publication/cutover against its existing origin. Complete
|
||||
private-state backup/restore, monitoring and rollback ownership.
|
||||
4. Capture the current Deployment and Service configuration, close new review
|
||||
traffic for cutover, and retain any existing source-held evidence. Only then
|
||||
apply the admitted packet. Its Recreate rollout intentionally incurs downtime.
|
||||
5. Check both process health and application readiness, policy caller/subject
|
||||
allow/refusal cases, genuine human login and a declared human-control approval.
|
||||
Retrieve the independent audit receipt and the original presentation. Recheck
|
||||
the callback's TLS/redirect/cookie behavior and source custody after restart.
|
||||
|
||||
The image publication, workload/policy/custody admission and rollout remain
|
||||
distinct. No signed decision attribution, native approval or factory admission
|
||||
is inferred from this packet. `FLEX-WP-0024` and the commitment-only custody
|
||||
limitations remain as recorded in the consumer contract.
|
||||
|
||||
## Backup, restore and rollback
|
||||
|
||||
The installed `informed-decision-admin` supports local custody operations only:
|
||||
|
||||
```sh
|
||||
informed-decision-admin inspect --db /data/private/review.sqlite
|
||||
informed-decision-admin backup --db /data/private/review.sqlite --output /backup/private/review.sqlite
|
||||
```
|
||||
|
||||
The backup parent must already be owned/private 0700; the destination must not
|
||||
exist. Backup uses SQLite's consistent backup API while the service may be live.
|
||||
Do not copy a running SQLite file while ignoring WAL. Inspection prints counts
|
||||
and schema version, not memo content or credentials. These are privileged
|
||||
operator custody commands, not browser endpoints. An independent backup copy,
|
||||
retention, access controls and an actual platform restoration drill remain owed.
|
||||
|
||||
For restore, stop the serving writer, restore to a separately prepared private
|
||||
volume, verify the immutable content and unresolved submission state, then
|
||||
mount that volume as `/data`. A restart requires a new human login. Never reset
|
||||
an unresolved intent or POST again to manufacture a presentation correlation.
|
||||
Do not roll schema v2 back to an older reader against the same live database.
|
||||
|
||||
For a failed initial cutover, stop the new writer, retain the PVC and restore
|
||||
Railiance Apps' **Deployment and Service** from the prior origin manifest.
|
||||
Restoring only the Deployment is insufficient: the candidate Service selector
|
||||
also names the review component. Returning to the placeholder is a service
|
||||
rollback, not deletion or reconciliation of any approval/evidence already held.
|
||||
12
deploy/admission.example.json
Normal file
12
deploy/admission.example.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"image": "REQUIRED: forgejo.coulomb.social/coulomb/informed-decision@sha256:<published manifest digest>",
|
||||
"policy": {
|
||||
"origin": "REQUIRED: http://<admitted service>.flex-auth.svc.cluster.local:8080",
|
||||
"package": "REQUIRED: owner-admitted package",
|
||||
"version": "REQUIRED: owner-admitted version",
|
||||
"package_digest": "REQUIRED: sha256:<native package digest>",
|
||||
"pod_name": "REQUIRED: exact app.kubernetes.io/name label of admitted PDP"
|
||||
},
|
||||
"keycape_egress_ips": ["REQUIRED: observed and admitted public issuer IPv4/IPv6 address"],
|
||||
"storage_class": "REQUIRED: admitted local-filesystem ReadWriteOnce storage class"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue