Record Policy Nexus metadata apply and diagnose bootstrap
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 00:18:15 +02:00
parent 1d5f35539d
commit a6d47c51cc
3 changed files with 46 additions and 2 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: approved status: applied
created: '2026-08-31' created: '2026-08-31'
updated: '2026-08-31' updated: '2026-08-31'
requester: requester:
@ -137,6 +137,16 @@ verification:
and its public health endpoint returns 200; the KeyCape openbao-admin authorize and its public health endpoint returns 200; the KeyCape openbao-admin authorize
path returns 302. No Forgejo identity, PAT, OpenBao secret value, Actions secret, path returns 302. No Forgejo identity, PAT, OpenBao secret value, Actions secret,
or workflow run was created. or workflow run was created.
- at: '2026-08-31T22:15:50+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.
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

@ -26,6 +26,7 @@ SECRET = "FORGEJO_SOURCE_TOKEN"
TOKEN_PREFIX = "policy-nexus-source-read-" TOKEN_PREFIX = "policy-nexus-source-read-"
SCOPES = ["read:repository"] SCOPES = ["read:repository"]
REPO_DIR = Path(__file__).resolve().parent.parent REPO_DIR = Path(__file__).resolve().parent.parent
DIAGNOSTIC_PATH = Path("/tmp/policy-nexus-source-bootstrap-diagnostic.json")
NON_CODE_UNITS = ( NON_CODE_UNITS = (
"repo.actions", "repo.actions",
"repo.packages", "repo.packages",
@ -43,6 +44,14 @@ class ProvisionError(RuntimeError):
pass pass
def write_diagnostic(stage: str, error: Exception | None = None) -> None:
detail = str(error) if isinstance(error, ProvisionError) else "unexpected internal error"
DIAGNOSTIC_PATH.write_text(
json.dumps({"stage": stage, "detail": detail}, sort_keys=True) + "\n"
)
DIAGNOSTIC_PATH.chmod(0o600)
def api_request( def api_request(
token: str, token: str,
method: str, method: str,
@ -332,6 +341,7 @@ def provision(admin_token: str) -> None:
def outer() -> int: def outer() -> int:
DIAGNOSTIC_PATH.unlink(missing_ok=True)
result = subprocess.run( result = subprocess.run(
[ [
"warden", "warden",
@ -350,6 +360,8 @@ def outer() -> int:
check=False, check=False,
timeout=900, timeout=900,
) )
if result.returncode != 0 and not DIAGNOSTIC_PATH.exists():
write_diagnostic("forgejo-admin-route")
return result.returncode return result.returncode
@ -362,7 +374,12 @@ def main() -> int:
admin_token = os.environ.get("API_TOKEN", "") admin_token = os.environ.get("API_TOKEN", "")
if not admin_token: if not admin_token:
raise ProvisionError("Warden did not provide API_TOKEN") raise ProvisionError("Warden did not provide API_TOKEN")
provision(admin_token) try:
provision(admin_token)
except Exception as error:
write_diagnostic("provision", error)
raise
DIAGNOSTIC_PATH.unlink(missing_ok=True)
return 0 return 0

View file

@ -31,6 +31,23 @@ class PolicyNexusForgejoSourceProvisionTests(unittest.TestCase):
MODULE.verify_source_token("candidate", ["read:repository", "write:repository"]) MODULE.verify_source_token("candidate", ["read:repository", "write:repository"])
request.assert_not_called() request.assert_not_called()
def test_diagnostic_redacts_unexpected_exception_details(self) -> None:
with self.subTest("unexpected"):
with mock.patch.object(MODULE, "DIAGNOSTIC_PATH") as path:
MODULE.write_diagnostic("provision", RuntimeError("sensitive detail"))
payload = path.write_text.call_args.args[0]
self.assertNotIn("sensitive detail", payload)
self.assertIn("unexpected internal error", payload)
with self.subTest("bounded provision error"):
with mock.patch.object(MODULE, "DIAGNOSTIC_PATH") as path:
MODULE.write_diagnostic(
"provision",
MODULE.ProvisionError("PUT /bounded/path returned HTTP 403"),
)
payload = path.write_text.call_args.args[0]
self.assertIn("PUT /bounded/path returned HTTP 403", payload)
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]] = []