From c9b1cea83b488f307d9521bad89bf81888dd9d52 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sat, 10 Oct 2026 12:41:20 +0200 Subject: [PATCH] Fix case render self-lifecycle stanzas; record overnight replies case_build: policies carry lookup-self/revoke-self when the CCR declares token_self_lifecycle (CCR-2026-0041 review); Forgejo bundle updated. WP-0004: six descriptions completed from owner replies (draft, awaiting acceptance). WP-0009-T05: login proof passed. WP-0010-T03: CCR-2026-0041 applied. WP-0005-T06: ops-warden catalogued the entry as draft. Co-Authored-By: Claude Opus 5.5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 327203@bnt-lap001 Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0 --- .../manifest.json | 5 +- .../workload-kv-read-keycape-forgejo-eso.hcl | 9 +++ ...rkload-kv-read-keycape-forgejo-forgejo.hcl | 9 +++ manifests/custody-descriptions.yaml | 77 +++++++++++-------- src/ops_mason/case_build.py | 16 +++- tests/test_case_build.py | 4 + ...-0004-credential-inventory-descriptions.md | 11 +++ ...fluid-telegram-operator-credential-lane.md | 5 ++ ...e-secrets-engine-openbao-client-custody.md | 10 ++- ...N-WP-0010-security-case-materialization.md | 13 ++++ 10 files changed, 120 insertions(+), 39 deletions(-) diff --git a/builds/case-forgejo-netkingdom-oidc/manifest.json b/builds/case-forgejo-netkingdom-oidc/manifest.json index 4a1cdc5..fb76bdb 100644 --- a/builds/case-forgejo-netkingdom-oidc/manifest.json +++ b/builds/case-forgejo-netkingdom-oidc/manifest.json @@ -4,8 +4,8 @@ "catalog-proposal.yaml": "8bb3faedca22c7fa995e26978a0f040def032882fb9072b3a818cd40d5ff3818", "credential-change-requests/CCR-DRAFT-FORGEJO-NETKINGDOM-OIDC-ESO.yaml": "50940969383a9c7a6a8a3c2d03a0aa6fbed574a12139072b5388402651550b3e", "credential-change-requests/CCR-DRAFT-FORGEJO-NETKINGDOM-OIDC-FORGEJO.yaml": "691423c684da31d4611b15adb601f622f89c9cd465b55c637aed0836bb9ac9c8", - "openbao/policies/workload-kv-read-keycape-forgejo-eso.hcl": "92fa2aa74b6d4254b7b15dd7f376566afdafe5bcfbc9546fa9bccdf8d2214ab8", - "openbao/policies/workload-kv-read-keycape-forgejo-forgejo.hcl": "690aa95a2ecd7eb906de87af20e3c0905854e14e864a24f4241216afa4bc9c45", + "openbao/policies/workload-kv-read-keycape-forgejo-eso.hcl": "a25095bba974a6d63674765330abf9bc0dd719c27b446c22d95e79bb21b9631e", + "openbao/policies/workload-kv-read-keycape-forgejo-forgejo.hcl": "1abeb50d99e850e3ea8d8d860216520fb73f4c26c12b551587dc4c95ce754950", "rollback.yaml": "b8bc1a3c99507183733a246d415fa5508e0f45590e9517d5a70e48ae73206fc9" }, "kv_path": "platform/workloads/keycape/forgejo", @@ -14,6 +14,7 @@ "catalog activation (ops-warden)", "client registration (net-kingdom, attended)" ], + "note": "2026-10-10: policy files updated with the token self-lifecycle stanzas (render defect found in CCR-2026-0041 review); filed as CCR-2026-0041/0042.", "security_case": { "acceptance_record": "key-cape docs/forgejo-oidc-client-request.yaml (status accepted-2026-10-08, KEY-WP-0038-T01); type acknowledged via informed-decision memo nk-wp-0048-t05-oidc-browser-relying-party-r4, hub decision e418263e", "accepted_at": "2026-10-08", diff --git a/builds/case-forgejo-netkingdom-oidc/openbao/policies/workload-kv-read-keycape-forgejo-eso.hcl b/builds/case-forgejo-netkingdom-oidc/openbao/policies/workload-kv-read-keycape-forgejo-eso.hcl index 2ecbad7..cf94ae8 100644 --- a/builds/case-forgejo-netkingdom-oidc/openbao/policies/workload-kv-read-keycape-forgejo-eso.hcl +++ b/builds/case-forgejo-netkingdom-oidc/openbao/policies/workload-kv-read-keycape-forgejo-eso.hcl @@ -4,3 +4,12 @@ path "platform/data/workloads/keycape/forgejo" { capabilities = ["read"] } + +# ESO validates its own short-lived workload session. +path "auth/token/lookup-self" { + capabilities = ["read"] +} + +path "auth/token/revoke-self" { + capabilities = ["update"] +} diff --git a/builds/case-forgejo-netkingdom-oidc/openbao/policies/workload-kv-read-keycape-forgejo-forgejo.hcl b/builds/case-forgejo-netkingdom-oidc/openbao/policies/workload-kv-read-keycape-forgejo-forgejo.hcl index 017af60..c524571 100644 --- a/builds/case-forgejo-netkingdom-oidc/openbao/policies/workload-kv-read-keycape-forgejo-forgejo.hcl +++ b/builds/case-forgejo-netkingdom-oidc/openbao/policies/workload-kv-read-keycape-forgejo-forgejo.hcl @@ -4,3 +4,12 @@ path "platform/data/workloads/keycape/forgejo" { capabilities = ["read"] } + +# ESO validates its own short-lived workload session. +path "auth/token/lookup-self" { + capabilities = ["read"] +} + +path "auth/token/revoke-self" { + capabilities = ["update"] +} diff --git a/manifests/custody-descriptions.yaml b/manifests/custody-descriptions.yaml index 4466617..3825d1b 100644 --- a/manifests/custody-descriptions.yaml +++ b/manifests/custody-descriptions.yaml @@ -12,18 +12,19 @@ operators/nextcloud: sources: [] used_by: '' operators/nextcloud/backup: - description: '' - missing: - - description - - used_by - - rotation - - on_loss - on_loss: '' + description: Operator login (BACKUP_USERNAME, BACKUP_PASSWORD) for the dedicated Nextcloud Storage Share + account Backup on nx4069.your-storageshare.de, the independent secondary backup copy lane. + missing: [] + on_loss: Resettable by the founder in the Storage Share provider admin (attended). If the share is recreated, + update the workload lane's NC_WEBDAV_TOKEN. Stored backups are unaffected. owner: railiance-platform review: draft - rotation: '' - sources: [] - used_by: '' + rotation: railiance-platform/docs/backup-credential-recovery.md; railiance-platform/credential-change-requests/CCR-2026-0004-railiance-backup-offsite-lane.yaml + sources: + - railiance-platform reply 3e490cd4 (2026-10-09) + used_by: Attended operator only, to manage the account and its create-only /railiance-backups share. + Never delivered to production; workloads get only the derived NC_WEBDAV_TOKEN/NC_WEBDAV_URL via the + workload lane. platform/workloads/activity-core/llm-connect/llm-connect-provider-secrets: description: llm-connect provider access through OpenBao workload KV and External Secrets missing: [] @@ -64,8 +65,7 @@ platform/workloads/activity-core/ops-run-workers/rein-aharness-railiance01: actcore-runtime-secret in namespace activity-core. platform/workloads/agent-harness/forgejo-deploy-key: description: agent-harness Forgejo deploy key (write sandbox; binky-control at cutover) - missing: - - used_by + missing: [] on_loss: 're-establish by railiance-platform: On railiance01 generate a new ed25519 keypair under ~/.local/agent-harness/ssh/ (mode 600); do not paste the private key into chat or Git.' owner: railiance-platform @@ -73,7 +73,10 @@ platform/workloads/agent-harness/forgejo-deploy-key: rotation: ops-warden/wiki/playbooks/agent-harness-secrets.md#lane-2-forgejo-deploy-key sources: - ops-warden catalog agent-harness-forgejo-deploy - used_by: '' + - railiance-platform reply 3e490cd4 (2026-10-09) + used_by: agent-harness worker on railiance01 (private key at ~/.local/agent-harness/ssh/forgejo-deploy); + this OpenBao copy is the recovery copy, via ops-warden agent-harness-forgejo-deploy (policy workload-kv-read-agent-harness-forgejo). + Deploy key on coulomb/executor-sandbox (write). platform/workloads/approval-engine/audit-sender: description: Provide only the approval-engine sender with source=approval-engine, tenants=[tenant:platform], may_write=true, may_read=false, evidence_kind=load-bearing, secret_policy=redact. @@ -169,8 +172,7 @@ platform/workloads/coulomb-social/backup-primary: used_by: /etc/coulomb-social-backup/primary.env platform/workloads/coulomb/whynot-design/npm-publish: description: npm package publishing through ops-warden caller-scoped fetch/exec - missing: - - used_by + missing: [] on_loss: 'Re-issue per rotation: Replace NPM_AUTH_TOKEN value directly in OpenBao and record non-secret rotation evidence.' owner: railiance-platform @@ -179,7 +181,9 @@ platform/workloads/coulomb/whynot-design/npm-publish: sources: - CCR-2026-0001-whynot-design-npm-publish.yaml - ops-warden catalog whynot-design-npm-publish - used_by: '' + - railiance-platform reply 3e490cd4 (2026-10-09) + used_by: Attended whynot-design npm publishing via ops-warden whynot-design-npm-publish (warden access + ... --exec -- npm publish), OIDC role whynot-design-workload-kv-read on auth/netkingdom. Field NPM_AUTH_TOKEN. platform/workloads/email-connect/backup-primary: description: Read this application backup publisher key pair into the admitted node delivery process; no other workload credential or escrow. @@ -367,16 +371,18 @@ platform/workloads/railiance-clock/authority-signing: used_by: /var/lib/railiance-clock/signing.pem platform/workloads/railiance-telemetry/smtp: description: Native password-reset notifier; password mounted read-only under /run/secrets/authelia-smtp/password. - missing: - - used_by - - on_loss - on_loss: '' + missing: [] + on_loss: 'Resettable by the founder in IONOS mail admin; write a new KV version keeping the other fields, + wait for ESO refresh. Cost: alert mail and Authelia reset emails fail until then; no data loss.' owner: railiance-platform review: draft rotation: railiance-platform/credential-change-requests/CCR-2026-0035-authelia-platform-smtp.yaml#lifecycle.rotate sources: - CCR-2026-0035-authelia-platform-smtp.yaml - used_by: '' + - railiance-platform reply 3e490cd4 (2026-10-09) + used_by: railiance-telemetry alert mail (ESO telemetry-smtp-eso -> Secret telemetry/telemetry-alert-smtp, + SMTP_PASSWORD only) and the Authelia password-reset notifier (CCR-2026-0035, /run/secrets/authelia-smtp/password). + Mailbox platform@coulomb.social at IONOS. platform/workloads/railiance/backup/object-storage: description: Object-store credentials for Railiance backup destinations. missing: [] @@ -418,8 +424,7 @@ platform/workloads/railiance/scaleway/bootstrap: used_by: reef-storage/tools/create-platform-audit-bucket.sh (reads, never prints) platform/workloads/rapp-qonto/keycape-client: description: rapp-qonto KeyCape workload client - missing: - - used_by + missing: [] on_loss: 'rotate by key-cape: Generate a fresh newline-free secret through an approved execution transport; never print it. NOT automatable — no admitted execution and rollback contract (see delegation.blocked_on).' owner: key-cape @@ -427,7 +432,10 @@ platform/workloads/rapp-qonto/keycape-client: rotation: ops-warden/wiki/CredentialRouting.md#routing-catalog-index sources: - ops-warden catalog rapp-qonto-keycape-client - used_by: '' + - key-cape reply 40395cc2 (2026-10-10) + used_by: (1) KeyCape via ESO -> Secret sso/keycape-rapp-qonto-client key client-secret, to verify client_credentials + for rapp-qonto-client. (2) The rapp-qonto runtime, presenting it to keycape service-token; its delivery + transport is for railiance-apps/rapp-qonto to name. platform/workloads/reuse/reuse-surface/runtime-secrets: description: reuse-surface federation hub runtime secrets through OpenBao workload KV and External Secrets missing: [] @@ -490,18 +498,19 @@ platform/workloads/state-hub/repository-rename-preflight: used_by: Namespace SecretStore openbao-state-hub-rename-preflight -> ExternalSecret/Secret state-hub-rename-preflight; required explicit API-only secretKeyRef. Owner creation, Retain deletion policy. platform/workloads/telemetry/grafana-admin: - description: '' - missing: - - description - - used_by - - rotation - - on_loss - on_loss: '' + description: Grafana native administrator for rapp-telemetry on railiance01 (ADMIN_USERNAME, ADMIN_PASSWORD), + the attended bootstrap credential. + missing: [] + on_loss: 'Resettable by a cluster operator with Grafana''s admin reset in the pod, then a new KV version + (not yet exercised). Cost: short loss of admin access; dashboards and data unaffected.' owner: railiance-platform review: draft - rotation: '' - sources: [] - used_by: '' + rotation: 'railiance-platform/docs/credential-lane-designs/telemetry-grafana.md (attended: change the + Grafana DB admin password and OpenBao together, then test old fails and new works)' + sources: + - railiance-platform reply 3e490cd4 (2026-10-09) + used_by: Grafana in namespace telemetry via ExternalSecret telemetry-grafana-admin (ESO SA/role telemetry-grafana-eso, + policy telemetry-grafana-admin-eso), plus the attended check scripts/telemetry_grafana_access.py. platform/workloads/tenant-engine/audit-core-sender: description: tenant-engine's audit-core sender token, a copy of its entry in the audit-core sender registry. Not the registry itself. diff --git a/src/ops_mason/case_build.py b/src/ops_mason/case_build.py index 74fdab4..4c2e0bf 100644 --- a/src/ops_mason/case_build.py +++ b/src/ops_mason/case_build.py @@ -123,10 +123,24 @@ def _ccr(case: dict, rendered: dict, policy: dict, role: dict | None, kv_path: s return doc +# The CCR drafts set token_self_lifecycle: true, so the platform applier generates +# these two stanzas and refuses a policy file without them (CCR-2026-0041 review). +_SELF_LIFECYCLE = """ +# ESO validates its own short-lived workload session. +path "auth/token/lookup-self" { + capabilities = ["read"] +} + +path "auth/token/revoke-self" { + capabilities = ["update"] +} +""" + + def _policy_hcl(policy: dict, prov: dict) -> str: head = (f"# {policy['template']}: rendered by ops-mason from SecurityCase {prov['case']} " f"({prov['type']}, render {prov['render_digest']}).\n# Do not edit: re-run ops-mason build --case.\n\n") - return head + policy["body"].rstrip() + "\n" + return head + policy["body"].rstrip() + "\n" + _SELF_LIFECYCLE def validate_with_platform(ccr_paths: list[Path], platform: Path = RAILIANCE_PLATFORM) -> list[str]: diff --git a/tests/test_case_build.py b/tests/test_case_build.py index c09dd15..2882be2 100644 --- a/tests/test_case_build.py +++ b/tests/test_case_build.py @@ -55,6 +55,10 @@ def test_builds_bundle_naming_case_type_and_acceptance(tmp_path, types_root): assert doc["security_case"]["acceptance_record"] and "case acceptance replaces" in doc["requester"]["reason"] hcl = (out / "openbao/policies/workload-kv-read-keycape-forgejo-eso.hcl").read_text() assert 'path "platform/data/workloads/keycape/forgejo"' in hcl and '["read"]' in hcl and "forgejo-netkingdom-oidc" in hcl + # token_self_lifecycle: true needs the self stanzas, or the platform applier refuses the file. + assert 'path "auth/token/lookup-self"' in hcl and 'path "auth/token/revoke-self"' in hcl + stanzas = [l for l in hcl.splitlines() if l.startswith("path ")] + assert len(stanzas) == 3 rollback = yaml.safe_load((out / "rollback.yaml").read_text()) assert rollback["removes_exactly"][-1] == {"kind": "kv_path", "name": "platform/workloads/keycape/forgejo"} assert rollback["removes_exactly"][0]["kind"] == "catalog_entry" diff --git a/workplans/MASON-WP-0004-credential-inventory-descriptions.md b/workplans/MASON-WP-0004-credential-inventory-descriptions.md index 1eebe9c..0e61b27 100644 --- a/workplans/MASON-WP-0004-credential-inventory-descriptions.md +++ b/workplans/MASON-WP-0004-credential-inventory-descriptions.md @@ -178,6 +178,17 @@ stays a draft until that exists. railiance-platform retired the duplicate `activity-core/default/llm-connect-provider-secrets` (message `af873813`), and the four `infotech` fluid-telegram entries were moved to `coulomb`. +2026-10-10: answers filled into the manifest (still `review: draft`, awaiting +founder acceptance and an apply run): railiance-platform (message `3e490cd4`) +completed `operators/nextcloud/backup`, `railiance-telemetry/smtp`, +`telemetry/grafana-admin`, `agent-harness/forgejo-deploy-key` and +`whynot-design/npm-publish`; key-cape (message `40395cc2`) named the two readers +of `rapp-qonto/keycape-client` (the rapp-qonto runtime's transport is for +railiance-apps to name). Still open: `operators/nextcloud` (railiance-platform +is asking the founder what it holds), `keycape-factor-issuer` rotation +(railiance-platform gap) and `user-engine/runtime` on_loss (ops-mason, after +its rotation rehearsal). + ## Make an undescribed path visible before it accumulates ```task diff --git a/workplans/MASON-WP-0005-fluid-telegram-operator-credential-lane.md b/workplans/MASON-WP-0005-fluid-telegram-operator-credential-lane.md index 8ddebb0..1c22456 100644 --- a/workplans/MASON-WP-0005-fluid-telegram-operator-credential-lane.md +++ b/workplans/MASON-WP-0005-fluid-telegram-operator-credential-lane.md @@ -293,6 +293,11 @@ role. `applied-pending-verify` (message `856bd6ba`); activation stays with ops-warden after T05. +2026-10-10: ops-warden catalogued it (`23ba584`, message `b73aa5f0`) as +`fluid-telegram-operator`, pointer-only, status `draft` (its catalog has no +applied-pending-verify), with playbook `wiki/playbooks/fluid-telegram-operator.md`. +It activates on the member receipt and the FT-WP-0002 salt probe. + ## Loose-end review — 2026-09-28 T01–T06 remain wait: accepted tenant/matrix, confirmed identity/MFA/callbacks, approved matching writer contracts, live survey, explicit construction approval and verification are outstanding. The platform design remains proposed. No lane was built or activated. diff --git a/workplans/MASON-WP-0009-keycape-secrets-engine-openbao-client-custody.md b/workplans/MASON-WP-0009-keycape-secrets-engine-openbao-client-custody.md index 472dcba..cb35142 100644 --- a/workplans/MASON-WP-0009-keycape-secrets-engine-openbao-client-custody.md +++ b/workplans/MASON-WP-0009-keycape-secrets-engine-openbao-client-custody.md @@ -127,8 +127,8 @@ exist yet" whenever `bao policy read` failed, including when the founder's ```task id: MASON-WP-0009-T05 status: wait -blocked_on: message-from:secrets-engine -blocking_reason: "CCR-2026-0038 applied by the founder 2026-10-08T22:42Z (readback matched). Waits on the login proof with a real KeyCape service JWT (SECRETS-WP-0012-T03 probe-openbao); then ops-mason checks 1-3 and 6 and invariant (ii) (deny on both guarded paths) and proposes the pointer-only route." +blocked_on: human +blocking_reason: "Check 6 passed 2026-10-10 (secrets-engine probe-openbao). Remaining: invariant (ii) and the policy/role checks under a survey grant; operator/ESO capability checks and non-member refusal are owner-run; then propose the pointer-only route." priority: medium state_hub_task_id: "1b1a0566-add7-59c1-94b0-6bb81d2d1537" ``` @@ -152,3 +152,9 @@ on the founder's approve, confirm-binding and delegated apply. approval, binding confirmation and delegated apply at 2026-10-08T22:42Z, with a matching value-free readback (evidence in the CCR). RPF-WP-0035-T02 now waits only on the login proof (SECRETS-WP-0012-T03). + +2026-10-10: check 6 passed. The founder ran `secrets-engine service-auth +probe-openbao`: ok, auth provider service-jwt, secret source +openbao-oidc-in-memory, both revoke-self true (secrets-engine evidence +`docs/evidence/2026-10-10-keycape-openbao-probe.json`, `a963a77`; message +`6ed92390`). SECRETS-WP-0012 is finished. diff --git a/workplans/MASON-WP-0010-security-case-materialization.md b/workplans/MASON-WP-0010-security-case-materialization.md index c8945ea..32577f7 100644 --- a/workplans/MASON-WP-0010-security-case-materialization.md +++ b/workplans/MASON-WP-0010-security-case-materialization.md @@ -189,3 +189,16 @@ state_hub_task_id: "f6ad0d3c-8f47-5fdf-8115-6ca9d8a1fead" Once `oidc-browser-relying-party` (or the confidential service client type) is implemented, express MASON-WP-0009's placement as a case of that type without changing the live structure, and close the hand-built path. + +2026-10-10 (T03): railiance-platform filed the drafts as CCR-2026-0041 (ESO +reader) and CCR-2026-0042 (consumer reader, in_flight until railiance-apps binds +it), messages `83465dcd`/`be3a762d`; the founder applied CCR-2026-0041 at +2026-10-09T18:09Z. Its review found a render defect: the CCRs declare +`token_self_lifecycle: true` but the policies lacked the lookup-self/revoke-self +stanzas, so the applier refused them. Fixed in `case_build.py` (test asserts +the three stanzas; output now equals the platform-generated policy apart from +comments) and in the committed bundle. Two follow-ups for the next render: +net-kingdom changed the type to `KEYCAPE_{client_id:env}_CLIENT_SECRET` +(ops-warden `23ba584`), so the render digest will change; and a live re-render +of a partly applied case will report its own objects as collisions. The KV +value waits on mint-secret (RPF-WP-0054).