Require declared human control in factory credential delivery
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-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-10 20:16:55 +02:00
parent d1c13b5dd6
commit 2b0d04e8e1
11 changed files with 451 additions and 27 deletions

View file

@ -86,9 +86,50 @@ authority is approval-engine (checked as `issuer`); the decision's is flex-auth.
Every live privileged production handler passes `_require_lane_approval`,
which calls `require_production_consume` before `OpenBaoClient.resolve`.
Dry-run and `plan` do not consume. Build/test remain fail-open relative to
approval-engine. The three-factor unsafe-demo exception is not a consume
path.
Dry-run and `plan` do not consume. For undeclared lanes, build/test and the
three-factor unsafe-demo exception retain their existing behavior. An explicitly
declared human control requires observation, PDP ALLOW and CAS consumption at
every stage; no demo or lane-review fallback discharges it.
## Declared human-control workflow
The factory lane explicitly declares `approval.human_control: true`. This
implements its existing human action-review requirement and GH-DEC-2026-016;
it does not infer human control from a CCR model, stage, actor, or approver entry,
and does not make a local authorization decision. Other catalog entries default
to undeclared. The catalog value must be a boolean, and `bootstrap-only` cannot
be combined with a declared human control.
The generated CheckRequest includes `context.human_control: true`. This changes
its evaluator-bound identity. The separate request-creation caller must issue an
unapproved Approval Engine object with **top-level `human_control: true`** and
`pdp_path: true`, using the actual evaluator-origin digest of that exact claim-free
request. A human subsequently supplies `/entries` through the admitted approver
surface. Do not copy an old request digest or retrofit an existing approval.
Approval Engine retains its unchanged five-field native act digest; the consumer
joins through the distinct evaluator-origin PDP digest as before.
At observation, this engine requires **`claim.binding.human_control is true`**
in addition to current validity, freshness and the PDP path. Missing, false,
string or numeric declarations refuse before the PDP call. The declaration is
checked again after PDP validation and carried in the internal consume binding
and non-secret `approval_human_control` evidence. A declared lane cannot skip
consumption through a build/test or unsafe-demo fallback. The consumer does not
reconstruct approver identities or counts: Approval Engine owns that evidence.
The repeatable `tools/exercise_approval_identity.py --exec-owner --human-control`
exercise creates a declared request through the actual engine API, proves a real
KeyCape service JWT cannot bind it, proves an undeclared claim cannot reach the
PDP/consume/backend path, and proves the real evaluator preserves the requirement.
The positive human entry is **seeded in the disposable store**, while requester,
claim and consume use real local service authentication. The backend and child
payload are synthetic; this is not human JWT/PKCE or live custody evidence.
See [the component receipt](evidence/2026-09-10-human-control-consumer-exercise.json).
Native narrow requester identity, browser human approval, admitted custody and
current deployed services remain APPROVAL-WP-0002-T01/T03/T05,
INFD-WP-0001-T07/T08 and SECRETS-WP-0009-T03. The factory catalog's exec owner
remains pending; adding this requirement grants no runtime or credential access.
## Fail closed
@ -110,8 +151,9 @@ digest, idempotence, and consumed-at only. No token, secret, or accessor.
## Required configuration
The join is absent by default, so an unconfigured engine behaves exactly as it
did before. Production additionally needs:
The join is absent by default. Undeclared lanes retain their existing behavior;
a lane declaring `approval.human_control: true` refuses an absent join.
Production and declared human-control paths need:
| Variable | Meaning |
| --- | --- |

View file

@ -127,3 +127,16 @@ Before accepting an existing production lane:
lanes. Set `false` when the consumer needs only the KV data GET; generated
policy omits the metadata endpoint. Owner metadata verification then needs
separate operator authority, not broader consumer access.
## Explicit human-control requirement
`approval.human_control` is an optional boolean, defaulting to undeclared. Set it
to `true` only for a workflow whose existing contract requires human review. It
is not inferred from `approval.model`, stage or principal type. A declared lane
cannot use `bootstrap-only`; its live action requires an Approval Engine claim
explicitly declared human-controlled, current PDP ALLOW and CAS consumption.
Missing services cannot fall back to ordinary lane review or an unsafe demo.
See [the requester and consumer contract](approval-consumption.md#declared-human-control-workflow).
The HelixForge native-delivery catalog declares this requirement and remains
pending owner admission. No OpenBao policy, role, credential or readiness state
is activated by this source declaration.

View file

@ -0,0 +1,80 @@
{
"schema_version": 1,
"target": "disposable local processes; synthetic credentials",
"started_at": "2026-09-10T18:15:35.247006+00:00",
"keycape_image": "forgejo.coulomb.social/coulomb/key-cape@sha256:7ff54c54e63ee172ae9e6e7fd2da96e427352f712343d74626ee6fe0f6f82611",
"approval_engine_commit": "c8f85c6d7691f2319ad462791e6d385515d7e70d",
"flex_auth_commit": "88b354377c8e26b162f1234e673072f1c06dcd89",
"keycape_contract_commit": "f9812ab3b2bfe8f0817185f44071e612264ec3ee",
"consumer_source_sha256": {
"approval_auth.py": "6f3b033e7928e1c527bc19f5a1e01bf243540769a8646bd8cd47268da25637b5",
"approval_consume.py": "4515c74dbe1cea030cdccebf17b27642ad4f67f2aaee4f3a87e4bb2b9cfad295",
"approval_claim.py": "20b728d2d3e14ffc89fa21a137716015875f9a05c6af7ff48d07cf48d89503a9",
"authorization.py": "c2b6679b4235611c4fd39dad8964a522378df42c0658f0a02dcc31f05141d6a0",
"config.py": "2f2f1b60664d89bbb806aed0c768378923062077740e1f96e4c359238eb06955",
"service_auth.py": "653723ef5babce2157771416d93cb15cdbb7caca3c45509c3730520c55e4515c",
"cli.py": "1147d0e60850cfc38ee21e8564f51656d364ddc3cd8d6353a0c2dd6a0b78b8ec",
"catalog.py": "247c29314bcf86b3439d756ed911df62fb43c3c498b18ce5403704986a501b18",
"exec_owner.py": "10c21e7e37dd3d0aad41c4bb15df8f4a69c22d9046105a981a9613a91cd4c145",
"exec_delivery.py": "b142b60d875acf3dea1ba3ae99182a7ed7328d955dee5be2d12c977fc5646e8e",
"routing.py": "9d5050d7494a207394ce8251d8aac574ca0c08e3252639b5f05b373d6e35a076"
},
"limitations": [
"standalone Flex Auth source, not deployed pin",
"local Approval Engine source, not deployed image",
"no live custody or client-side read grant",
"no OpenBao effect or model execution",
"positive human entry seeded in disposable store; no human JWT/PKCE proof"
],
"checks": {
"operator_issued_and_approved_via_verified_jwt": true,
"wrong_action_refused_before_consume": true,
"producer_origin_join_with_carried_claim": true,
"actual_consumer_claim_check_consume": true,
"same_digest_retry_idempotent": true,
"different_digest_refused": true,
"spent_claim_refused": true,
"operator_consume_scope_denied_by_issuer": true,
"wrong_secret_refused": true,
"no_access_token_file_created": true,
"registry_override_accepts_exact_submission": true,
"same_enriched_result_different_submission_refused": true,
"real_dual_control_denial_then_claim_check_consume": true,
"declared_control_refuses_real_keycape_service_bind": true,
"undeclared_control_refused_before_real_pdp_consume_backend": true,
"exec_owner_substitution_refused_before_consume_backend": true,
"exec_owner_changed_environment_replay_refused_by_real_pdp_join": true,
"exec_owner_real_cli_consumes_before_fixture_backend": true,
"exec_owner_actual_child_excludes_parent_credentials": true,
"exec_owner_digest_preserved_by_real_evaluator": true,
"declared_human_intent_preserved_by_real_evaluator": true,
"declared_human_fixture_consumed_before_owner_delivery": true
},
"flex_auth_binary_sha256": "c7a1f35aa2cd7cf2733272923ace7fc4b4e55171db4ef8f3d0d6629183dcf1fa",
"producer_input_sha256": {
"policy_package.md": "657fa9312c9dcabee059ec31c89ee13396fe9aa54d852edc9e6559a74bbc139a",
"registry_snapshot.json": "37fba44ec0e0fd9b1e17a05ad1b7e4f9bb6ec9e0fc0bb3133e8af2ac6f832d7c"
},
"exec_owner_scope": "Synthetic recipient/backend with real KeyCape, Approval Engine, Flex Auth and Secrets Engine CLI; not native custody or human approval proof",
"status": "passed",
"cleanup_complete": true,
"finished_at": "2026-09-10T18:15:47.092615+00:00",
"consumer_base_commit": "d1c13b5dd667bcad453c94564f65bdf5f172ba3b",
"source_suite": {
"passed": 388,
"new_cases": 27,
"first_25_cases_failed_before": 25,
"log_sha256": "e676747dc0f2547e42bf0f3d7f97a3e1a6da4d413428b44afe28d725abd7a4c7"
},
"factory_attempts": 0,
"paid_model_calls": 0,
"native_human_approval_proof": false,
"remaining_records": [
"SECRETS-WP-0009-T03",
"APPROVAL-WP-0002-T01/T03/T05",
"INFD-WP-0001-T07/T08",
"RPF-WP-0035-T06 / CCR-2026-0019",
"HFACT-WP-0001-T01/T03/T04/T05"
],
"command": "python tools/exercise_approval_identity.py --keycape-source PATH --approval-engine-source PATH --flex-auth-source PATH --exec-owner --human-control --receipt NEW_PATH"
}