From a94d06dbcf0c4991d07eb69523c05a713acd59c2 Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 8 Sep 2026 22:40:04 +0200 Subject: [PATCH] docs(custody): record attended KeyCape first-provision authority proof Assistant: codex Assistant-Model: gpt-5.6-luna Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc --- WORK-RECORDS.md | 6 ++ .../keycape-approval-clients.md | 22 +++++ ...08-keycape-approval-custody-preflight.json | 86 +++++++++++++++++++ scripts/keycape-approval-custody-preflight.py | 64 ++++++++++++++ ...-WP-0035-credential-lane-implementation.md | 26 ++++++ 5 files changed, 204 insertions(+) create mode 100644 docs/evidence/2026-09-08-keycape-approval-custody-preflight.json create mode 100644 scripts/keycape-approval-custody-preflight.py diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index 5e3512b..c5be3bc 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -14,6 +14,7 @@ | workplan | RPF-WP-0029 | blocked | — | workplans/RPF-WP-0029-backup-credential-default-removal.md | | workplan | RPF-WP-0035 | blocked | — | workplans/RPF-WP-0035-credential-lane-implementation.md | | workplan | RPF-WP-0036 | blocked | — | workplans/RPF-WP-0036-platform-service-assurance.md | +| workplan | RPF-WP-0038 | active | — | workplans/RPF-WP-0038-forgejo-scaleway-primary-coverage.md | | task | RPF-WP-0015-T01 | done | — | workplans/RPF-WP-0015-audit-core-custody-and-recovery-coordination.md | | task | RPF-WP-0015-T02 | wait | — | workplans/RPF-WP-0015-audit-core-custody-and-recovery-coordination.md | | task | RPF-WP-0015-T03 | wait | — | workplans/RPF-WP-0015-audit-core-custody-and-recovery-coordination.md | @@ -34,6 +35,7 @@ | task | RPF-WP-0035-T02 | wait | — | workplans/RPF-WP-0035-credential-lane-implementation.md | | task | RPF-WP-0035-T03 | wait | — | workplans/RPF-WP-0035-credential-lane-implementation.md | | task | RPF-WP-0035-T04 | done | — | workplans/RPF-WP-0035-credential-lane-implementation.md | +| task | RPF-WP-0035-T05 | wait | — | workplans/RPF-WP-0035-credential-lane-implementation.md | | task | RPF-WP-0036-T01 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md | | task | RPF-WP-0036-T02 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md | | task | RPF-WP-0036-T03 | wait | — | workplans/RPF-WP-0036-platform-service-assurance.md | @@ -41,3 +43,7 @@ | task | RPF-WP-0036-T05 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md | | task | RPF-WP-0036-T06 | wait | — | workplans/RPF-WP-0036-platform-service-assurance.md | | task | RPF-WP-0036-T07 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md | +| task | RPF-WP-0038-T01 | done | — | workplans/RPF-WP-0038-forgejo-scaleway-primary-coverage.md | +| task | RPF-WP-0038-T02 | done | — | workplans/RPF-WP-0038-forgejo-scaleway-primary-coverage.md | +| task | RPF-WP-0038-T03 | done | — | workplans/RPF-WP-0038-forgejo-scaleway-primary-coverage.md | +| task | RPF-WP-0038-T04 | progress | — | workplans/RPF-WP-0038-forgejo-scaleway-primary-coverage.md | diff --git a/docs/credential-lane-designs/keycape-approval-clients.md b/docs/credential-lane-designs/keycape-approval-clients.md index aca1364..0a6ed43 100644 --- a/docs/credential-lane-designs/keycape-approval-clients.md +++ b/docs/credential-lane-designs/keycape-approval-clients.md @@ -156,3 +156,25 @@ platform side; the window needs roughly 60–90 minutes with both owners present (KEY-WP-0009-T04) or to RPF-WP-0035-T02's service-JWT lane. - No approval for `approval:consume` on the operator client, now or by later scope edit. Adding it is a new lane decision. + + +## Attended authority return — 2026-09-08 + +The metadata-only first-provision preflight is now observed on the exact six +policy/role/data paths: create/update capabilities are present. The successful +session self-revoked and its helper was removed. This settles the availability +of the named operator authority, not the CCR approvals or the upstream issuer +precondition. See +[the receipt](../evidence/2026-09-08-keycape-approval-custody-preflight.json). + +For a repeat after a role/policy change, use the existing contained WSL wrapper: + +```bash +python3 scripts/openbao-attended-exec.py -- /usr/bin/python3 \ + scripts/keycape-approval-custody-preflight.py --receipt /tmp/.json +``` + +Use an absolute path to the owner command if invoking from another directory. +It emits no output or values; inspect its allowlisted capability metadata only +after Warden has completed revocation and cleanup. No custody activation or +approval is performed by this preflight. diff --git a/docs/evidence/2026-09-08-keycape-approval-custody-preflight.json b/docs/evidence/2026-09-08-keycape-approval-custody-preflight.json new file mode 100644 index 0000000..248a02f --- /dev/null +++ b/docs/evidence/2026-09-08-keycape-approval-custody-preflight.json @@ -0,0 +1,86 @@ +{ + "observed_at": "2026-09-08T20:36:47.042499+00:00", + "requests": [ + "CCR-2026-0017", + "CCR-2026-0018" + ], + "operation": "capabilities-self only", + "credential_data_read": false, + "metadata_applied": false, + "custody_activated": false, + "upstream_issuer_proven": false, + "status": "observed", + "capabilities": { + "sys/policies/acl/workload-kv-read-keycape-secrets-engine-approval": [ + "create", + "delete", + "list", + "read", + "sudo", + "update" + ], + "sys/policies/acl/workload-kv-read-keycape-approval-engine-operator": [ + "create", + "delete", + "list", + "read", + "sudo", + "update" + ], + "auth/kubernetes/role/external-secrets-keycape-secrets-engine-approval": [ + "create", + "delete", + "list", + "read", + "sudo", + "update" + ], + "auth/kubernetes/role/external-secrets-keycape-approval-engine-operator": [ + "create", + "delete", + "list", + "read", + "sudo", + "update" + ], + "platform/data/workloads/secrets-engine/approval-client": [ + "create", + "delete", + "list", + "read", + "update" + ], + "platform/data/workloads/approval-engine/operator-client": [ + "create", + "delete", + "list", + "read", + "update" + ] + }, + "required_metadata_capabilities_present": true, + "paths_verified": 6, + "login_lane": "openbao-platform-admin-login", + "launcher": "scripts/openbao-attended-exec.py", + "command": "scripts/keycape-approval-custody-preflight.py --receipt ", + "wrapper_exit": 0, + "session_self_revoked": true, + "helper_root_removed": true, + "attempt_notes": [ + { + "attempt": 1, + "result": "direct launcher unavailable; no child handoff; revocation unconfirmed", + "credential_data_read": false + }, + { + "attempt": 2, + "result": "owner wrapper login/self-revocation succeeded; capability command rejected unsupported multiple-path syntax", + "credential_data_read": false + }, + { + "attempt": 3, + "result": "six single-path capability queries succeeded; session self-revoked and helper removed", + "credential_data_read": false + } + ] +} diff --git a/scripts/keycape-approval-custody-preflight.py b/scripts/keycape-approval-custody-preflight.py new file mode 100644 index 0000000..8e631f7 --- /dev/null +++ b/scripts/keycape-approval-custody-preflight.py @@ -0,0 +1,64 @@ +"""Read-only, silent owner preflight inside Warden's attended login envelope. + +Queries only token capabilities for the exact two reviewed CCR targets. Reads +no secret data, applies no metadata, and does not record an approval. Warden +owns the temporary token helper and self-revokes after this command returns. +""" +import argparse +import json +import os +import subprocess +from datetime import datetime, timezone +from pathlib import Path + +PATHS = [ + 'sys/policies/acl/workload-kv-read-keycape-secrets-engine-approval', + 'sys/policies/acl/workload-kv-read-keycape-approval-engine-operator', + 'auth/kubernetes/role/external-secrets-keycape-secrets-engine-approval', + 'auth/kubernetes/role/external-secrets-keycape-approval-engine-operator', + 'platform/data/workloads/secrets-engine/approval-client', + 'platform/data/workloads/approval-engine/operator-client', +] +ALLOWED = {'create', 'read', 'update', 'patch', 'delete', 'list', 'sudo', 'deny', 'root'} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--receipt", type=Path, required=True) + args = parser.parse_args() + receipt = {'observed_at': datetime.now(timezone.utc).isoformat(), + 'requests': ['CCR-2026-0017', 'CCR-2026-0018'], + 'operation': 'capabilities-self only', 'credential_data_read': False, + 'metadata_applied': False, 'custody_activated': False, + 'upstream_issuer_proven': False} + caps = {} + for path in PATHS: + # This installed CLI accepts one PATH. Supplying several positional + # arguments selects a different TOKEN/PATH form or refuses the call. + result = subprocess.run(['bao', 'token', 'capabilities', '-format=json', path], + capture_output=True, text=True, timeout=20) + if result.returncode: + receipt['status'] = 'capability-query-failed' + break + payload = json.loads(result.stdout) + values = payload if isinstance(payload, list) else payload.get('capabilities') + if not isinstance(values, list) or any(v not in ALLOWED for v in values): + raise ValueError('unexpected capability response shape') + caps[path] = sorted(set(values)) + else: + receipt['status'] = 'observed' + receipt['capabilities'] = caps + receipt['required_metadata_capabilities_present'] = all( + {'create', 'update'}.issubset(values) for values in caps.values()) + receipt['paths_verified'] = len(caps) + fd = os.open(args.receipt, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) + with os.fdopen(fd, 'w') as stream: + json.dump(receipt, stream, indent=2) + stream.write('\n') + + +if __name__ == '__main__': + try: + main() + except Exception: + raise SystemExit(1) from None diff --git a/workplans/RPF-WP-0035-credential-lane-implementation.md b/workplans/RPF-WP-0035-credential-lane-implementation.md index 7adf8ea..edcebe2 100644 --- a/workplans/RPF-WP-0035-credential-lane-implementation.md +++ b/workplans/RPF-WP-0035-credential-lane-implementation.md @@ -147,6 +147,7 @@ closure: `history/2026-09-05-preflight-signing-activation-complete.md`. id: RPF-WP-0035-T05 status: wait priority: high +state_hub_task_id: "e15d62c9-e5da-5721-a135-87c050f7851c" ``` Answers KEY-WP-0013-T02 (State Hub message @@ -194,3 +195,28 @@ and access-engine Check (SECRETS-WP-0007-T04). Do not carry forward the old loca stub as a blocker. T02 still needs the accepted service issuer/JWKS, claims, audience and consumer binding. T03 still needs confirmed operator group/tenant and consumer semantics; T04 is already complete. No new owner acceptance inferred. + + +### 2026-09-08 attended capability preflight + +HFACT-WP-0001's continued execution verified the existing first-provision +front door without provisioning anything. `warden plan` selected +`openbao-platform-admin-login` / founder_required / one oidc_login. The native +`scripts/openbao-attended-exec.py` supplied the existing WSL browser launcher; +a direct attempt had no launcher and failed before handoff. Its first revocation +result was unconfirmed and is preserved in the receipt rather than silently +reclassified. The two subsequent contained sessions completed self-revocation +and helper cleanup. + +`scripts/keycape-approval-custody-preflight.py --receipt ` is +a silent, read-only command for that envelope. The installed Bao CLI supports +one path per `token capabilities` call; the final run used six single-path calls. +Create/update authority is present on both exact policy paths, both Kubernetes +auth-role paths and both KV data paths from CCR-2026-0017/0018. This is authority +metadata, not a secret-data read or policy/role/KV mutation. Receipt: +`docs/evidence/2026-09-08-keycape-approval-custody-preflight.json`. + +T05 remains wait: both CCRs are still proposed, the actual upstream ID-token +issuer precondition remains open, and no verifier-side credential is provisioned. +Client-side retrieval and audit-sender custody are still separate owner returns. +The capability receipt is not a review approval or service readiness proof.