diff --git a/credential-change-requests/CCR-2026-0014-policy-nexus-forgejo-source-read.yaml b/credential-change-requests/CCR-2026-0014-policy-nexus-forgejo-source-read.yaml index 851afdf..98d0d92 100644 --- a/credential-change-requests/CCR-2026-0014-policy-nexus-forgejo-source-read.yaml +++ b/credential-change-requests/CCR-2026-0014-policy-nexus-forgejo-source-read.yaml @@ -3,49 +3,74 @@ kind: credential-change-request schema_version: 1 request_type: workload-kv-read title: Policy Nexus Forgejo private-source read token lane -status: in_flight +status: approved created: '2026-08-31' updated: '2026-08-31' requester: agent: codex - reason: >- - PNEX-WP-0004 makes scheduled Policy Nexus candidate builds fetch exact - archives from private owner repositories. Anonymous Forgejo API/archive - reads return 404, while the existing Forgejo admin PAT carries package, - repository-write, and admin authority that the publication workflow must - not receive. + reason: PNEX-WP-0004 makes scheduled Policy Nexus candidate builds fetch exact archives + from private owner repositories. Anonymous Forgejo API/archive reads return 404, + while the existing Forgejo admin PAT carries package, repository-write, and admin + authority that the publication workflow must not receive. review: required: true required_approvers: - - platform-operator - - policy-nexus-owner - comments: [] -in_flight: - missing_fields: - - openbao.policy_file - - openbao.auth - blocking_reason: >- - The platform owner must choose and verify the attended OpenBao-to-Forgejo - Actions secret-delivery path before policy/auth metadata is generated. - owner: railiance-platform + - platform-operator + - policy-nexus-owner + comments: + - at: '2026-08-31T20:51:17+00:00' + reviewer: platform operator and Policy Nexus owner (chat approval) + decision: approved + comment: 'Approved 2026-08-31: dedicated restricted Forgejo service identity; + PAT scope exactly read:repository; all-repository repo.code read team with all + non-code units disabled; no package, repository-write, organization-admin, instance-admin, + cluster, or deployment authority; attended secret custody plus positive and + negative verification required.' + - at: '2026-08-31T20:51:18+00:00' + reviewer: platform operator and Policy Nexus owner (chat approval) + decision: binding_confirmed + comment: Confirmed reuse of the net-kingdom-admins OIDC group binding with only + workload-kv-read-policy-nexus-forgejo-source attached and a 15-minute TTL. target: domain: infotech tenant: coulomb workload: policy-nexus-actions environment: production - purpose: >- - Hold a dedicated Forgejo PAT with read:repository only and deliver it as + purpose: Hold a dedicated Forgejo PAT with read:repository only and deliver it as the FORGEJO_SOURCE_TOKEN secret to the policy-nexus Actions workflow. openbao: mount: platform kv_path: platform/workloads/policy-nexus/forgejo-source-read fields: - - FORGEJO_SOURCE_TOKEN - - API_USER - - API_BASE_URL - - TOKEN_SCOPES - - GENERATED_AT + - FORGEJO_SOURCE_TOKEN + - API_USER + - API_BASE_URL + - TOKEN_SCOPES + - GENERATED_AT policy_name: workload-kv-read-policy-nexus-forgejo-source + policy_file: openbao/policies/workload-kv-read-policy-nexus-forgejo-source.hcl + auth: + method: oidc + mount: netkingdom + role: policy-nexus-forgejo-source-workload-kv-read + allowed_redirect_uris: + - https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback + - http://localhost:8250/oidc/callback + - http://127.0.0.1:8250/oidc/callback + oidc_scopes: + - openid + - profile + - email + - groups + user_claim: sub + groups_claim: groups + bound_claims: + groups: + - net-kingdom-admins + bound_claims_confirmed: true + policies: + - workload-kv-read-policy-nexus-forgejo-source + ttl: 15m access_frontdoor: type: ops-warden catalog_id: policy-nexus-forgejo-source-read @@ -54,55 +79,61 @@ access_frontdoor: resolvable: false delivery: surface: forgejo-actions-secret - target: >- - Repository Actions secret FORGEJO_SOURCE_TOKEN on coulomb/policy-nexus. - Delivery is attended and must not expose the value in command output, - process arguments, Git, State Hub, or workflow logs. + target: Repository Actions secret FORGEJO_SOURCE_TOKEN on coulomb/policy-nexus. + Delivery is attended and must not expose the value in command output, process + arguments, Git, State Hub, or workflow logs. + forgejo_identity: policy-nexus-source + forgejo_team: policy-nexus-source-readers + forgejo_team_contract: Restricted service user; organization team permission read, + includes_all_repositories true, can_create_org_repo false, repo.code read, every + non-code unit none. PAT scope exactly read:repository. risk: classification: high notes: - - The PAT scope is exactly read:repository; no package, repository-write, - organization-admin, user-write, cluster, or deployment authority. - - REGISTRY_TOKEN remains a separate package-write credential and is never - reused for source acquisition. - - The workflow binds the authorization header to - https://forgejo.coulomb.social and refuses cross-origin forwarding. - - The existing Forgejo admin PAT is not an acceptable fallback. + - The PAT scope is exactly read:repository; no package, repository-write, organization-admin, + user-write, cluster, or deployment authority. + - REGISTRY_TOKEN remains a separate package-write credential and is never reused + for source acquisition. + - The workflow binds the authorization header to https://forgejo.coulomb.social + and refuses cross-origin forwarding. + - The existing Forgejo admin PAT is not an acceptable fallback. verification: positive: - - >- - A scheduled or dispatched policy-nexus workflow resolves every declared - private repository revision and exact archive, then publishes a candidate. - - >- - The token metadata reports read:repository and no broader scopes without - printing the token value. + - A scheduled or dispatched policy-nexus workflow resolves every declared private + repository revision and exact archive, then publishes a candidate. + - The token metadata reports read:repository and no broader scopes without printing + the token value. negative: - - The PAT cannot create, update, or delete repository content. - - The PAT cannot write packages or administer users, organizations, hooks, - runners, Actions secrets, or the Forgejo instance. - - A default or unrelated OpenBao identity cannot read the KV data path. - - Removing FORGEJO_SOURCE_TOKEN makes the workflow fail before source fetch. + - The PAT cannot create, update, or delete repository content. + - The PAT cannot write packages or administer users, organizations, hooks, runners, + Actions secrets, or the Forgejo instance. + - A default or unrelated OpenBao identity cannot read the KV data path. + - Removing FORGEJO_SOURCE_TOKEN makes the workflow fail before source fetch. activation_conditions: - - Platform operator and Policy Nexus owner approve this CCR. - - A dedicated service identity and read:repository-only PAT are created in - an attended Forgejo session. - - The OpenBao policy/auth path and non-secret metadata are reviewed before - apply. - - The PAT is transferred directly into OpenBao and the repository Actions - secret without logs, chat, Git, State Hub, or persistent temp files. - - Positive and negative scope tests and one workflow run are recorded. + - Platform operator and Policy Nexus owner approve this CCR. + - A dedicated service identity and read:repository-only PAT are created in an attended + Forgejo session. + - The OpenBao policy/auth path and non-secret metadata are reviewed before apply. + - The PAT is transferred directly into OpenBao and the repository Actions secret + without logs, chat, Git, State Hub, or persistent temp files. + - Positive and negative scope tests and one workflow run are recorded. + evidence: + - at: '2026-08-31T21:03:08+00:00' + actor: codex attended operator + kind: delegated_metadata_apply + result: blocked + details: + - Approved metadata dry-run passed; two governed platform-admin OIDC attempts + failed closed before command handoff; Warden revoked any possible session; no + OpenBao mutation or secret provisioning occurred. lifecycle: - deactivate: >- - Remove the repository Actions secret, revoke the Forgejo PAT, disable the - OpenBao access path, and leave scheduled publication failing closed. - rotate: >- - Mint a replacement read:repository-only PAT, update OpenBao and the Actions - secret through attended custody, pass one candidate build, then revoke the - predecessor. - compromised: >- - Remove the Actions secret and revoke the PAT immediately, inspect private - repository read activity, rotate through the approved lane, and record a - bounded incident follow-up. + deactivate: Remove the repository Actions secret, revoke the Forgejo PAT, disable + the OpenBao access path, and leave scheduled publication failing closed. + rotate: Mint a replacement read:repository-only PAT, update OpenBao and the Actions + secret through attended custody, pass one candidate build, then revoke the predecessor. + compromised: Remove the Actions secret and revoke the PAT immediately, inspect private + repository read activity, rotate through the approved lane, and record a bounded + incident follow-up. state_hub: workplan_id: PNEX-WP-0004 task_id: PNEX-WP-0004-T03 diff --git a/openbao/policies/agent-high-risk-boundary.hcl b/openbao/policies/agent-high-risk-boundary.hcl index 1d45373..60c1d63 100644 --- a/openbao/policies/agent-high-risk-boundary.hcl +++ b/openbao/policies/agent-high-risk-boundary.hcl @@ -100,3 +100,10 @@ path "auth/token/lookup-self" { path "auth/token/revoke-self" { capabilities = ["update"] } +path "platform/data/workloads/policy-nexus/forgejo-source-read" { + capabilities = ["deny"] +} + +path "platform/metadata/workloads/policy-nexus/forgejo-source-read" { + capabilities = ["deny"] +} diff --git a/openbao/policies/workload-kv-read-policy-nexus-forgejo-source.hcl b/openbao/policies/workload-kv-read-policy-nexus-forgejo-source.hcl new file mode 100644 index 0000000..57faedd --- /dev/null +++ b/openbao/policies/workload-kv-read-policy-nexus-forgejo-source.hcl @@ -0,0 +1,7 @@ +path "platform/data/workloads/policy-nexus/forgejo-source-read" { + capabilities = ["read"] +} + +path "platform/metadata/workloads/policy-nexus/forgejo-source-read" { + capabilities = ["read"] +}