Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a11fd9-caf6-7a63-b578-9daaaa134ff2
134 lines
7.8 KiB
Markdown
134 lines
7.8 KiB
Markdown
# User-engine caller policy draft — 2026-10-08
|
|
|
|
This is the historical draft review. The compatible rollout preparation below
|
|
updates its scope and resolves the source compatibility gap; activation remains open.
|
|
|
|
This file proposes the only caller that exists today. It is not mounted,
|
|
`EMAIL_CONNECT_CALLERS_FILE` is not set, and no token file was created.
|
|
EMAIL-WP-0008-T03 stays waiting until the bindings, quotas and token custody
|
|
are approved.
|
|
|
|
Source: `config/callers.user-engine.draft.json`.
|
|
|
|
## What the live caller does
|
|
|
|
user-engine sends invitation mail to `/v1/send` with source `user-engine` and
|
|
templates `family_member.invited` or `family_invitation.resent`. It reads
|
|
`/v1/status` and `/v1/delivery-status`. Registration uses
|
|
`/v1/registration-verifications`, consume and cancel. The live registration
|
|
allow-list is tenant `tenant:coulomb` and client `coulomb-social`
|
|
(`USER_ENGINE_REGISTRATION_TENANTS` / `USER_ENGINE_REGISTRATION_CLIENTS` in
|
|
`net-kingdom/sso-mfa/k8s/user-engine/runtime.yaml`). Mail and verification
|
|
share the current `user-engine-delivery` `mail-token`. Suppression is not a
|
|
user-engine operation and is omitted.
|
|
|
|
## Proposed limits
|
|
|
|
`rate_per_minute` 10 matches the live registration limit of 10 requests per
|
|
60 seconds. Burst 5 and an 8 KiB payload cap are below the receiver ceilings
|
|
(6000/minute, 600 burst, 128 KiB). They are proposals, not an approved quota.
|
|
`adopt_legacy_verifications` is proposed so this original caller can still
|
|
consume verification rows written before caller ids existed.
|
|
|
|
## Gap that blocks activation
|
|
|
|
Current invitation envelopes carry `tenant` and do not carry `client_id`.
|
|
Scoped send accepts a binding only when both fields are present and admitted,
|
|
or when both are absent and `legacy_invitation_binding` is set. A tenant
|
|
without a client id is denied. Family invitations also use tenants other than
|
|
`tenant:coulomb`. This draft therefore does not claim to carry current
|
|
invitation traffic. Activation needs a user-engine change that sends an
|
|
admitted tenant/client pair, or a separate reviewed contract change.
|
|
|
|
The token path in the draft does not exist. Selecting this file on the
|
|
running receiver would fail startup before serving traffic. Do not copy the
|
|
shared ingest token into that path as part of this draft.
|
|
|
|
## Compatible rollout preparation — 2026-10-09
|
|
|
|
User selected the proposed limits and requested glob or regex support. The draft
|
|
now admits exact tenant:coulomb/coulomb-social plus the proposed case-sensitive
|
|
tenant:*-family and tenant:family-* globs with literal client coulomb-social.
|
|
Only * and ? glob operators are supported; all patterns and actual identifiers
|
|
are bounded to 128 characters, with at most 128 total exact/pattern pairs.
|
|
These family naming patterns are proposals rather than a complete tenant inventory.
|
|
They apply to verification creation and handle consumption/cancellation as well
|
|
as invitation sends. Suppression remains excluded.
|
|
|
|
User-engine source accepts opt-in USER_ENGINE_MAIL_CLIENT_BINDINGS, a JSON list
|
|
matching config/mail-client-bindings.user-engine.draft.json. It resolves one
|
|
literal client for the actual tenant; missing or ambiguous matches refuse before
|
|
any HTTP delivery. Only the mail transport gains client_id: audit envelopes and
|
|
stored outbox payloads retain their original shape. Default unset configuration
|
|
retains current live behavior. The reviewed patch is retained in
|
|
deploy/caller-rollout/user-engine-mail-bindings.patch.
|
|
|
|
adopt_legacy_invitations explicitly reserves original invitation ids for this
|
|
user-engine caller. A matching old fingerprint can tolerate the added transport
|
|
client_id, preserving accepted evidence and terminal unknown/permanent outcomes.
|
|
Other immutable changes still refuse; admission checks precede legacy matching.
|
|
New events bind the full payload. Other callers cannot opt into this adoption.
|
|
|
|
The immutable ConfigMap and strategic deployment patch in deploy/caller-rollout
|
|
pass server dry-run; packaged-evidence-2026-10-09.json binds the local candidate
|
|
image to the exact caller module under UID10001 and disabled networking.
|
|
Before activation, deliver a caller-specific token to the separately admitted
|
|
Secret email-connect-caller-user-engine (key token) and corresponding user-engine
|
|
custody lane. Do not copy the legacy shared ingest token into that projection.
|
|
Publish/admit the new receiver image, retain the current ledger/recovery receipt,
|
|
fence outbox dispatch during coordinated token/policy transition, and set both
|
|
the receiver policy and user-engine binding configuration. Pending outbox tenants
|
|
must match the admitted scope before traffic resumes; narrow or add explicit
|
|
bindings when their names do not match these proposed globs.
|
|
|
|
The live receiver remains eb3e7b68 in single-caller mode. Capture and rehearsal
|
|
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.
|