diff --git a/credential-change-requests/CCR-2026-0006-forgejo-admin-api-token-lane.yaml b/credential-change-requests/CCR-2026-0006-forgejo-admin-api-token-lane.yaml index d37fc16..dbd1725 100644 --- a/credential-change-requests/CCR-2026-0006-forgejo-admin-api-token-lane.yaml +++ b/credential-change-requests/CCR-2026-0006-forgejo-admin-api-token-lane.yaml @@ -3,20 +3,26 @@ kind: credential-change-request schema_version: 1 request_type: workload-kv-read title: Forgejo operator/admin API token (PAT) lane -status: proposed +status: applied created: '2026-07-12' updated: '2026-07-12' requester: agent: grok message_id: 54125f84-e9df-4fa0-9309-7370633a20d3 reason: Establish OpenBao custody for the Forgejo site-admin PAT currently dropped - at /tmp/forgejo-tegwick-api-token or FORGEJO_ADMIN_TOKEN on workstations. - Drivers include ACTIVITY-WP-0020 weekly package prune and railiance-apps / - railiance-platform Forgejo automation tools. + at /tmp/forgejo-tegwick-api-token or FORGEJO_ADMIN_TOKEN on workstations. Drivers + include ACTIVITY-WP-0020 weekly package prune and railiance-apps / railiance-platform + Forgejo automation tools. review: required: true required_approvers: - platform-operator + comments: + - at: '2026-07-12T14:05:00+00:00' + reviewer: bernd.worsch + decision: approved + comment: "Approved in chat \u2014 establish Forgejo admin PAT lane at platform/workloads/forgejo/forgejo-admin\ + \ (sibling to forgejo-mailer)." target: domain: infotech tenant: coulomb @@ -63,12 +69,12 @@ access_frontdoor: selector: forgejo admin PAT package prune FORGEJO_ADMIN_TOKEN command: warden access forgejo-admin-api-token --fetch API_TOKEN resolvable: false - readiness: pending-review + readiness: approved-pending-apply delivery: surface: operator-workstation - target: railiance-platform tools/cmd/forgejo-package-prune, activity-core - weekly-forgejo-package-prune shell resolver, and railiance-apps Forgejo tools - (load_token pattern after lane verified) + target: railiance-platform tools/cmd/forgejo-package-prune, activity-core weekly-forgejo-package-prune + shell resolver, and railiance-apps Forgejo tools (load_token pattern after lane + verified) risk: classification: high notes: @@ -79,25 +85,42 @@ risk: - Distinct from forgejo-mailer (SMTP) and railiance-backup-offsite-lane (WebDAV). verification: positive: - - Approved net-kingdom-admins identity can read API_TOKEN through OpenBao or - warden access without printing values in logs or hub messages. + - Approved net-kingdom-admins identity can read API_TOKEN through OpenBao or warden + access without printing values in logs or hub messages. - warden route find "forgejo admin pat" resolves to catalog id forgejo-admin-api-token. negative: - default-policy token denied on platform/data/workloads/forgejo/forgejo-admin. activation_conditions: - CCR approved by platform-operator. - Policy and OIDC role applied with platform-admin or delegated applier authority. - - PAT minted in attended Forgejo session (tegwick → Settings → Applications) - and stored at platform/workloads/forgejo/forgejo-admin; metadata fields optional. + - "PAT minted in attended Forgejo session (tegwick \u2192 Settings \u2192 Applications)\ + \ and stored at platform/workloads/forgejo/forgejo-admin; metadata fields optional." - Positive and negative verification recorded with non-secret audit references. - ops-warden catalog entry promoted from draft after verification. + evidence: + - at: '2026-07-12T14:05:07+00:00' + actor: grok + kind: delegated_metadata_apply + result: passed + details: + - Delegated metadata applier ran as grok using local bao CLI ambient authority. + - 'Policy metadata write: sys/policies/acl/workload-kv-read-forgejo-admin' + - 'Auth role metadata write: auth/netkingdom/role/forgejo-admin-workload-kv-read' + - No secret values were read, written, printed, or accepted in argv. + - at: '2026-07-12T14:06:54+00:00' + actor: grok + kind: negative_verification + result: passed + details: + - default-policy token denied on platform/data/workloads/forgejo/forgejo-admin + (HTTP 403, 2026-07-12T14:06Z) lifecycle: deactivate: Disable ops-warden catalog entry and detach OIDC role policy; revoke PAT in Forgejo and retire workstation file-drop path. rotate: Mint a new PAT in Forgejo, update API_TOKEN in OpenBao, record non-secret rotation evidence, and restart dependent automation after downstream consumers load from OpenBao. - compromised: Revoke PAT in Forgejo immediately, deactivate front door, rotate, - audit package/webhook changes, record blast-radius notes. + compromised: Revoke PAT in Forgejo immediately, deactivate front door, rotate, audit + package/webhook changes, record blast-radius notes. state_hub: - workplan_id: ACTIVITY-WP-0020 \ No newline at end of file + workplan_id: ACTIVITY-WP-0020 diff --git a/scripts/forgejo-admin-pat-provision.sh b/scripts/forgejo-admin-pat-provision.sh new file mode 100755 index 0000000..f4a42ce --- /dev/null +++ b/scripts/forgejo-admin-pat-provision.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Provision Forgejo admin PAT into OpenBao (CCR-2026-0006). +# Usage: forgejo-admin-pat-provision.sh /path/to/pat-file +# Never pass the PAT on argv; use a mode-0600 file with a single-line token. +set -euo pipefail + +PAT_FILE="${1:?usage: forgejo-admin-pat-provision.sh /path/to/pat-file (mode 0600, single line)}" +BAO_PATH="${FORGEJO_ADMIN_BAO_PATH:-platform/workloads/forgejo/forgejo-admin}" +API_USER="${FORGEJO_ADMIN_API_USER:-tegwick}" +API_BASE_URL="${FORGEJO_ADMIN_API_BASE_URL:-https://forgejo.coulomb.social}" +TOKEN_SCOPES="${FORGEJO_ADMIN_TOKEN_SCOPES:-read:package,write:package,read:repository,write:repository,read:user,write:user}" +GENERATED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + +if [[ ! -f "${PAT_FILE}" ]]; then + echo "ERROR: PAT file not found: ${PAT_FILE}" >&2 + exit 1 +fi +if [[ "$(stat -c '%a' "${PAT_FILE}")" != "600" ]]; then + echo "ERROR: PAT file must be mode 0600" >&2 + exit 1 +fi +command -v bao >/dev/null 2>&1 || { echo "ERROR: bao CLI required" >&2; exit 1; } + +# Smoke without printing token +TOKEN="$(<"${PAT_FILE}")" +code="$(curl -sS -o /dev/null -w '%{http_code}' \ + -H "Authorization: token ${TOKEN}" \ + "${API_BASE_URL}/api/v1/user")" +if [[ "${code}" != "200" ]]; then + echo "ERROR: Forgejo API smoke failed (HTTP ${code})" >&2 + exit 1 +fi +unset TOKEN + +bao kv put "${BAO_PATH}" \ + "API_TOKEN=@${PAT_FILE}" \ + "API_USER=${API_USER}" \ + "API_BASE_URL=${API_BASE_URL}" \ + "TOKEN_SCOPES=${TOKEN_SCOPES}" \ + "GENERATED_AT=${GENERATED_AT}" + +bao kv metadata get "${BAO_PATH}" >/dev/null +echo "OK: ${BAO_PATH} provisioned (field presence verified; values not printed)" \ No newline at end of file