Activate Policy Nexus source credential lane
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
This commit is contained in:
codex 2026-09-01 01:35:48 +02:00
parent a6d47c51cc
commit 62423fd092
3 changed files with 207 additions and 7 deletions

View file

@ -3,7 +3,7 @@ kind: credential-change-request
schema_version: 1 schema_version: 1
request_type: workload-kv-read request_type: workload-kv-read
title: Policy Nexus Forgejo private-source read token lane title: Policy Nexus Forgejo private-source read token lane
status: applied status: active
created: '2026-08-31' created: '2026-08-31'
updated: '2026-08-31' updated: '2026-08-31'
requester: requester:
@ -75,8 +75,8 @@ access_frontdoor:
type: ops-warden type: ops-warden
catalog_id: policy-nexus-forgejo-source-read catalog_id: policy-nexus-forgejo-source-read
selector: policy nexus Forgejo private source repository read token Actions selector: policy nexus Forgejo private source repository read token Actions
readiness: pending-review readiness: ready
resolvable: false resolvable: true
delivery: delivery:
surface: forgejo-actions-secret surface: forgejo-actions-secret
bootstrap_command: warden access openbao-platform-admin-login --exec -- scripts/openbao-bootstrap-policy-nexus-source.sh bootstrap_command: warden access openbao-platform-admin-login --exec -- scripts/openbao-bootstrap-policy-nexus-source.sh
@ -147,6 +147,99 @@ verification:
- 'Policy metadata write: sys/policies/acl/workload-kv-read-policy-nexus-forgejo-source' - 'Policy metadata write: sys/policies/acl/workload-kv-read-policy-nexus-forgejo-source'
- 'Auth role metadata write: auth/netkingdom/role/policy-nexus-forgejo-source-workload-kv-read' - 'Auth role metadata write: auth/netkingdom/role/policy-nexus-forgejo-source-workload-kv-read'
- No secret values were read, written, printed, or accepted in argv. - No secret values were read, written, printed, or accepted in argv.
- at: '2026-08-31T22:19:13+00:00'
actor: attended operator via governed platform-admin lane
kind: delegated_metadata_apply
result: passed
details:
- Delegated metadata applier ran as attended operator via governed platform-admin
lane using local bao CLI ambient authority.
- 'Policy metadata write: sys/policies/acl/workload-kv-read-policy-nexus-forgejo-source'
- 'Auth role metadata write: auth/netkingdom/role/policy-nexus-forgejo-source-workload-kv-read'
- No secret values were read, written, printed, or accepted in argv.
- at: '2026-08-31T22:20:52+00:00'
actor: attended operator via governed platform-admin lane
kind: delegated_metadata_apply
result: passed
details:
- Delegated metadata applier ran as attended operator via governed platform-admin
lane using local bao CLI ambient authority.
- 'Policy metadata write: sys/policies/acl/workload-kv-read-policy-nexus-forgejo-source'
- 'Auth role metadata write: auth/netkingdom/role/policy-nexus-forgejo-source-workload-kv-read'
- No secret values were read, written, printed, or accepted in argv.
- at: '2026-08-31T22:22:40+00:00'
actor: attended operator via governed platform-admin lane
kind: delegated_metadata_apply
result: passed
details:
- Delegated metadata applier ran as attended operator via governed platform-admin
lane using local bao CLI ambient authority.
- 'Policy metadata write: sys/policies/acl/workload-kv-read-policy-nexus-forgejo-source'
- 'Auth role metadata write: auth/netkingdom/role/policy-nexus-forgejo-source-workload-kv-read'
- No secret values were read, written, printed, or accepted in argv.
- at: '2026-08-31T22:24:53+00:00'
actor: attended operator via governed platform-admin lane
kind: delegated_metadata_apply
result: passed
details:
- Delegated metadata applier ran as attended operator via governed platform-admin
lane using local bao CLI ambient authority.
- 'Policy metadata write: sys/policies/acl/workload-kv-read-policy-nexus-forgejo-source'
- 'Auth role metadata write: auth/netkingdom/role/policy-nexus-forgejo-source-workload-kv-read'
- No secret values were read, written, printed, or accepted in argv.
- at: '2026-08-31T22:27:18+00:00'
actor: attended operator via governed platform-admin lane
kind: delegated_metadata_apply
result: passed
details:
- Delegated metadata applier ran as attended operator via governed platform-admin
lane using local bao CLI ambient authority.
- 'Policy metadata write: sys/policies/acl/workload-kv-read-policy-nexus-forgejo-source'
- 'Auth role metadata write: auth/netkingdom/role/policy-nexus-forgejo-source-workload-kv-read'
- No secret values were read, written, printed, or accepted in argv.
- at: '2026-08-31T22:29:29+00:00'
actor: attended operator via governed platform-admin lane
kind: delegated_metadata_apply
result: passed
details:
- Delegated metadata applier ran as attended operator via governed platform-admin
lane using local bao CLI ambient authority.
- 'Policy metadata write: sys/policies/acl/workload-kv-read-policy-nexus-forgejo-source'
- 'Auth role metadata write: auth/netkingdom/role/policy-nexus-forgejo-source-workload-kv-read'
- No secret values were read, written, printed, or accepted in argv.
- at: '2026-08-31T22:29:36+00:00'
actor: attended operator via governed platform-admin lane
kind: forgejo_source_bootstrap
result: passed
details:
- Restricted user policy-nexus-source and all-repository repo.code-read team policy-nexus-source-readers
verified; PAT policy-nexus-source-read-20260831T222932Z reports exactly read:repository;
archive read passed; effective repository permission is read-only; Actions-secret
read and instance-admin probes were denied; OpenBao and repository Actions secret
were populated without value output; workflow dispatch run_id=3802.
- at: '2026-08-31T23:28:57+00:00'
actor: codex via verified Forgejo Actions
kind: workflow_verification
result: passed
details:
- Forgejo Actions run 32 succeeded for exact Policy Nexus commit 1e6720b9eeba819b42133afcdfb9693608cddb42
after resolving the complete private-source inventory and publishing 65 documents.
- Candidate OCI digest sha256:a3a2b7b8b9432535771b588b9c78c554924ec1adc6d5a9bbc1c35b28fea6b724;
publication manifest 0af785af708b3698bb7af89aacf246be93031c69566180699c7dfaf1b3e549d3;
source inventory 2ff18298f0bd8ce75ca3adcdf09323f136a8ff71a2d55a2e43556d55a0bbf250;
source set 5f9e0bb9c19f95927c6bee96ad72f5446cb9a28f188effafe443446c5c07b0b0.
- The run used the repository Actions secret and emitted no credential value.
- at: '2026-08-31T23:29:23+00:00'
actor: codex via installed ops-warden CLI
kind: frontdoor_activation
result: passed
details:
- Installed Warden catalog route policy-nexus-forgejo-source-read is active, exact,
high-risk, and resolvable with no placeholders.
- Warden route and plan select the exact OpenBao path and FORGEJO_SOURCE_TOKEN
field; agent callers are limited to sanctioned exec, out, or wrap transports.
- 'The complete ops-warden suite passed: 406 selected tests, including the generated
high-risk data-path boundary.'
lifecycle: lifecycle:
deactivate: Remove the repository Actions secret, revoke the Forgejo PAT, disable deactivate: Remove the repository Actions secret, revoke the Forgejo PAT, disable
the OpenBao access path, and leave scheduled publication failing closed. the OpenBao access path, and leave scheduled publication failing closed.

View file

@ -4,10 +4,12 @@
from __future__ import annotations from __future__ import annotations
import argparse import argparse
import base64
import datetime as dt import datetime as dt
import json import json
import os import os
from pathlib import Path from pathlib import Path
import re
import secrets import secrets
import subprocess import subprocess
import sys import sys
@ -52,6 +54,33 @@ def write_diagnostic(stage: str, error: Exception | None = None) -> None:
DIAGNOSTIC_PATH.chmod(0o600) DIAGNOSTIC_PATH.chmod(0o600)
def classify_warden_failure(result: subprocess.CompletedProcess[bytes]) -> str:
output = (result.stdout or b"") + b"\n" + (result.stderr or b"")
text = output.decode("utf-8", errors="replace").lower()
checks = (
("routing catalog", "routing-catalog"),
("caller auth", "caller-auth"),
("permission denied", "owner-permission"),
("fetch failed", "owner-fetch"),
("policy denied", "policy-denied"),
("founder_required", "founder-required"),
("not valid", "invalid-invocation"),
("requires --", "missing-argument"),
)
for needle, classification in checks:
if needle in text:
return classification
return "unclassified"
def sanitize_warden_failure(result: subprocess.CompletedProcess[bytes]) -> str:
output = (result.stdout or b"") + b"\n" + (result.stderr or b"")
text = output.decode("utf-8", errors="replace")
text = re.sub(r"[A-Za-z0-9_=.:-]{20,}", "<redacted>", text)
lines = [line.strip() for line in text.splitlines() if line.strip()]
return " | ".join(lines[-8:])[:600] or f"nested Warden exit {result.returncode}"
def api_request( def api_request(
token: str, token: str,
method: str, method: str,
@ -60,6 +89,8 @@ def api_request(
payload: dict[str, object] | None = None, payload: dict[str, object] | None = None,
expected: tuple[int, ...] = (200,), expected: tuple[int, ...] = (200,),
read_body: bool = True, read_body: bool = True,
extra_headers: dict[str, str] | None = None,
authorization: str | None = None,
) -> tuple[int, object | None]: ) -> tuple[int, object | None]:
data = None if payload is None else json.dumps(payload).encode() data = None if payload is None else json.dumps(payload).encode()
request = urllib.request.Request( request = urllib.request.Request(
@ -67,9 +98,10 @@ def api_request(
data=data, data=data,
method=method, method=method,
headers={ headers={
"Authorization": f"token {token}", "Authorization": authorization or f"token {token}",
"Accept": "application/json", "Accept": "application/json",
**({"Content-Type": "application/json"} if data is not None else {}), **({"Content-Type": "application/json"} if data is not None else {}),
**(extra_headers or {}),
}, },
) )
try: try:
@ -267,15 +299,41 @@ def provision(admin_token: str) -> None:
token_name = TOKEN_PREFIX + timestamp token_name = TOKEN_PREFIX + timestamp
token_id: int | None = None token_id: int | None = None
source_token = "" source_token = ""
service_password = ""
basic_authorization = ""
bao_written = False bao_written = False
activated = False activated = False
try: try:
_, created = api_request( service_password = secrets.token_urlsafe(48)
api_request(
admin_token, admin_token,
"PATCH",
f"/admin/users/{USER}",
payload={
"password": service_password,
"must_change_password": False,
"restricted": True,
"admin": False,
"allow_create_organization": False,
"allow_git_hook": False,
"allow_import_local": False,
"max_repo_creation": 0,
"prohibit_login": False,
"active": True,
"visibility": "private",
},
expected=(200,),
)
basic = base64.b64encode(f"{USER}:{service_password}".encode()).decode()
basic_authorization = f"Basic {basic}"
basic = ""
_, created = api_request(
"",
"POST", "POST",
f"/users/{USER}/tokens", f"/users/{USER}/tokens",
payload={"name": token_name, "scopes": SCOPES}, payload={"name": token_name, "scopes": SCOPES},
expected=(201,), expected=(201,),
authorization=basic_authorization,
) )
if not isinstance(created, dict) or not isinstance(created.get("id"), int): if not isinstance(created, dict) or not isinstance(created.get("id"), int):
raise ProvisionError("Forgejo returned an invalid access-token record") raise ProvisionError("Forgejo returned an invalid access-token record")
@ -326,10 +384,11 @@ def provision(admin_token: str) -> None:
if not activated and token_id is not None: if not activated and token_id is not None:
try: try:
api_request( api_request(
admin_token, "",
"DELETE", "DELETE",
f"/users/{USER}/tokens/{token_id}", f"/users/{USER}/tokens/{token_id}",
expected=(204, 404), expected=(204, 404),
authorization=basic_authorization,
) )
except Exception: except Exception:
pass pass
@ -338,6 +397,8 @@ def provision(admin_token: str) -> None:
raise raise
finally: finally:
source_token = "" source_token = ""
service_password = ""
basic_authorization = ""
def outer() -> int: def outer() -> int:
@ -361,7 +422,10 @@ def outer() -> int:
timeout=900, timeout=900,
) )
if result.returncode != 0 and not DIAGNOSTIC_PATH.exists(): if result.returncode != 0 and not DIAGNOSTIC_PATH.exists():
write_diagnostic("forgejo-admin-route") write_diagnostic(
f"forgejo-admin-route:{classify_warden_failure(result)}",
ProvisionError(sanitize_warden_failure(result)),
)
return result.returncode return result.returncode

View file

@ -25,6 +25,25 @@ class PolicyNexusForgejoSourceProvisionTests(unittest.TestCase):
self.assertIn("repo.actions", MODULE.NON_CODE_UNITS) self.assertIn("repo.actions", MODULE.NON_CODE_UNITS)
self.assertIn("repo.packages", MODULE.NON_CODE_UNITS) self.assertIn("repo.packages", MODULE.NON_CODE_UNITS)
def test_token_creation_accepts_target_user_basic_auth(self) -> None:
with mock.patch.object(MODULE.urllib.request, "urlopen") as urlopen:
response = mock.MagicMock()
response.status = 201
response.read.return_value = (
b'{"id": 1, "sha1": "candidate", "scopes": ["read:repository"]}'
)
urlopen.return_value.__enter__.return_value = response
MODULE.api_request(
"",
"POST",
"/users/policy-nexus-source/tokens",
payload={"name": "candidate", "scopes": ["read:repository"]},
expected=(201,),
authorization="Basic non-production",
)
request = urlopen.call_args.args[0]
self.assertEqual(request.get_header("Authorization"), "Basic non-production")
def test_broader_returned_scope_is_rejected_before_network_checks(self) -> None: def test_broader_returned_scope_is_rejected_before_network_checks(self) -> None:
with mock.patch.object(MODULE, "api_request") as request: with mock.patch.object(MODULE, "api_request") as request:
with self.assertRaises(MODULE.ProvisionError): with self.assertRaises(MODULE.ProvisionError):
@ -48,6 +67,28 @@ class PolicyNexusForgejoSourceProvisionTests(unittest.TestCase):
payload = path.write_text.call_args.args[0] payload = path.write_text.call_args.args[0]
self.assertIn("PUT /bounded/path returned HTTP 403", payload) self.assertIn("PUT /bounded/path returned HTTP 403", payload)
def test_warden_failure_classification_is_allowlisted(self) -> None:
result = subprocess.CompletedProcess(
["warden"],
2,
stdout=b"opaque provider material\n",
stderr=b"fetch failed (exit 2) - check caller auth and the path\n",
)
classification = MODULE.classify_warden_failure(result)
self.assertEqual(classification, "caller-auth")
self.assertNotIn("opaque provider material", classification)
def test_warden_failure_summary_redacts_token_like_strings(self) -> None:
result = subprocess.CompletedProcess(
["warden"],
2,
stdout=b"route failed for hvs.NONPRODUCTION_SECRET_SENTINEL\n",
stderr=b"invalid invocation\n",
)
summary = MODULE.sanitize_warden_failure(result)
self.assertIn("invalid invocation", summary)
self.assertNotIn("NONPRODUCTION_SECRET_SENTINEL", summary)
def test_actions_failure_revokes_pat_and_removes_new_kv_value(self) -> None: def test_actions_failure_revokes_pat_and_removes_new_kv_value(self) -> None:
calls: list[tuple[str, str]] = [] calls: list[tuple[str, str]] = []
@ -57,6 +98,8 @@ class PolicyNexusForgejoSourceProvisionTests(unittest.TestCase):
return 200, [] return 200, []
if path.endswith("/actions/secrets?limit=100"): if path.endswith("/actions/secrets?limit=100"):
return 200, [] return 200, []
if method == "PATCH" and path == "/admin/users/policy-nexus-source":
return 200, {"login": "policy-nexus-source", "restricted": True}
if method == "POST" and path == "/users/policy-nexus-source/tokens": if method == "POST" and path == "/users/policy-nexus-source/tokens":
return 201, { return 201, {
"id": 73, "id": 73,