From 34eda527552666f53054d443dc8f486f1f4528c4 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sun, 27 Sep 2026 20:45:28 +0200 Subject: [PATCH] Support exact-ID human review of ordinary approvals and prepare metered memos Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e387-534d-70e3-ad53-4ea05676db8c --- .../2026-09-27-metered-activation/index.json | 45 +++++ .../metered-20260927-provider-apply.memo.json | 1 + ...etered-20260927-provider-apply.packet.json | 163 +++++++++++++++++ .../metered-20260927-provider-exec.memo.json | 1 + ...metered-20260927-provider-exec.packet.json | 168 ++++++++++++++++++ ...metered-20260927-provider-verify.memo.json | 1 + ...tered-20260927-provider-verify.packet.json | 167 +++++++++++++++++ .../metered-20260927-worker-apply.memo.json | 1 + .../metered-20260927-worker-apply.packet.json | 113 ++++++++++++ .../metered-20260927-worker-exec.memo.json | 1 + .../metered-20260927-worker-exec.packet.json | 117 ++++++++++++ .../metered-20260927-worker-verify.memo.json | 1 + ...metered-20260927-worker-verify.packet.json | 117 ++++++++++++ informed_decision/approval_http.py | 15 +- informed_decision/runtime.py | 7 +- tests/test_exact_ordinary_review.py | 68 +++++++ tools/prepare_metered_memos.py | 59 ++++++ tools/render_deployment.py | 9 +- 18 files changed, 1048 insertions(+), 6 deletions(-) create mode 100644 docs/batches/2026-09-27-metered-activation/index.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-provider-apply.memo.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-provider-apply.packet.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-provider-exec.memo.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-provider-exec.packet.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-provider-verify.memo.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-provider-verify.packet.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-worker-apply.memo.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-worker-apply.packet.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-worker-exec.memo.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-worker-exec.packet.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-worker-verify.memo.json create mode 100644 docs/batches/2026-09-27-metered-activation/metered-20260927-worker-verify.packet.json create mode 100644 tests/test_exact_ordinary_review.py create mode 100644 tools/prepare_metered_memos.py diff --git a/docs/batches/2026-09-27-metered-activation/index.json b/docs/batches/2026-09-27-metered-activation/index.json new file mode 100644 index 0000000..5a6c6d0 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/index.json @@ -0,0 +1,45 @@ +{ + "kind": "informed-decision-bound-sitting", + "sitting_id": "metered-20260927-activation", + "principal": "uid=platform-root,ou=people,dc=netkingdom,dc=local", + "submitted": false, + "agent_disposition_forbidden": true, + "memos": [ + { + "memo_id": "metered-20260927-provider-apply", + "approval_id": "0c05bd0a-f81f-451d-840c-5565628e2edc", + "memo": "metered-20260927-provider-apply.memo.json", + "packet": "metered-20260927-provider-apply.packet.json" + }, + { + "memo_id": "metered-20260927-provider-verify", + "approval_id": "47f118a3-a86c-43ad-969d-42e09a0f45bb", + "memo": "metered-20260927-provider-verify.memo.json", + "packet": "metered-20260927-provider-verify.packet.json" + }, + { + "memo_id": "metered-20260927-provider-exec", + "approval_id": "7b32443a-a817-400c-a130-01b9ef04c8ee", + "memo": "metered-20260927-provider-exec.memo.json", + "packet": "metered-20260927-provider-exec.packet.json" + }, + { + "memo_id": "metered-20260927-worker-apply", + "approval_id": "2ce76d7f-01c3-4b63-8476-8d1230679769", + "memo": "metered-20260927-worker-apply.memo.json", + "packet": "metered-20260927-worker-apply.packet.json" + }, + { + "memo_id": "metered-20260927-worker-verify", + "approval_id": "c2af4bcf-15b4-4305-aac1-acc7e4dcb099", + "memo": "metered-20260927-worker-verify.memo.json", + "packet": "metered-20260927-worker-verify.packet.json" + }, + { + "memo_id": "metered-20260927-worker-exec", + "approval_id": "dc22666a-d5d7-46bc-9490-ebe9fe09dc38", + "memo": "metered-20260927-worker-exec.memo.json", + "packet": "metered-20260927-worker-exec.packet.json" + } + ] +} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-apply.memo.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-apply.memo.json new file mode 100644 index 0000000..cb960f7 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-apply.memo.json @@ -0,0 +1 @@ +{"approval_binding_digest":"sha256:a36b88244c26b1ffcd765cbadc201ff79260c7bcbd71d20d1584c3c0a3b1c3de","approval_id":"0c05bd0a-f81f-451d-840c-5565628e2edc","binding":{"justification":null,"principal":{"display_name":"uid=platform-root,ou=people,dc=netkingdom,dc=local","id":"uid=platform-root,ou=people,dc=netkingdom,dc=local","identifiers":[],"kind":"person","role":"Metered proof reviewer"},"target":{"environment":"prod","id":"catalog:glas-claude-agent-dev-anthropic","kind":"secret-catalog-lane","label":"Metered provider credential","requires_new_bind":false},"terms":null},"binding_level":"organizational","brief":"Create only the exact data-read policy and AppRole. Token TTL 5 minutes, maximum 15 minutes; single-use SecretIDs last 5 minutes; at most eight token uses. Existing KV values are preserved. This does not run the proof.","highlights":[{"id":"metered-20260927-provider-apply-scope","item_id":"metered-20260927-provider-apply-packet","locator":{},"note":"Create only the exact data-read policy and AppRole. Token TTL 5 minutes, maximum 15 minutes; single-use SecretIDs last 5 minutes; at most eight token uses. Existing KV values are preserved. This does not run the proof.","required_ack":true,"severity":"critical"}],"id":"metered-20260927-provider-apply","locale":"en","packet":[{"hash":"sha256:4b12a96e16984e6cba24abba42acf2f8fafd5a57fea6b8e007fff912bfd47b6e","item_id":"metered-20260927-provider-apply-packet","label":"Exact action and consequences"}],"question":"Approve apply for the metered provider credential lane?","requested_act":"approve","sealed":false,"step_kind":"approve","ui_release":"informed-decision@0.2.0","version":1} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-apply.packet.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-apply.packet.json new file mode 100644 index 0000000..dd5c70d --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-apply.packet.json @@ -0,0 +1,163 @@ +{ + "workplan": "SECRETS-WP-0009", + "task": "SECRETS-WP-0009-T03", + "question": "Approve apply for the metered provider credential lane?", + "consequences": "Create only the exact data-read policy and AppRole. Token TTL 5 minutes, maximum 15 minutes; single-use SecretIDs last 5 minutes; at most eight token uses. Existing KV values are preserved. This does not run the proof.", + "human_control_required": true, + "reviewer": "Human review; ordinary worker-lane control stays ordinary.", + "approval": { + "binding": { + "action": "apply", + "actor": "secrets-engine", + "digest": "sha256:a36b88244c26b1ffcd765cbadc201ff79260c7bcbd71d20d1584c3c0a3b1c3de", + "human_control": true, + "pdp_digest": "sha256:ad563454ecebe247b34e7b7dd3c06dd851d686624a00f782636a688b1f9069b9", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "fields": [], + "policy_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "stage": "prod" + }, + "id": "catalog:glas-claude-agent-dev-anthropic", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-27T18:38:25+00:00", + "entries": [], + "id": "0c05bd0a-f81f-451d-840c-5565628e2edc", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-27T18:38:25+00:00", + "validity": { + "expires_at": "2026-09-28T18:20:00+00:00", + "not_before": "2026-09-27T18:38:24.734893+00:00" + } + }, + "exact_execution_request": { + "tenant": "tenant:platform", + "subject": { + "id": "secrets-engine", + "type": "service" + }, + "action": "apply", + "resource": { + "id": "catalog:glas-claude-agent-dev-anthropic", + "type": "secret-catalog-lane", + "system": "secrets-engine", + "attributes": { + "stage": "prod", + "fields": [], + "policy_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "auth_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ] + } + }, + "context": { + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch", + "catalog_target": { + "kind": "kv", + "org": "coulomb", + "repo": "sand-boxer", + "mount": "platform", + "path": "workloads/glas-harness/claude-agent-dev", + "fields": [ + "ANTHROPIC_API_KEY" + ], + "mount_management": "existing", + "consumers": [ + { + "name": "sand-boxer-glas-agent-dev", + "auth": "approle", + "claim": "catalog:glas-claude-agent-dev-anthropic", + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch" + } + ], + "delivery_modes": [ + "exec-env", + "read-check" + ], + "delivery_auth": { + "method": "approle", + "management": "engine", + "policy_name": "se-prod-glas-claude-agent-dev-anthropic", + "role_name": "se-prod-glas-claude-agent-dev-anthropic", + "metadata_read": false, + "token_ttl": "5m", + "token_max_ttl": "15m", + "secret_id_ttl": "5m", + "secret_id_num_uses": 1, + "token_num_uses": 8 + }, + "delivery_config": { + "exec_owner": { + "status": "configured", + "owner": "rein-aharness MessagesOwner (metered-once) with sand-boxer runtime boundary", + "command": [ + "/home/tegwick/.helixforge-factory/runtimes/b6e4e8a429393d68831c996a65c0489664205df969ac9882e581983ec2da4969/bin/python3", + "-I", + "-B", + "-m", + "rein_aharness.cli", + "metered-once", + "--owner-config", + "/home/tegwick/hfact/owner-metered/owner.json" + ], + "cwd": "/home/tegwick/hfact/owner-metered", + "environment": { + "PATH": "/usr/bin:/bin", + "LANG": "C.UTF-8", + "HOME": "/home/tegwick", + "ACTIVITY_CORE_URL": "http://127.0.0.1:8010", + "AGENT_HARNESS_WORKER_ID": "rein-aharness-metered@railiance01", + "AGENT_HARNESS_OPS_LABELS": "hfact-metered", + "AGENT_HARNESS_OPS_LABELS_MODE": "all", + "AGENT_HARNESS_EXECUTION_PROJECT": "prj-helixforge-factory", + "AGENT_HARNESS_REQUIRE_SPEND_ADMISSION": "1", + "AGENT_HARNESS_REQUIRE_REQUEST_ADMISSION": "1", + "AGENT_HARNESS_SPEND_POLICY": "/home/tegwick/hfact/owner-metered/spend-policy.json", + "AGENT_HARNESS_SPEND_LEDGER": "/home/tegwick/hfact/owner-metered/spend-tool-proof-renewal-20260927.sqlite3", + "AGENT_HARNESS_REPO_MAP": "{\"hfact-glas-proof\":\"/home/tegwick/hfact/targets/hfact-glas-proof\"}" + }, + "files": { + "/home/tegwick/.helixforge-factory/runtimes/b6e4e8a429393d68831c996a65c0489664205df969ac9882e581983ec2da4969/bin/python3": { + "sha256": "e50d468e8b0adfb05733f5b87b3cff34829c4a8c1aea50c865aa8bdfe4bb150f", + "private": false + }, + "/home/tegwick/hfact/owner-metered/owner.json": { + "sha256": "fed3f80fb451b742bf306e89b6800a742db5cf75d1a6e2ed5556ee204597b9db", + "private": true + }, + "/home/tegwick/hfact/owner-metered/spend-policy.json": { + "sha256": "69ea0071d2cc4311895b1df16039438f7bbc9f6dd3c797af05d4bc845d7afde2", + "private": true + } + }, + "companions": [ + { + "catalog": "activity-core-metered-worker-token", + "field": "token", + "env": "ACTIVITY_CORE_WORKER_TOKEN" + } + ] + } + }, + "auth_capability": {}, + "workload_delivery": [] + }, + "human_control": true + } + } +} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-exec.memo.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-exec.memo.json new file mode 100644 index 0000000..0d3b931 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-exec.memo.json @@ -0,0 +1 @@ +{"approval_binding_digest":"sha256:8b31dd5911552b901b1f807a8cd6348d09547f3dbb2a52e3b42ad9fd948a2b01","approval_id":"7b32443a-a817-400c-a130-01b9ef04c8ee","binding":{"justification":null,"principal":{"display_name":"uid=platform-root,ou=people,dc=netkingdom,dc=local","id":"uid=platform-root,ou=people,dc=netkingdom,dc=local","identifiers":[],"kind":"person","role":"Metered proof reviewer"},"target":{"environment":"prod","id":"catalog:glas-claude-agent-dev-anthropic","kind":"secret-catalog-lane","label":"Metered provider credential","requires_new_bind":false},"terms":null},"binding_level":"organizational","brief":"Deliver this credential only into the hash-pinned metered owner, together with its separately approved companion. One disposable PROOF.md tool/commit attempt, no publication or automatic retry. Accepted spend memo infd-20260927-b02 limits the attempt to EUR 10 through 2026-09-28T18:20:00Z; daily EUR 20 and total EUR 500 retain prior liabilities. Both lanes must pass their own native consume and delivery gates before the child runs.","highlights":[{"id":"metered-20260927-provider-exec-scope","item_id":"metered-20260927-provider-exec-packet","locator":{},"note":"Deliver this credential only into the hash-pinned metered owner, together with its separately approved companion. One disposable PROOF.md tool/commit attempt, no publication or automatic retry. Accepted spend memo infd-20260927-b02 limits the attempt to EUR 10 through 2026-09-28T18:20:00Z; daily EUR 20 and total EUR 500 retain prior liabilities. Both lanes must pass their own native consume and delivery gates before the child runs.","required_ack":true,"severity":"critical"}],"id":"metered-20260927-provider-exec","locale":"en","packet":[{"hash":"sha256:0ae05b1937dbb6fa3339d8deb8cff6dd81620f49d5b942fa9529ffa59d6e9252","item_id":"metered-20260927-provider-exec-packet","label":"Exact action and consequences"}],"question":"Approve exec for the metered provider credential lane?","requested_act":"approve","sealed":false,"step_kind":"approve","ui_release":"informed-decision@0.2.0","version":1} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-exec.packet.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-exec.packet.json new file mode 100644 index 0000000..5dd68ff --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-exec.packet.json @@ -0,0 +1,168 @@ +{ + "workplan": "SECRETS-WP-0009", + "task": "SECRETS-WP-0009-T03", + "question": "Approve exec for the metered provider credential lane?", + "consequences": "Deliver this credential only into the hash-pinned metered owner, together with its separately approved companion. One disposable PROOF.md tool/commit attempt, no publication or automatic retry. Accepted spend memo infd-20260927-b02 limits the attempt to EUR 10 through 2026-09-28T18:20:00Z; daily EUR 20 and total EUR 500 retain prior liabilities. Both lanes must pass their own native consume and delivery gates before the child runs.", + "human_control_required": true, + "reviewer": "Human review; ordinary worker-lane control stays ordinary.", + "approval": { + "binding": { + "action": "exec", + "actor": "secrets-engine", + "digest": "sha256:8b31dd5911552b901b1f807a8cd6348d09547f3dbb2a52e3b42ad9fd948a2b01", + "human_control": true, + "pdp_digest": "sha256:62686f744536db70a48e17f416be6c32203c48d7d1bb3dbda85afb3f0e3ea0f3", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "fields": [ + "ANTHROPIC_API_KEY" + ], + "policy_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "stage": "prod" + }, + "id": "catalog:glas-claude-agent-dev-anthropic", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-27T18:38:28+00:00", + "entries": [], + "id": "7b32443a-a817-400c-a130-01b9ef04c8ee", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-27T18:38:28+00:00", + "validity": { + "expires_at": "2026-09-28T18:20:00+00:00", + "not_before": "2026-09-27T18:38:27.518711+00:00" + } + }, + "exact_execution_request": { + "tenant": "tenant:platform", + "subject": { + "id": "secrets-engine", + "type": "service" + }, + "action": "exec", + "resource": { + "id": "catalog:glas-claude-agent-dev-anthropic", + "type": "secret-catalog-lane", + "system": "secrets-engine", + "attributes": { + "stage": "prod", + "fields": [ + "ANTHROPIC_API_KEY" + ], + "policy_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "auth_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ] + } + }, + "context": { + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch", + "catalog_target": { + "kind": "kv", + "org": "coulomb", + "repo": "sand-boxer", + "mount": "platform", + "path": "workloads/glas-harness/claude-agent-dev", + "fields": [ + "ANTHROPIC_API_KEY" + ], + "mount_management": "existing", + "consumers": [ + { + "name": "sand-boxer-glas-agent-dev", + "auth": "approle", + "claim": "catalog:glas-claude-agent-dev-anthropic", + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch" + } + ], + "delivery_modes": [ + "exec-env", + "read-check" + ], + "delivery_auth": { + "method": "approle", + "management": "engine", + "policy_name": "se-prod-glas-claude-agent-dev-anthropic", + "role_name": "se-prod-glas-claude-agent-dev-anthropic", + "metadata_read": false, + "token_ttl": "5m", + "token_max_ttl": "15m", + "secret_id_ttl": "5m", + "secret_id_num_uses": 1, + "token_num_uses": 8 + }, + "delivery_config": { + "exec_owner": { + "status": "configured", + "owner": "rein-aharness MessagesOwner (metered-once) with sand-boxer runtime boundary", + "command": [ + "/home/tegwick/.helixforge-factory/runtimes/b6e4e8a429393d68831c996a65c0489664205df969ac9882e581983ec2da4969/bin/python3", + "-I", + "-B", + "-m", + "rein_aharness.cli", + "metered-once", + "--owner-config", + "/home/tegwick/hfact/owner-metered/owner.json" + ], + "cwd": "/home/tegwick/hfact/owner-metered", + "environment": { + "PATH": "/usr/bin:/bin", + "LANG": "C.UTF-8", + "HOME": "/home/tegwick", + "ACTIVITY_CORE_URL": "http://127.0.0.1:8010", + "AGENT_HARNESS_WORKER_ID": "rein-aharness-metered@railiance01", + "AGENT_HARNESS_OPS_LABELS": "hfact-metered", + "AGENT_HARNESS_OPS_LABELS_MODE": "all", + "AGENT_HARNESS_EXECUTION_PROJECT": "prj-helixforge-factory", + "AGENT_HARNESS_REQUIRE_SPEND_ADMISSION": "1", + "AGENT_HARNESS_REQUIRE_REQUEST_ADMISSION": "1", + "AGENT_HARNESS_SPEND_POLICY": "/home/tegwick/hfact/owner-metered/spend-policy.json", + "AGENT_HARNESS_SPEND_LEDGER": "/home/tegwick/hfact/owner-metered/spend-tool-proof-renewal-20260927.sqlite3", + "AGENT_HARNESS_REPO_MAP": "{\"hfact-glas-proof\":\"/home/tegwick/hfact/targets/hfact-glas-proof\"}" + }, + "files": { + "/home/tegwick/.helixforge-factory/runtimes/b6e4e8a429393d68831c996a65c0489664205df969ac9882e581983ec2da4969/bin/python3": { + "sha256": "e50d468e8b0adfb05733f5b87b3cff34829c4a8c1aea50c865aa8bdfe4bb150f", + "private": false + }, + "/home/tegwick/hfact/owner-metered/owner.json": { + "sha256": "fed3f80fb451b742bf306e89b6800a742db5cf75d1a6e2ed5556ee204597b9db", + "private": true + }, + "/home/tegwick/hfact/owner-metered/spend-policy.json": { + "sha256": "69ea0071d2cc4311895b1df16039438f7bbc9f6dd3c797af05d4bc845d7afde2", + "private": true + } + }, + "companions": [ + { + "catalog": "activity-core-metered-worker-token", + "field": "token", + "env": "ACTIVITY_CORE_WORKER_TOKEN" + } + ] + } + }, + "auth_capability": {}, + "workload_delivery": [] + }, + "human_control": true, + "exec_owner_sha256": "310600eab467ed79fc3851178a065de12d57d3ada5bcf68d9c364ed11b3ee50f" + } + } +} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-verify.memo.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-verify.memo.json new file mode 100644 index 0000000..1c7c8d4 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-verify.memo.json @@ -0,0 +1 @@ +{"approval_binding_digest":"sha256:98636335ccd36286c02fe018f296fd7d4dfd091ee89d27fe1b629e3db00cf121","approval_id":"47f118a3-a86c-43ad-969d-42e09a0f45bb","binding":{"justification":null,"principal":{"display_name":"uid=platform-root,ou=people,dc=netkingdom,dc=local","id":"uid=platform-root,ou=people,dc=netkingdom,dc=local","identifiers":[],"kind":"person","role":"Metered proof reviewer"},"target":{"environment":"prod","id":"catalog:glas-claude-agent-dev-anthropic","kind":"secret-catalog-lane","label":"Metered provider credential","requires_new_bind":false},"terms":null},"binding_level":"organizational","brief":"Verify exact data-read access, configured limits, refusal of unrelated paths, metadata, listing and writes, and session revocation. This does not run inference or display credential values.","highlights":[{"id":"metered-20260927-provider-verify-scope","item_id":"metered-20260927-provider-verify-packet","locator":{},"note":"Verify exact data-read access, configured limits, refusal of unrelated paths, metadata, listing and writes, and session revocation. This does not run inference or display credential values.","required_ack":true,"severity":"critical"}],"id":"metered-20260927-provider-verify","locale":"en","packet":[{"hash":"sha256:65d3fe42bdb085231e893c5882f201b61f6162bb39d97196be77a1e91dd6a5d2","item_id":"metered-20260927-provider-verify-packet","label":"Exact action and consequences"}],"question":"Approve verify for the metered provider credential lane?","requested_act":"approve","sealed":false,"step_kind":"approve","ui_release":"informed-decision@0.2.0","version":1} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-verify.packet.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-verify.packet.json new file mode 100644 index 0000000..474e491 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-provider-verify.packet.json @@ -0,0 +1,167 @@ +{ + "workplan": "SECRETS-WP-0009", + "task": "SECRETS-WP-0009-T03", + "question": "Approve verify for the metered provider credential lane?", + "consequences": "Verify exact data-read access, configured limits, refusal of unrelated paths, metadata, listing and writes, and session revocation. This does not run inference or display credential values.", + "human_control_required": true, + "reviewer": "Human review; ordinary worker-lane control stays ordinary.", + "approval": { + "binding": { + "action": "verify", + "actor": "secrets-engine", + "digest": "sha256:98636335ccd36286c02fe018f296fd7d4dfd091ee89d27fe1b629e3db00cf121", + "human_control": true, + "pdp_digest": "sha256:0e45d156c8a2b31789fa6f9431c260ee411d8546c3aeaf50d3ac56d5c4b39139", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "fields": [ + "ANTHROPIC_API_KEY" + ], + "policy_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "stage": "prod" + }, + "id": "catalog:glas-claude-agent-dev-anthropic", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-27T18:38:26+00:00", + "entries": [], + "id": "47f118a3-a86c-43ad-969d-42e09a0f45bb", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-27T18:38:26+00:00", + "validity": { + "expires_at": "2026-09-28T18:20:00+00:00", + "not_before": "2026-09-27T18:38:25.790058+00:00" + } + }, + "exact_execution_request": { + "tenant": "tenant:platform", + "subject": { + "id": "secrets-engine", + "type": "service" + }, + "action": "verify", + "resource": { + "id": "catalog:glas-claude-agent-dev-anthropic", + "type": "secret-catalog-lane", + "system": "secrets-engine", + "attributes": { + "stage": "prod", + "fields": [ + "ANTHROPIC_API_KEY" + ], + "policy_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ], + "auth_targets": [ + "se-prod-glas-claude-agent-dev-anthropic" + ] + } + }, + "context": { + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch", + "catalog_target": { + "kind": "kv", + "org": "coulomb", + "repo": "sand-boxer", + "mount": "platform", + "path": "workloads/glas-harness/claude-agent-dev", + "fields": [ + "ANTHROPIC_API_KEY" + ], + "mount_management": "existing", + "consumers": [ + { + "name": "sand-boxer-glas-agent-dev", + "auth": "approle", + "claim": "catalog:glas-claude-agent-dev-anthropic", + "purpose": "Owner-admitted glas-harness agt run through the reviewed local profile; no caller-facing key fetch" + } + ], + "delivery_modes": [ + "exec-env", + "read-check" + ], + "delivery_auth": { + "method": "approle", + "management": "engine", + "policy_name": "se-prod-glas-claude-agent-dev-anthropic", + "role_name": "se-prod-glas-claude-agent-dev-anthropic", + "metadata_read": false, + "token_ttl": "5m", + "token_max_ttl": "15m", + "secret_id_ttl": "5m", + "secret_id_num_uses": 1, + "token_num_uses": 8 + }, + "delivery_config": { + "exec_owner": { + "status": "configured", + "owner": "rein-aharness MessagesOwner (metered-once) with sand-boxer runtime boundary", + "command": [ + "/home/tegwick/.helixforge-factory/runtimes/b6e4e8a429393d68831c996a65c0489664205df969ac9882e581983ec2da4969/bin/python3", + "-I", + "-B", + "-m", + "rein_aharness.cli", + "metered-once", + "--owner-config", + "/home/tegwick/hfact/owner-metered/owner.json" + ], + "cwd": "/home/tegwick/hfact/owner-metered", + "environment": { + "PATH": "/usr/bin:/bin", + "LANG": "C.UTF-8", + "HOME": "/home/tegwick", + "ACTIVITY_CORE_URL": "http://127.0.0.1:8010", + "AGENT_HARNESS_WORKER_ID": "rein-aharness-metered@railiance01", + "AGENT_HARNESS_OPS_LABELS": "hfact-metered", + "AGENT_HARNESS_OPS_LABELS_MODE": "all", + "AGENT_HARNESS_EXECUTION_PROJECT": "prj-helixforge-factory", + "AGENT_HARNESS_REQUIRE_SPEND_ADMISSION": "1", + "AGENT_HARNESS_REQUIRE_REQUEST_ADMISSION": "1", + "AGENT_HARNESS_SPEND_POLICY": "/home/tegwick/hfact/owner-metered/spend-policy.json", + "AGENT_HARNESS_SPEND_LEDGER": "/home/tegwick/hfact/owner-metered/spend-tool-proof-renewal-20260927.sqlite3", + "AGENT_HARNESS_REPO_MAP": "{\"hfact-glas-proof\":\"/home/tegwick/hfact/targets/hfact-glas-proof\"}" + }, + "files": { + "/home/tegwick/.helixforge-factory/runtimes/b6e4e8a429393d68831c996a65c0489664205df969ac9882e581983ec2da4969/bin/python3": { + "sha256": "e50d468e8b0adfb05733f5b87b3cff34829c4a8c1aea50c865aa8bdfe4bb150f", + "private": false + }, + "/home/tegwick/hfact/owner-metered/owner.json": { + "sha256": "fed3f80fb451b742bf306e89b6800a742db5cf75d1a6e2ed5556ee204597b9db", + "private": true + }, + "/home/tegwick/hfact/owner-metered/spend-policy.json": { + "sha256": "69ea0071d2cc4311895b1df16039438f7bbc9f6dd3c797af05d4bc845d7afde2", + "private": true + } + }, + "companions": [ + { + "catalog": "activity-core-metered-worker-token", + "field": "token", + "env": "ACTIVITY_CORE_WORKER_TOKEN" + } + ] + } + }, + "auth_capability": {}, + "workload_delivery": [] + }, + "human_control": true + } + } +} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-apply.memo.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-apply.memo.json new file mode 100644 index 0000000..7b6a7c9 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-apply.memo.json @@ -0,0 +1 @@ +{"approval_binding_digest":"sha256:412b79fb537d4444e52e3358820b6ea204fa17173a4420ab6372c52d010ee018","approval_id":"2ce76d7f-01c3-4b63-8476-8d1230679769","binding":{"justification":null,"principal":{"display_name":"uid=platform-root,ou=people,dc=netkingdom,dc=local","id":"uid=platform-root,ou=people,dc=netkingdom,dc=local","identifiers":[],"kind":"person","role":"Metered proof reviewer"},"target":{"environment":"prod","id":"catalog:activity-core-metered-worker-token","kind":"secret-catalog-lane","label":"Metered worker credential","requires_new_bind":false},"terms":null},"binding_level":"organizational","brief":"Create only the exact data-read policy and AppRole. Token TTL 5 minutes, maximum 15 minutes; single-use SecretIDs last 5 minutes; at most eight token uses. Existing KV values are preserved. This does not run the proof.","highlights":[{"id":"metered-20260927-worker-apply-scope","item_id":"metered-20260927-worker-apply-packet","locator":{},"note":"Create only the exact data-read policy and AppRole. Token TTL 5 minutes, maximum 15 minutes; single-use SecretIDs last 5 minutes; at most eight token uses. Existing KV values are preserved. This does not run the proof.","required_ack":true,"severity":"critical"}],"id":"metered-20260927-worker-apply","locale":"en","packet":[{"hash":"sha256:3c8f3e8b9c84e5360a7c9d373a9b3e47a3f25ea532cf0c4a4d95e0a66ded701c","item_id":"metered-20260927-worker-apply-packet","label":"Exact action and consequences"}],"question":"Approve apply for the metered worker credential lane?","requested_act":"approve","sealed":false,"step_kind":"approve","ui_release":"informed-decision@0.2.0","version":1} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-apply.packet.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-apply.packet.json new file mode 100644 index 0000000..4184401 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-apply.packet.json @@ -0,0 +1,113 @@ +{ + "workplan": "SECRETS-WP-0009", + "task": "SECRETS-WP-0009-T03", + "question": "Approve apply for the metered worker credential lane?", + "consequences": "Create only the exact data-read policy and AppRole. Token TTL 5 minutes, maximum 15 minutes; single-use SecretIDs last 5 minutes; at most eight token uses. Existing KV values are preserved. This does not run the proof.", + "human_control_required": false, + "reviewer": "Human review; ordinary worker-lane control stays ordinary.", + "approval": { + "binding": { + "action": "apply", + "actor": "secrets-engine", + "digest": "sha256:412b79fb537d4444e52e3358820b6ea204fa17173a4420ab6372c52d010ee018", + "human_control": false, + "pdp_digest": "sha256:f8cffb9005b5d267d14ec1a216a785716ad3d611422c94ab52d6d66d3b259d95", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "fields": [], + "policy_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "stage": "prod" + }, + "id": "catalog:activity-core-metered-worker-token", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-27T18:38:29+00:00", + "entries": [], + "id": "2ce76d7f-01c3-4b63-8476-8d1230679769", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-27T18:38:29+00:00", + "validity": { + "expires_at": "2026-09-28T18:20:00+00:00", + "not_before": "2026-09-27T18:38:29.092610+00:00" + } + }, + "exact_execution_request": { + "tenant": "tenant:platform", + "subject": { + "id": "secrets-engine", + "type": "service" + }, + "action": "apply", + "resource": { + "id": "catalog:activity-core-metered-worker-token", + "type": "secret-catalog-lane", + "system": "secrets-engine", + "attributes": { + "stage": "prod", + "fields": [], + "policy_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "auth_targets": [ + "se-prod-activity-core-metered-worker-token" + ] + } + }, + "context": { + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner", + "catalog_target": { + "kind": "kv", + "org": "coulomb", + "repo": "activity-core", + "mount": "platform", + "path": "workloads/activity-core/ops-run-workers/rein-aharness-metered-railiance01", + "fields": [ + "token" + ], + "mount_management": "existing", + "consumers": [ + { + "name": "rein-aharness-metered-railiance01", + "auth": "approle", + "claim": "catalog:activity-core-metered-worker-token", + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner" + } + ], + "delivery_modes": [ + "exec-env" + ], + "delivery_auth": { + "method": "approle", + "management": "engine", + "policy_name": "se-prod-activity-core-metered-worker-token", + "role_name": "se-prod-activity-core-metered-worker-token", + "metadata_read": false, + "token_ttl": "5m", + "token_max_ttl": "15m", + "secret_id_ttl": "5m", + "secret_id_num_uses": 1, + "token_num_uses": 8 + }, + "delivery_config": { + "companion_of": [ + "glas-claude-agent-dev-anthropic" + ] + }, + "auth_capability": {}, + "workload_delivery": [] + } + } + } +} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-exec.memo.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-exec.memo.json new file mode 100644 index 0000000..62d4c25 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-exec.memo.json @@ -0,0 +1 @@ +{"approval_binding_digest":"sha256:ae261c9271a21b626be354646054f493d0951f69aecdbde3cfce3ac0c5667e8f","approval_id":"dc22666a-d5d7-46bc-9490-ebe9fe09dc38","binding":{"justification":null,"principal":{"display_name":"uid=platform-root,ou=people,dc=netkingdom,dc=local","id":"uid=platform-root,ou=people,dc=netkingdom,dc=local","identifiers":[],"kind":"person","role":"Metered proof reviewer"},"target":{"environment":"prod","id":"catalog:activity-core-metered-worker-token","kind":"secret-catalog-lane","label":"Metered worker credential","requires_new_bind":false},"terms":null},"binding_level":"organizational","brief":"Deliver this credential only into the hash-pinned metered owner, together with its separately approved companion. One disposable PROOF.md tool/commit attempt, no publication or automatic retry. Accepted spend memo infd-20260927-b02 limits the attempt to EUR 10 through 2026-09-28T18:20:00Z; daily EUR 20 and total EUR 500 retain prior liabilities. Both lanes must pass their own native consume and delivery gates before the child runs.","highlights":[{"id":"metered-20260927-worker-exec-scope","item_id":"metered-20260927-worker-exec-packet","locator":{},"note":"Deliver this credential only into the hash-pinned metered owner, together with its separately approved companion. One disposable PROOF.md tool/commit attempt, no publication or automatic retry. Accepted spend memo infd-20260927-b02 limits the attempt to EUR 10 through 2026-09-28T18:20:00Z; daily EUR 20 and total EUR 500 retain prior liabilities. Both lanes must pass their own native consume and delivery gates before the child runs.","required_ack":true,"severity":"critical"}],"id":"metered-20260927-worker-exec","locale":"en","packet":[{"hash":"sha256:375d53ed68149d19d005bb0be3e77084a881b45aa69549710b7f57decf3a7764","item_id":"metered-20260927-worker-exec-packet","label":"Exact action and consequences"}],"question":"Approve exec for the metered worker credential lane?","requested_act":"approve","sealed":false,"step_kind":"approve","ui_release":"informed-decision@0.2.0","version":1} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-exec.packet.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-exec.packet.json new file mode 100644 index 0000000..54a2a3e --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-exec.packet.json @@ -0,0 +1,117 @@ +{ + "workplan": "SECRETS-WP-0009", + "task": "SECRETS-WP-0009-T03", + "question": "Approve exec for the metered worker credential lane?", + "consequences": "Deliver this credential only into the hash-pinned metered owner, together with its separately approved companion. One disposable PROOF.md tool/commit attempt, no publication or automatic retry. Accepted spend memo infd-20260927-b02 limits the attempt to EUR 10 through 2026-09-28T18:20:00Z; daily EUR 20 and total EUR 500 retain prior liabilities. Both lanes must pass their own native consume and delivery gates before the child runs.", + "human_control_required": false, + "reviewer": "Human review; ordinary worker-lane control stays ordinary.", + "approval": { + "binding": { + "action": "exec", + "actor": "secrets-engine", + "digest": "sha256:ae261c9271a21b626be354646054f493d0951f69aecdbde3cfce3ac0c5667e8f", + "human_control": false, + "pdp_digest": "sha256:93b12e31b0323a21ae310fced3add0b887658e64530f2e4bc65130ebbd6d9a3d", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "fields": [ + "token" + ], + "policy_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "stage": "prod" + }, + "id": "catalog:activity-core-metered-worker-token", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-27T18:38:31+00:00", + "entries": [], + "id": "dc22666a-d5d7-46bc-9490-ebe9fe09dc38", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-27T18:38:31+00:00", + "validity": { + "expires_at": "2026-09-28T18:20:00+00:00", + "not_before": "2026-09-27T18:38:31.300944+00:00" + } + }, + "exact_execution_request": { + "tenant": "tenant:platform", + "subject": { + "id": "secrets-engine", + "type": "service" + }, + "action": "exec", + "resource": { + "id": "catalog:activity-core-metered-worker-token", + "type": "secret-catalog-lane", + "system": "secrets-engine", + "attributes": { + "stage": "prod", + "fields": [ + "token" + ], + "policy_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "auth_targets": [ + "se-prod-activity-core-metered-worker-token" + ] + } + }, + "context": { + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner", + "catalog_target": { + "kind": "kv", + "org": "coulomb", + "repo": "activity-core", + "mount": "platform", + "path": "workloads/activity-core/ops-run-workers/rein-aharness-metered-railiance01", + "fields": [ + "token" + ], + "mount_management": "existing", + "consumers": [ + { + "name": "rein-aharness-metered-railiance01", + "auth": "approle", + "claim": "catalog:activity-core-metered-worker-token", + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner" + } + ], + "delivery_modes": [ + "exec-env" + ], + "delivery_auth": { + "method": "approle", + "management": "engine", + "policy_name": "se-prod-activity-core-metered-worker-token", + "role_name": "se-prod-activity-core-metered-worker-token", + "metadata_read": false, + "token_ttl": "5m", + "token_max_ttl": "15m", + "secret_id_ttl": "5m", + "secret_id_num_uses": 1, + "token_num_uses": 8 + }, + "delivery_config": { + "companion_of": [ + "glas-claude-agent-dev-anthropic" + ] + }, + "auth_capability": {}, + "workload_delivery": [] + } + } + } +} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-verify.memo.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-verify.memo.json new file mode 100644 index 0000000..cd436d7 --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-verify.memo.json @@ -0,0 +1 @@ +{"approval_binding_digest":"sha256:bce6e2091ed076ec0040804d24c822078ac1eda18cd62703801fc9da77898303","approval_id":"c2af4bcf-15b4-4305-aac1-acc7e4dcb099","binding":{"justification":null,"principal":{"display_name":"uid=platform-root,ou=people,dc=netkingdom,dc=local","id":"uid=platform-root,ou=people,dc=netkingdom,dc=local","identifiers":[],"kind":"person","role":"Metered proof reviewer"},"target":{"environment":"prod","id":"catalog:activity-core-metered-worker-token","kind":"secret-catalog-lane","label":"Metered worker credential","requires_new_bind":false},"terms":null},"binding_level":"organizational","brief":"Verify exact data-read access, configured limits, refusal of unrelated paths, metadata, listing and writes, and session revocation. This does not run inference or display credential values.","highlights":[{"id":"metered-20260927-worker-verify-scope","item_id":"metered-20260927-worker-verify-packet","locator":{},"note":"Verify exact data-read access, configured limits, refusal of unrelated paths, metadata, listing and writes, and session revocation. This does not run inference or display credential values.","required_ack":true,"severity":"critical"}],"id":"metered-20260927-worker-verify","locale":"en","packet":[{"hash":"sha256:ee5b72e18ef4320195f49c8bfedbb8ff09437a286784a75ea7b7de7237c494f2","item_id":"metered-20260927-worker-verify-packet","label":"Exact action and consequences"}],"question":"Approve verify for the metered worker credential lane?","requested_act":"approve","sealed":false,"step_kind":"approve","ui_release":"informed-decision@0.2.0","version":1} diff --git a/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-verify.packet.json b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-verify.packet.json new file mode 100644 index 0000000..bd98ecb --- /dev/null +++ b/docs/batches/2026-09-27-metered-activation/metered-20260927-worker-verify.packet.json @@ -0,0 +1,117 @@ +{ + "workplan": "SECRETS-WP-0009", + "task": "SECRETS-WP-0009-T03", + "question": "Approve verify for the metered worker credential lane?", + "consequences": "Verify exact data-read access, configured limits, refusal of unrelated paths, metadata, listing and writes, and session revocation. This does not run inference or display credential values.", + "human_control_required": false, + "reviewer": "Human review; ordinary worker-lane control stays ordinary.", + "approval": { + "binding": { + "action": "verify", + "actor": "secrets-engine", + "digest": "sha256:bce6e2091ed076ec0040804d24c822078ac1eda18cd62703801fc9da77898303", + "human_control": false, + "pdp_digest": "sha256:d53ce35084b40ccf92f2e0062185d721ba726323f5b6324ba5884d4fbe2c23c4", + "pdp_path": true, + "principal": "secrets-engine", + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner", + "target": { + "attributes": { + "auth_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "fields": [ + "token" + ], + "policy_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "stage": "prod" + }, + "id": "catalog:activity-core-metered-worker-token", + "system": "secrets-engine", + "type": "secret-catalog-lane" + } + }, + "created_at": "2026-09-27T18:38:30+00:00", + "entries": [], + "id": "c2af4bcf-15b4-4305-aac1-acc7e4dcb099", + "required_count": 1, + "status": "requested", + "superseded_by": null, + "updated_at": "2026-09-27T18:38:30+00:00", + "validity": { + "expires_at": "2026-09-28T18:20:00+00:00", + "not_before": "2026-09-27T18:38:30.369203+00:00" + } + }, + "exact_execution_request": { + "tenant": "tenant:platform", + "subject": { + "id": "secrets-engine", + "type": "service" + }, + "action": "verify", + "resource": { + "id": "catalog:activity-core-metered-worker-token", + "type": "secret-catalog-lane", + "system": "secrets-engine", + "attributes": { + "stage": "prod", + "fields": [ + "token" + ], + "policy_targets": [ + "se-prod-activity-core-metered-worker-token" + ], + "auth_targets": [ + "se-prod-activity-core-metered-worker-token" + ] + } + }, + "context": { + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner", + "catalog_target": { + "kind": "kv", + "org": "coulomb", + "repo": "activity-core", + "mount": "platform", + "path": "workloads/activity-core/ops-run-workers/rein-aharness-metered-railiance01", + "fields": [ + "token" + ], + "mount_management": "existing", + "consumers": [ + { + "name": "rein-aharness-metered-railiance01", + "auth": "approle", + "claim": "catalog:activity-core-metered-worker-token", + "purpose": "Claim the admitted hfact-metered ops_run as rein-aharness-metered@railiance01 inside the catalog-bound Glas metered owner" + } + ], + "delivery_modes": [ + "exec-env" + ], + "delivery_auth": { + "method": "approle", + "management": "engine", + "policy_name": "se-prod-activity-core-metered-worker-token", + "role_name": "se-prod-activity-core-metered-worker-token", + "metadata_read": false, + "token_ttl": "5m", + "token_max_ttl": "15m", + "secret_id_ttl": "5m", + "secret_id_num_uses": 1, + "token_num_uses": 8 + }, + "delivery_config": { + "companion_of": [ + "glas-claude-agent-dev-anthropic" + ] + }, + "auth_capability": {}, + "workload_delivery": [] + } + } + } +} diff --git a/informed_decision/approval_http.py b/informed_decision/approval_http.py index 77bacec..3a98dfb 100644 --- a/informed_decision/approval_http.py +++ b/informed_decision/approval_http.py @@ -16,13 +16,23 @@ from .oidc import HumanSession from .provenance import assert_human_control_dischargeable +def ordinary_review_ids(value): + """An explicit bounded set of ordinary approvals; empty keeps strict default.""" + if (not isinstance(value, (list, tuple)) or len(value) > 32 + or any(not isinstance(item, str) or not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_-]{0,127}", item) for item in value) + or len(set(value)) != len(value)): + raise ValueError("exact ordinary approval ids required") + return frozenset(value) + + class ApprovalHTTPClient: def __init__(self, origin: str, session: HumanSession, *, transport=None, clock=time.time, - allow_internal_http=False): + allow_internal_http=False, ordinary_approval_ids=()): self.origin = fixed_origin(origin, allow_internal_http=allow_internal_http) assert_human_control_dischargeable(session.principal_type) if session.tenant.value != "tenant:platform": raise ValueError("platform approver required") + self.ordinary_approval_ids = ordinary_review_ids(ordinary_approval_ids) self.session = session self.transport = transport or JSONTransport(allow_internal_http=allow_internal_http) self.clock = clock @@ -47,7 +57,8 @@ class ApprovalHTTPClient: raise ApprovalEngineError(status, reason if isinstance(reason, str) and reason in known else "upstream_refused") binding = data.get("binding") if (data.get("id") != approval_id or not isinstance(binding, dict) - or binding.get("human_control") is not True + or (binding.get("human_control") is not True and not ( + binding.get("human_control") is False and approval_id in self.ordinary_approval_ids)) or not isinstance(binding.get("digest"), str) or not re.fullmatch(r"sha256:[0-9a-f]{64}", binding["digest"]) or data.get("status") not in {"requested", "approved", "consumed", "expired", "revoked", "superseded"}): diff --git a/informed_decision/runtime.py b/informed_decision/runtime.py index f004d1b..efec7ef 100644 --- a/informed_decision/runtime.py +++ b/informed_decision/runtime.py @@ -14,7 +14,7 @@ import tempfile import threading import time -from .approval_http import ApprovalHTTPClient +from .approval_http import ApprovalHTTPClient, ordinary_review_ids from .audit import AuditCoreSink, OutboxWorker from .policy import PolicyClient from .review import ReviewController @@ -109,11 +109,12 @@ class Runtime: or info.st_size > 16384): raise ValueError("runtime configuration must be an owned private 0600 file") data = json.loads(path.read_text()) - if (set(data) != {"schema", "evidence_db", "policy", "approval_origin", "audit"} + if ((set(data) - {"ordinary_approval_ids"}) != {"schema", "evidence_db", "policy", "approval_origin", "audit"} or data["schema"] != "informed-decision.review-runtime.v1" or set(data["policy"]) != {"origin", "package", "version", "package_digest", "caller_token_file"} or set(data["audit"]) != {"origin", "sender_token_file"}): raise ValueError("invalid review runtime configuration") + ordinary = ordinary_review_ids(data.get("ordinary_approval_ids", [])) if not Path(data["evidence_db"]).is_absolute(): raise ValueError("absolute evidence database path required") from .http_transport import fixed_origin @@ -126,5 +127,5 @@ class Runtime: allow_internal_http=True) store = Store(data["evidence_db"]) controller = ReviewController(store, client, lambda session: ApprovalHTTPClient( - approval_origin, session, allow_internal_http=True)) + approval_origin, session, allow_internal_http=True, ordinary_approval_ids=tuple(ordinary))) return cls(controller, AuditPump(store, sink)) diff --git a/tests/test_exact_ordinary_review.py b/tests/test_exact_ordinary_review.py new file mode 100644 index 0000000..bbc80c9 --- /dev/null +++ b/tests/test_exact_ordinary_review.py @@ -0,0 +1,68 @@ +import copy +import json +from dataclasses import replace + +import pytest + +from informed_decision.approval_http import ApprovalHTTPClient, ordinary_review_ids +from informed_decision.approval_client import ApprovalEngineError +from informed_decision.provenance import Claim, Route, HumanControlNotDischargeable +from test_approval_http import APPROVAL, ORIGIN, Responses, session +from test_deployment_candidate import inputs, module +from test_review_runtime import config +from informed_decision.runtime import Runtime + + +def test_human_can_review_only_the_explicit_ordinary_record(): + ordinary = copy.deepcopy(APPROVAL) + ordinary['binding']['human_control'] = False + transport = Responses((200, ordinary), (200, ordinary)) + result = ApprovalHTTPClient(ORIGIN, session(), transport=transport, + ordinary_approval_ids=['fixture']).add_entry('fixture') + assert result.correlation == ('fixture', 'human-fixture', '2026-09-10T00:00:00Z') + assert transport.calls[-1][2]['body'] == b'{}' + transport = Responses((200, ordinary)) + with pytest.raises(ApprovalEngineError, match='invalid_approval_response'): + ApprovalHTTPClient(ORIGIN, session(), transport=transport, + ordinary_approval_ids=['different-id']).add_entry('fixture') + assert [c[0] for c in transport.calls] == ['GET'] + + +def test_ordinary_opt_in_cannot_make_a_service_a_human(): + service = replace(session(), principal_type=Claim('service', Route.AUTHENTICATION)) + with pytest.raises(HumanControlNotDischargeable): + ApprovalHTTPClient(ORIGIN, service, ordinary_approval_ids=['fixture']) + + +@pytest.mark.parametrize('value', [None, True, '*', ['*'], ['a', 'a'], ['x/y'], [1], list(map(str, range(33)))]) +def test_invalid_ordinary_admission_refused(value): + with pytest.raises(ValueError): + ordinary_review_ids(value) + + +def test_renderer_pins_exact_ordinary_ids_in_immutable_configuration(): + base = module.render(inputs()) + data = inputs(); data['ordinary_approval_ids'] = ['worker-verify', 'worker-apply'] + rendered = module.render(data) + old = next(o for o in base['items'] if o['kind'] == 'ConfigMap') + new = next(o for o in rendered['items'] if o['kind'] == 'ConfigMap') + assert new['metadata']['name'] != old['metadata']['name'] + assert new['immutable'] is True + assert json.loads(new['data']['runtime.json'])['ordinary_approval_ids'] == ['worker-apply', 'worker-verify'] + assert 'ordinary_approval_ids' not in json.loads(old['data']['runtime.json']) + data['ordinary_approval_ids'] = ['*'] + with pytest.raises(ValueError): module.render(data) + + +def test_runtime_refuses_invalid_ordinary_ids_before_credentials(tmp_path): + path, data = config(tmp_path) + data['ordinary_approval_ids'] = ['*']; path.write_text(json.dumps(data)) + with pytest.raises(ValueError, match='exact ordinary approval ids'): + Runtime.from_file(path) + + +def test_runtime_passes_only_configured_ids_to_human_client(tmp_path): + path, data = config(tmp_path) + data['ordinary_approval_ids'] = ['worker-apply']; path.write_text(json.dumps(data)) + runtime = Runtime.from_file(path) + assert runtime.controller.approval_factory(session()).ordinary_approval_ids == frozenset({'worker-apply'}) diff --git a/tools/prepare_metered_memos.py b/tools/prepare_metered_memos.py new file mode 100644 index 0000000..e2cf358 --- /dev/null +++ b/tools/prepare_metered_memos.py @@ -0,0 +1,59 @@ +"""Draft six unsigned memos from the exact native metered-create receipt.""" +import argparse +import hashlib +import json +from pathlib import Path +from informed_decision.memo import Memo, BindingSlice, Principal, Scope, BindingLevel, StepKind, PacketItem, Highlight +from informed_decision.records import dumps, memo_from + +LANES = {'glas-claude-agent-dev-anthropic': ('provider', True), + 'activity-core-metered-worker-token': ('worker', False)} +TEXT = { + 'apply': 'Create only the exact data-read policy and AppRole. Token TTL 5 minutes, maximum 15 minutes; single-use SecretIDs last 5 minutes; at most eight token uses. Existing KV values are preserved. This does not run the proof.', + 'verify': 'Verify exact data-read access, configured limits, refusal of unrelated paths, metadata, listing and writes, and session revocation. This does not run inference or display credential values.', + 'exec': 'Deliver this credential only into the hash-pinned metered owner, together with its separately approved companion. One disposable PROOF.md tool/commit attempt, no publication or automatic retry. Accepted spend memo infd-20260927-b02 limits the attempt to EUR 10 through 2026-09-28T18:20:00Z; daily EUR 20 and total EUR 500 retain prior liabilities. Both lanes must pass their own native consume and delivery gates before the child runs.'} + +def prepare(principal, receipt, native, output): + expected = {(lane, action) for lane in LANES for action in TEXT} + rows = receipt['requests'] + if receipt['status'] != 'created' or len(rows) != 6 or {(r['catalog'], r['action']) for r in rows} != expected: + raise ValueError('exact six created requests required') + sources = {(r['catalog'], r['action']): r for r in native} + if len(native) != 6 or set(sources) != expected: raise ValueError('exact six native bindings required') + if not principal or any(c.isspace() for c in principal): raise ValueError('live human subject required') + output.mkdir(parents=True, exist_ok=False) + index = {'kind':'informed-decision-bound-sitting','sitting_id':'metered-20260927-activation', + 'principal':principal,'submitted':False,'agent_disposition_forbidden':True,'memos':[]} + for row in rows: + lane, action = row['catalog'], row['action']; label, human = LANES[lane] + approval = row['approval']; source = sources[lane, action]; request = source['request'] + if approval['status'] != 'requested' or approval['entries'] or approval['binding']['human_control'] is not human: + raise ValueError('unapproved native record with unchanged control required') + binding = {'action':action,'actor':'secrets-engine','principal':'secrets-engine', + 'purpose':request['context']['purpose'],'target':request['resource']} + if any(approval['binding'][k] != v for k,v in binding.items()) or approval['binding']['pdp_digest'] != source['decision']['binding']['request_digest']: + raise ValueError('native action binding mismatch') + ident = row['memo_id']; packet_id = ident+'-packet' + question = f'Approve {action} for the metered {label} credential lane?' + brief = TEXT[action] + packet = json.dumps({'workplan':'SECRETS-WP-0009','task':'SECRETS-WP-0009-T03', + 'question':question,'consequences':brief,'human_control_required':human, + 'reviewer':'Human review; ordinary worker-lane control stays ordinary.', + 'approval':approval,'exact_execution_request':request},indent=2)+'\n' + digest = 'sha256:'+hashlib.sha256(packet.encode()).hexdigest() + memo = Memo(id=ident,version=1,question=question,requested_act='approve', + binding_level=BindingLevel.ORGANIZATIONAL,brief=brief, + binding=BindingSlice(principal=Principal(id=principal,kind='person',display_name=principal,role='Metered proof reviewer'), + target=Scope(kind='secret-catalog-lane',id='catalog:'+lane,label=f'Metered {label} credential',environment='prod')), + step_kind=StepKind.APPROVE,packet=(PacketItem(packet_id,'Exact action and consequences',digest),), + highlights=(Highlight(ident+'-scope',packet_id,brief,required_ack=True,severity='critical'),), + approval_id=approval['id'],approval_binding_digest=approval['binding']['digest']) + raw=dumps(memo); assert memo_from(json.loads(raw)).approval_id == approval['id'] + (output/(ident+'.memo.json')).write_text(raw+'\n'); (output/(ident+'.packet.json')).write_text(packet) + index['memos'].append({'memo_id':ident,'approval_id':approval['id'],'memo':ident+'.memo.json','packet':ident+'.packet.json'}) + (output/'index.json').write_text(json.dumps(index,indent=2)+'\n') + return len(rows) + +if __name__ == '__main__': + p=argparse.ArgumentParser(description=__doc__);p.add_argument('--principal',required=True);p.add_argument('--receipt',type=Path,required=True);p.add_argument('--native',type=Path,required=True);p.add_argument('--output',type=Path,required=True);a=p.parse_args() + print('Prepared',prepare(a.principal,json.loads(a.receipt.read_text()),json.loads(a.native.read_text()),a.output),'unsigned memos; no presentations or dispositions.') diff --git a/tools/render_deployment.py b/tools/render_deployment.py index 89c0657..05c2ff8 100644 --- a/tools/render_deployment.py +++ b/tools/render_deployment.py @@ -13,7 +13,7 @@ LABEL = {'app.kubernetes.io/name': NAME} def render(inputs): - if not isinstance(inputs,dict) or set(inputs)!={'image','policy','keycape_egress_ips','storage_class'}: + if not isinstance(inputs,dict) or (set(inputs)-{'ordinary_approval_ids'})!={'image','policy','keycape_egress_ips','storage_class'}: raise ValueError('exact image, policy, KeyCape egress IPs and storage class inputs required') if not re.fullmatch(r'forgejo\.coulomb\.social/coulomb/informed-decision@sha256:[0-9a-f]{64}',inputs['image']): raise ValueError('immutable Informed Decision registry digest required') @@ -43,6 +43,13 @@ def render(inputs): 'policy':{key:policy[key] for key in ['origin','package','version','package_digest']}, 'audit':{'origin':'http://audit-core.audit-core.svc.cluster.local:8080', 'sender_token_file':'/var/run/secrets/informed-decision/audit/token'}} + if 'ordinary_approval_ids' in inputs: + ids=inputs['ordinary_approval_ids'] + if (not isinstance(ids,list) or len(ids)>32 + or any(not isinstance(i,str) or not re.fullmatch(r'[A-Za-z0-9][A-Za-z0-9_-]{0,127}',i) for i in ids) + or len(set(ids))!=len(ids)): + raise ValueError('exact ordinary approval ids required') + config['ordinary_approval_ids']=sorted(ids) config['policy']['caller_token_file']='/var/run/secrets/informed-decision/policy/token' raw=json.dumps(config,sort_keys=True,separators=(',',':')) config_name=NAME+'-runtime-'+hashlib.sha256(raw.encode()).hexdigest()[:12]