diff --git a/docs/evidence/2026-09-11-factory-receiver-live.json b/docs/evidence/2026-09-11-factory-receiver-live.json new file mode 100644 index 0000000..0cc1e6b --- /dev/null +++ b/docs/evidence/2026-09-11-factory-receiver-live.json @@ -0,0 +1,172 @@ +{ + "schema": "hfact.factory-audit-receiver-live.v1", + "observed_at": "2026-09-11", + "release": { + "image": "forgejo.coulomb.social/coulomb/audit-core@sha256:c82e0442de0fd181342916ae9cd5d6de41d859e1efda637bd93936c67873afa5", + "source_commit": "cb23dc82fd5dbadfdfb84e99581068bd0aa667c0" + }, + "native_contract": { + "schema": "platform.factory-audit-custody.v1", + "status": "receiver_contract_supported", + "credential_values_emitted": false, + "started_at": "2026-09-11T04:50:27.072575+00:00", + "lanes": [ + { + "ccr": "CCR-2026-0021", + "name": "approval-engine", + "kv": "platform/data/workloads/approval-engine/audit-sender", + "store": "openbao-approval-engine-audit", + "secret": "approval-engine-audit", + "secret_key": "audit-token", + "source_sha256": "ba69ecc8227c5bf887c2cd0ac4c50518c019bebfdfb6d49628edee1ce570da7d" + }, + { + "ccr": "CCR-2026-0022", + "name": "informed-decision", + "kv": "platform/data/workloads/informed-decision/audit-sender", + "store": "openbao-informed-decision-audit", + "secret": "informed-decision-audit", + "secret_key": "token", + "source_sha256": "2f7f7f214d1e21fd79275197edd03ee7e154ef451d62a182017926250515a6aa" + } + ], + "receiver": { + "image": "forgejo.coulomb.social/coulomb/audit-core@sha256:c82e0442de0fd181342916ae9cd5d6de41d859e1efda637bd93936c67873afa5", + "deployment_uid": "b85fe3d0-75c9-4e0d-8c34-c6f1df0881bb", + "deployment_resource_version": "59740687", + "pod_uid": "6642c414-a942-4b11-b048-267423e12da8", + "capabilities": { + "load_bearing": true, + "redact": true, + "write_only": true, + "source_exact": true, + "tenant_exact": true + }, + "synthetic_probe_only": true, + "credential_reads": 0 + } + }, + "native_before": { + "ready": { + "status": "ok", + "custody_class": "operational", + "durable": true, + "tamper_evidence": true, + "recoverable_days": 30, + "recoverable_source": "resource-control/data/capability/platform-audit-storage.json#provisions[capability=data.backup]", + "recoverable_basis": "measured" + }, + "chain": { + "intact": true, + "events": 32, + "head": "9fc0b4f25c562cec037a5077f00ee63380db8b5c4e85b6016fc40b301431e4fd", + "head_event_id": "whitehat-e2-event-b-20260822-03", + "head_accepted_at": "2026-08-22T22:09:37+00:00", + "first_break": null, + "attestation_match": null + }, + "image": "forgejo.coulomb.social/coulomb/audit-core@sha256:c2fe39a0185b99be3fc0cb14d2de69772b8e66e20490097c9d11d90cc39719a6", + "generation": 15, + "deployment_uid": "b85fe3d0-75c9-4e0d-8c34-c6f1df0881bb" + }, + "native_after": { + "ready": { + "status": "ok", + "custody_class": "operational", + "durable": true, + "tamper_evidence": false, + "recoverable_days": 30, + "recoverable_source": "resource-control/data/capability/platform-audit-storage.json#provisions[capability=data.backup]", + "recoverable_basis": "measured" + }, + "chain": { + "intact": true, + "events": 32, + "head": "9fc0b4f25c562cec037a5077f00ee63380db8b5c4e85b6016fc40b301431e4fd", + "head_event_id": "whitehat-e2-event-b-20260822-03", + "head_accepted_at": "2026-08-22T22:09:37+00:00", + "first_break": null, + "attestation_match": null + } + }, + "release_container": { + "image": "forgejo.coulomb.social/coulomb/audit-core:cb23dc82fd5dbadfdfb84e99581068bd0aa667c0", + "native_credentials_used": false, + "checks": { + "operational_ready": true, + "nonroot_readonly": true, + "approval-engine": { + "accepted": 202, + "duplicate": 200, + "wrong_source": 400, + "wrong_tenant": 400, + "read_routes_denied": 7, + "independent_read": 200, + "redacted": true, + "stored_once": true + }, + "informed-decision": { + "accepted": 202, + "duplicate": 200, + "wrong_source": 400, + "wrong_tenant": 400, + "read_routes_denied": 7, + "independent_read": 200, + "redacted": true, + "stored_once": true + }, + "sigterm": { + "exit_code": 0, + "inflight_committed_once": true, + "restart_retry_duplicate": true, + "chain_intact": true + } + }, + "started_at": "2026-09-11T04:47:21.436615+00:00", + "status": "passed", + "own_fixture_cleanup": true + }, + "approvals": [ + { + "ccr": "CCR-2026-0021", + "decision_id": "2c9fe9f0-034a-41d7-9d49-b99df488fdc8", + "status": "resolved", + "decided_by": "user (platform-operator, audit-core-owner, approval-engine-owner)", + "decided_at": "2026-09-11T04:36:46.312720Z" + }, + { + "ccr": "CCR-2026-0022", + "decision_id": "ee4ff001-256a-4406-9cb8-51be2cd5d31b", + "status": "resolved", + "decided_by": "user (platform-operator, audit-core-owner, informed-decision-owner)", + "decided_at": "2026-09-11T04:36:46.480026Z" + } + ], + "approval_engine_namespace": "created from owner manifest; no workload deployed", + "sender_ingress": "two exact source-declared namespace AND workload-label peers applied", + "sender_custody": { + "status": "attended_login_failed_before_command_handoff", + "credential_command_started": false, + "custody_receipt_exists": false, + "remote_session_revocation": "not_confirmed_by_warden", + "operator_browser_feedback": "requested" + }, + "receiver_tests": { + "passed": 229, + "migration_exclusion": "AUDIT-IN-0004: five existing PostgreSQL failures in historical SQLite importer" + }, + "platform_tests": { + "passed": 18 + }, + "schema_migration_executed": false, + "attestation_residual": "AUDIT-WP-0009-T12", + "factory_attempts": 0, + "paid_model_calls": 0, + "release_scan": { + "vulnerabilities": 0, + "sha256": "f2e6be3514040766bd29a4f8a5265989e8fab6802c935b86bad19aa3ae6c4824", + "scanner": "aquasec/trivy@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969", + "warning": "Alpine 3.24 not in scanner OS lifecycle list" + }, + "receiver_selector": "app.kubernetes.io/name=audit-core,app.kubernetes.io/component=receiver" +} diff --git a/scripts/factory_audit_custody.py b/scripts/factory_audit_custody.py index c7faa68..93de9f2 100644 --- a/scripts/factory_audit_custody.py +++ b/scripts/factory_audit_custody.py @@ -89,7 +89,7 @@ def receiver_check(kube, expected_image): and dep['status'].get('observedGeneration',0) >= dep['metadata']['generation'], 'receiver_not_ready') containers = dep['spec']['template']['spec']['containers'] require(len(containers) == 1 and containers[0]['image'] == expected_image, 'receiver_image_mismatch') - pods = data(command(kube + ['-n','audit-core','get','pods','-l','app.kubernetes.io/name=audit-core','-o','json']))['items'] + pods = data(command(kube + ['-n','audit-core','get','pods','-l','app.kubernetes.io/name=audit-core,app.kubernetes.io/component=receiver','-o','json']))['items'] require(len(pods) == 1 and not pods[0]['metadata'].get('deletionTimestamp'), 'receiver_rollout_in_progress') pod = pods[0] require(pod['spec']['containers'][0]['image'] == expected_image diff --git a/tests/test_factory_audit_custody.py b/tests/test_factory_audit_custody.py index 85c975a..ccdb7cb 100644 --- a/tests/test_factory_audit_custody.py +++ b/tests/test_factory_audit_custody.py @@ -77,6 +77,25 @@ class Contracts(unittest.TestCase): lane.receiver_check(['kubectl'],dep['spec']['template']['spec']['containers'][0]['image']) + def test_completed_attestation_pods_do_not_block_the_receiver(self): + image='forgejo.coulomb.social/coulomb/audit-core@sha256:'+'a'*64 + dep={'metadata':{'uid':'d','generation':1,'resourceVersion':'1'},'spec':{'replicas':1,'template':{'spec':{'containers':[{'name':'audit-core','image':image}]}}},'status':{'observedGeneration':1,'readyReplicas':1}} + receiver={'metadata':{'name':'receiver','uid':'p','labels':{'app.kubernetes.io/name':'audit-core','app.kubernetes.io/component':'receiver'}},'spec':dep['spec']['template']['spec'],'status':{'containerStatuses':[{'ready':True}]}} + attest={'metadata':{'name':'attestation-completed','labels':{'app.kubernetes.io/name':'audit-core','app.kubernetes.io/component':'attest'}},'status':{'phase':'Succeeded'}} + def kube(argv): + if 'deployment' in argv: result=dep + elif 'pods' in argv: + selector=argv[argv.index('-l')+1] + terms=[pair.split('=',1) for pair in selector.split(',')] + result={'items':[p for p in [receiver,attest] if all(p['metadata']['labels'].get(k)==v for k,v in terms)]} + else: + self.assertIn('receiver',argv) + result={k:True for k in ['load_bearing','redact','write_only','source_exact','tenant_exact']} + return subprocess.CompletedProcess(argv,0,json.dumps(result).encode(),b'') + with patch.object(lane,'assert_cluster'),patch.object(lane,'command',side_effect=kube),patch.object(lane,'bao',side_effect=AssertionError('no credentials')): + self.assertEqual(lane.receiver_check(['kubectl'],image)['pod_uid'],'p') + + class OpenBaoExercise(unittest.TestCase): @classmethod def setUpClass(cls): diff --git a/workplans/RPF-WP-0035-credential-lane-implementation.md b/workplans/RPF-WP-0035-credential-lane-implementation.md index 2b2f5c3..4959a39 100644 --- a/workplans/RPF-WP-0035-credential-lane-implementation.md +++ b/workplans/RPF-WP-0035-credential-lane-implementation.md @@ -397,11 +397,11 @@ into this client-identity grant. ```task id: RPF-WP-0035-T08 -status: progress +status: wait priority: high assignee: railiance-platform needs_human: true -intervention_note: "CCR-2026-0021/0022 need named platform-operator, audit-core-owner and producer-owner reviews. Receiver upgrade and namespace readiness remain separate preconditions; approval alone does not admit factory execution." +intervention_note: "All named CCR-2026-0021/0022 reviews are approved. Compatible receiver and namespaces are ready. Attended OIDC failed before owner-command handoff; Warden could not confirm remote session revocation. Await operator browser/MFA feedback and login/session resolution before custody retry. Do not repeat sender approval." state_hub_task_id: "0ef52c26-2669-5cd1-8149-b1f6fcdda6cb" ``` @@ -481,3 +481,20 @@ platform-operator, audit-core-owner and both producer owners. Both exact request are approved; their existing State Hub decisions are resolved. This clears the review request only. Receiver rollout, namespace readiness, attended custody and positive/negative native evidence remain the execution gates. + +### Native receiver and attended execution return — 2026-09-11 + +Audit Core c82e0442de0f is deployed and passes the native synthetic contract. +Its existing 32-event chain/head is unchanged. The owner Approval Engine +namespace now exists and all four ESO objects pass strict server dry-run. +The two exact ingress rules are applied; sender custody/ESO application is not. + +Warden selected founder_required/oidc_login and attempted the reviewed silent +seed command through the contained wrapper. Login failed before command +handoff; no custody receipt was created. Warden could not confirm remote +session revocation. Await operator browser/MFA feedback and login/session +resolution. Approvals remain valid; T08 waits for the identity act, not review. + +The receiver check now selects component=receiver, so retained attestation-job +pods cannot falsely block a stable receiver. Eighteen custody tests pass. +[Native return](../docs/evidence/2026-09-11-factory-receiver-live.json).