Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc |
||
|---|---|---|
| .. | ||
| admission.example.json | ||
| README.md | ||
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
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, clearing the
inherited setgid bit only on directories it just created on fsGroup volumes,
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.
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:
- Flex Auth/Informed Decision admit the exact request package, assignments and
caller
informed-decision=system:serviceaccount:informed-decision:review. The projected token's audience isflex-auth; no browser token substitutes. The service account spelling is a candidate until this return is recorded. - Platform/Audit Core complete
AUDIT-WP-0009-T11: the candidate expectsinformed-decision-auditwith keytoken, projected read-only. Its sender is exactinformed-decision, tenanttenant:platform, write-only, load-bearing, redact. Runwarden route find/showbefore any credential request. Rendering the Secret reference provisions nothing and confirms no custody name. - 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.
- 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.
- 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:
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.