Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
168 lines
10 KiB
Markdown
168 lines
10 KiB
Markdown
# MASON-WP-0009-T05: founder-run native capability proof
|
||
|
||
Preparation only. No credential was read, native session started, TokenRequest
|
||
issued, policy widened, KV GET performed, or route activated during preparation.
|
||
The existing T05 task stays in progress. Formal ops-mason owner source review,
|
||
founder attendance approval for the exact staged digest, and live native receipts
|
||
remain necessary. An `--approval-reference` argument records the founder's prior
|
||
disposition; it cannot approve itself or establish runtime isolation.
|
||
|
||
## Exact reuse and authority
|
||
|
||
The existing verifier `scripts/verify-fluid-telegram-lane.sh` demonstrates attended
|
||
OIDC and value-free capabilities, but accepts every failed login as a nonmember
|
||
refusal. It is not reused as proof. secrets-engine's
|
||
`OpenBaoOidcClientSecretSource` demonstrates `bao login -no-store -format=json`,
|
||
but its next operation reads CLIENT_SECRET, so that provider is not invoked here.
|
||
Existing `scripts/bao-session.sh grant MASON-WP-0009-T05` provides query authority:
|
||
45m `ops-mason-survey`, founder minting, explicit data denies, no policy/role/token
|
||
write. The grant may also carry `default`; all other token/identity policies are
|
||
refused. No new policy or credential owner is proposed.
|
||
|
||
Source inspection found neither CCR-0033's ESO reader nor CCR-0034's operator
|
||
reader grants `sys/capabilities-self` (both omit default). Calling capabilities
|
||
under their own tokens would prove endpoint denial, not the required path matrix.
|
||
The verifier uses the survey grant's existing `sys/capabilities` to query the
|
||
native lane token in memory. The lane token never enters argv, environment,
|
||
receipts or a token helper. All HTTP calls use a fixed loopback endpoint, reject
|
||
redirects/proxies and allow only login, self lookup, capability query and self
|
||
revocation endpoints. No secret or metadata GET exists in the HTTP interface.
|
||
|
||
Credential routing was read first: `WARDEN_MEMORY=0 warden route show
|
||
openbao-structure-survey --json`. That entry routes to ops-mason and is not a
|
||
credential vending surface. The initial default route lookup printed routing
|
||
metadata but failed to append its memory event outside this sandbox; no escalation
|
||
was requested. There is no active operator route in current ops-warden source;
|
||
the previously reported draft proposal must be accepted there separately.
|
||
|
||
## Concrete attended proposal
|
||
|
||
Proposal ID: `MASON-WP-0009-T05-native-capability-proof-20261011`.
|
||
Target: existing OpenBao on the railiance01 loopback tunnel and, for ESO only,
|
||
railiance01's `external-secrets/external-secrets` ServiceAccount TokenRequest.
|
||
Expected result: two exact native read-only matrices, confirmed lane/query
|
||
self-revokes, and a separately accepted nonmember refusal. Estimated software
|
||
cost EUR 0; bounded founder browser/session time around 10–20 minutes. Risk:
|
||
short-lived read-capable session tokens exist in founder process memory, and ESO
|
||
TokenRequest briefly mints a 10m JWT for the existing ServiceAccount. No secret
|
||
value is requested. No policy or deployment changes occur. Actual runtime
|
||
isolation remains unverified; exact source review and founder attendance are
|
||
procedural gates, not an autopilot grant.
|
||
|
||
After ops-mason accepts the source and the supervisor records the exact digest
|
||
and scoped founder go, the founder runs from their terminal. For each mode,
|
||
obtain a fresh existing survey grant through the established session helper.
|
||
Do not hand an agent an operator token or inspect either session file in chat.
|
||
Use a new output path each time and a private browser session for the chosen human.
|
||
The verifier requires TTY attendance, rejects ambient BAO_TOKEN/VAULT_TOKEN and
|
||
namespaces, and refuses a source digest different from the reviewed digest.
|
||
|
||
```bash
|
||
python3 scripts/verify-keycape-client-custody.py operator \
|
||
--attended --approval-reference '<recorded founder disposition>' \
|
||
--approved-source-sha256 '<reviewed script digest>' \
|
||
--survey-token-fd 3 --receipt '<new absolute 0600 receipt path>' \
|
||
3< "$HOME/.claude-bao-token"
|
||
```
|
||
|
||
Repeat with `eso` and then `nonmember`, fresh grant and receipt for each. Opening
|
||
the existing grant FD is performed only in the founder terminal. The verifier
|
||
closes it and self-revokes the query token. Existing `bao-session.sh revoke` is
|
||
then used by the founder to remove the stale grant file; its printed success is
|
||
not accepted as revocation evidence because that helper suppresses revoke errors.
|
||
The verifier's native revoke receipt is the relevant evidence.
|
||
|
||
For ESO the runner first captures node metadata via fixed `ssh -oBatchMode=yes
|
||
railiance01 'kubectl get nodes -o json'` and refuses any estate other than one node
|
||
with address `92.205.62.239`. It then captures only the exact audience `openbao`,
|
||
10m ServiceAccount TokenRequest JWT in memory and logs in at
|
||
`auth/kubernetes/login` as `external-secrets-keycape-secrets-engine-openbao`.
|
||
No Secret object, pod or controller token is read. The independently minted lane
|
||
token is revoked; the running ESO controller's token is never touched. If the
|
||
node metadata does not expose the documented IP, stop for platform owner source
|
||
review of the estate pin; do not loosen the check at runtime.
|
||
|
||
## Receipt acceptance and remaining proof gates
|
||
|
||
Schema `mason-client-custody-native/v1` includes exact script digest, proposal
|
||
reference, mode, timestamp, accessor SHA256, matrix and cleanup booleans. Files
|
||
are reserved with O_EXCL/O_NOFOLLOW and mode 0600. Raw CLI/HTTP errors and auth
|
||
responses are never copied into receipts. Capability queries must return every
|
||
named path; missing rows, unexpected default/identity policies, wrong role,
|
||
wrong ESO namespace/name, TTL over 5m/15m, any data write or parent/sibling/metadata
|
||
capability fail closed. `capability_matrix_observed` means observations passed;
|
||
`owner_acceptance: pending` is retained even when exit status is zero.
|
||
|
||
Operator and ESO acceptance requires ops-mason's actual owner review against the
|
||
existing CCRs/source receipts, native role/policy/TTL observations, exact read-only
|
||
matrix and **both** lane/query revocation confirmations. Operator role/claims
|
||
remain grounded in the existing approved CCR-0034 binding, not a CLI role label
|
||
chosen by the human. ESO metadata must show the fixed service account and role.
|
||
|
||
Nonmember never auto-passes. A semantic groups mismatch from the OIDC callback is
|
||
only `group_refusal_candidate`; transport failure, cancellation, HTTP 403 alone,
|
||
wrong issuer, malformed JSON, or MFA failure is `unproved_login_failure`. An
|
||
unexpected successful nonmember login is revoked and fails the run.
|
||
|
||
Before ops-mason accepts check 3, key-cape supplies a value-free owner-authenticated
|
||
identity record proving the **same attempted subject** is human, outside
|
||
net-kingdom-admins and aal2, with validated issuer/signature/expiry; platform supplies
|
||
a correlated native OpenBao callback refusal specifically for groups. The records
|
||
must bind the same attempt using an owner-verified request/flow correlation digest,
|
||
not merely nearby timestamps, a user-selected `nonmember` mode or decoded JWT
|
||
claims. Include owner record ids/digests, observed time, subject fingerprint,
|
||
issuer validation boolean, `group_member=false`, `aal2=true`, callback endpoint,
|
||
refusal class and no token issued. The identity/flow digest must be produced and
|
||
verified inside the owners' attended/audit surface; the runner does not possess
|
||
the upstream OIDC JWT and cannot manufacture this evidence. If owners cannot
|
||
produce this correlation, check 3 stays unproved. Never publish raw JWTs, callback
|
||
URLs/codes/states, cookies, session ids or authentication errors.
|
||
|
||
This is separate from KEY-WP-0039 human/coding-agent JWT boundary evidence and
|
||
secrets-engine's service identity denial matrix. Those do not prove this reader's
|
||
nonmember binding. The existing successful service-jwt exchange and self-revokes
|
||
remain accepted prior evidence; do not discard or regenerate them merely to
|
||
complete these different gates. ops-warden may activate the pointer only after
|
||
all T05 required owner-native receipts are actually accepted.
|
||
|
||
## Cleanup and failure recovery
|
||
|
||
On every obtained lane token, including policy mismatch/unexpected nonmember
|
||
success, attempt lane revoke-self, then query revoke-self. A failed revoke changes
|
||
result to unproved. A query token that fails its identity check is not trusted for
|
||
further calls; record no cleanup confirmation and use the established founder
|
||
revocation path. Callback timeout/malformed native auth may leave a token whose
|
||
handle was not recovered: no cleanup success is claimed; the role's 5m/15m TTL
|
||
bounds it and the platform owner decides recovery. No policy is widened to retry.
|
||
|
||
The Kubernetes TokenRequest JWT cannot be individually revoked by this procedure;
|
||
it expires after 10m and is never persisted. Do not delete the shared ServiceAccount
|
||
or revoke the controller's token as cleanup. No KV rollback exists because no KV
|
||
request occurred. Session cleanup is the rollback; any unconfirmed cleanup is
|
||
explicit open evidence and blocks acceptance until owner resolution.
|
||
|
||
|
||
## Corrected source revision — 2026-10-11
|
||
|
||
The prior immutable stage is retained at `/tmp/mason-jwt-capability-next-stage`
|
||
(manifest e5d4781c6280c3bc8a3930c63cfb563f59752465720d6c2c3e95eb0551f8e949).
|
||
Independent source review requested changes: its HTTP202/text response could
|
||
falsely confirm revocation and missing native accessors could hash the empty
|
||
string. This revised source rejects every unsupported status/content/body/error
|
||
shape. Lookup/capability/Kubernetes-login require HTTP200 application/json and
|
||
endpoint-specific object data/auth, no `errors` member, with bounded headers/body.
|
||
Revoke succeeds only on HTTP204 with an empty body. Error envelopes never imply
|
||
cleanup; a recovered token from a mixed login envelope is retained solely for
|
||
finally cleanup. Nonempty bounded typed actual accessors are required before
|
||
fingerprinting; empty/malformed query accessors still revoke a scope-validated
|
||
query token, and empty/malformed lane accessors still revoke recovered lane tokens.
|
||
|
||
TTL is a positive integer within the declared bound, with booleans refused.
|
||
CLI stdout/stderr are captured while running with a 64KiB limit per stream;
|
||
excess or timeout kills the local process group and leaves native outcome
|
||
unproved. No unlimited capture is described as bounded. The exact approved
|
||
source digest is checked before receipt/token/native IO. 29 offline tests cover
|
||
these corrections, actual relative redirect refusal with hostile proxy settings,
|
||
synthetic oversized subprocess output, valid native204 cleanup versus bad202,
|
||
missing-accessor cleanup, and mixed-error session recovery. Source corrections
|
||
are not a new native success, owner acceptance, founder go or adoption proof.
|