Prepare immutable caller rollout and independent Scaleway recovery custody
Some checks failed
Transactional mail acceptance / mail (push) Failing after 32s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a11fd9-caf6-7a63-b578-9daaaa134ff2
This commit is contained in:
tegwick 2026-10-09 19:49:24 +02:00
parent 3e18f11afe
commit 9a2cf213d1
19 changed files with 1543 additions and 4 deletions

View file

@ -86,3 +86,49 @@ must be repinned together only when a new receiver image is actually deployed.
Policy narrowing/removal preserves ledger evidence but can deny existing links;
review rollback with the compatible image and both caller credentials before
releasing traffic. Source preparation does not issue a token or select this policy.
## Published closure candidates — 2026-10-09
The immutable receiver candidate is
forgejo.coulomb.social/coulomb/email-connect@sha256:5d79fd1fec15d3a279383820f170d263de3a55f5308df01a0a34732ebaea6d3d.
The coordinated user-engine candidate is
forgejo.coulomb.social/coulomb/user-engine@sha256:312dcb062b237c518148e1b4f09798a4e6ad08bc60d4add6834aab3f246f2002.
It applies only the retained binding patch to the verified live source baseline
0d0751d, avoiding unrelated owner-repository changes. Baseline regression passes
302 tests with 20 baseline optional skips; the six packaged binding tests pass
under UID10001/network-none. A read-only live query found no historical family
invitation outbox rows. This does not replace scope checks at release time.
Six delivery objects and both immutable-image deployment patches in deploy/closure
pass actual cluster server dry-run. Caller custody is a separate OpenBao leaf,
platform/workloads/email-connect/callers/user-engine, field TOKEN, initial CAS0.
The two dedicated namespace/ServiceAccount readers have exact leaf-only policies;
no legacy ingest token is copied. scripts/admit-scoped-caller.py previews by
default and silently installs exact policies/roles, creates or verifies the leaf
with a five-minute bounded writer, and self-revokes that writer before its receipt.
It refuses changed artifacts, differing existing roles/policies and unreviewed
plan decisions. It does not apply workloads or create Kubernetes Secrets.
The reviewed plan hash is 8e529e2ffdb6ee3d53a768d65b2d025b95e788734c48a29f2f8b975825dbaed7. For an attended execution, bind a resolved
User decision to this exact plan and use a fresh receipt under a mode-0700 parent:
```text
BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200 \
warden access openbao-platform-admin-login --exec -- \
python3 /home/worsch/email-connect/scripts/admit-scoped-caller.py --execute \
--reviewed-sha256 8e529e2ffdb6ee3d53a768d65b2d025b95e788734c48a29f2f8b975825dbaed7 \
--decision-id RESOLVED_USER_DECISION_UUID --receipt PRIVATE_RECEIPT_PATH
```
The environment orientation §5 requires the founder to run this in their own
terminal because OIDC/MFA needs a browser and TTY:
/home/worsch/the-custodian/docs/agent-environment-orientation.md.
The child captures all secret output. Operator login and session revocation must
be verified separately; Warden's exit code alone is insufficient.
After custody/reader proof, project both bounded secrets, freeze user-engine
dispatch, capture the ledger, deploy the coordinated scoped pair, and prove health,
denials/quotas and legacy handle continuity without sending mail. Repin backup
capture/rehearsal together only after actual receiver activation and refresh the
recovery kit. No new credential, image rollout or policy activation has occurred.
T03 remains progress. Full email regression: 193 passed, zero skips.

View file

@ -185,3 +185,54 @@ using the loopback GreenMail harness; focused syntax checks pass. Retention,
capacity, independent receipt/key/image custody, separate recovery caller and
recurring schedule/RPO admission retain EMAIL-WP-0007-T03/T04. Production restore
still requires fencing and post-capture reconciliation before traffic release.
## Closure package and Scaleway custody — 2026-10-09
User selected Scaleway, then named `email-connect-backup-primary`. Retain that
existing IAM application (0eb0f958-77a4-4c70-9aa7-14ba46411415) for routine archive
publication; CCR-2026-0037 admits only the email-connect archive prefix and excludes
escrow and administration. This selection is not evidence of additional grants.
Actual native metadata shows versioning Enabled and a bucket-wide 30-day expiry
for current and noncurrent objects. No provider configuration was changed.
The public closure contract is deploy/closure/plan.json; preparation evidence is
deploy/closure/evidence-2026-10-09.json. Proposed schedule is daily 04:15 UTC with
five-minute jitter, 24-hour RPO target and 26-hour freshness threshold. Proposed
local capacity floor/budget are both 8 GiB, with 14 daily/4 weekly generations and
weekly owner-operated expiry by platform-root. The new staged capacity guard
refuses before capture at low free space or when local retained files approach
that budget; it never deletes retained objects. These targets are prepared, not
measured production RTO or enabled operation. Node-installed helpers are unchanged.
A private 47,541,825-byte recovery kit binds the existing protected first backup,
receiver image, recovery tools and public receipts. It excludes the private age
identity. SHA256: 97d1a4d4b55729dd226277601637d64b086de21b21c9951c1d7da05c914c350b.
Rehearsal using its hash-bound bundled image passes without pulling an image,
under UID10001/network-none, preserving all six tables; elapsed 2.31 seconds is
application rehearsal only. The kit remains local and has not been uploaded.
Prepared Scaleway custody uses a protected opaque Secret Manager container
`email-connect-ledger-age-recovery` in nl-ams with no ephemeral policy, and private
versioned bucket `railiance-email-connect-recovery`, prefix `kits/`, with no expiry.
This preserves the protected recovery point beyond the primary archive lifecycle.
Provider containers, project/secret references, separate recovery application and
effective grants still need owner admission. Existing publisher access cannot
create these resources. A different durable arrangement is acceptable after its
actual effective permissions and retention are reconciled with the contract.
scripts/scaleway-recovery-custody.py defaults to preview. Attended execution takes
--secret-id, --project-id, --identity and a fresh --receipt; SCW_SECRET_KEY stays
in the operator environment. It checks exact protected metadata, writes/reuses
only revision 1 and silently verifies the matching age recipient by readback.
scripts/publish-ledger-recovery-kit.py defaults to preview; execution accepts
private owner/reader credential files, --kit, --kit-receipt, --output and --receipt.
It refuses disabled versioning or lifecycle rules, publishes conditionally and
checks size/hash through a separate reader's version-pinned GET. Different key
IDs do not prove different application bindings or denied writes. Receipts keep
those fields false pending native proof, independent account entry and a drill
from the provider-retrieved kit and escrow identity. No secret values belong in
chat, argv, evidence, Git or the operations inbox.
Full email regression: 193 passed, zero skips; focused syntax checks pass.
Timers remain disabled. T03/T04 stay progress until durable independent custody,
retention/schedule admission and actual recurring operation are evidenced.