Bind credential exec to exact owner inputs and approval digest
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-10 09:29:38 +02:00
parent 9eb07fd8fc
commit 42b48aa54f
13 changed files with 626 additions and 7 deletions

View file

@ -0,0 +1,57 @@
{
"schema_version": 1,
"target": "disposable local processes; synthetic credentials",
"started_at": "2026-09-10T07:15:53.047975+00:00",
"keycape_image": "forgejo.coulomb.social/coulomb/key-cape@sha256:7ff54c54e63ee172ae9e6e7fd2da96e427352f712343d74626ee6fe0f6f82611",
"approval_engine_commit": "62233c7c52447a6065055933a9c7cc1cfe3059eb",
"flex_auth_commit": "88b354377c8e26b162f1234e673072f1c06dcd89",
"keycape_contract_commit": "324b5e056dcfd5c6336750cd7a7b7f8c5ca2255f",
"consumer_source_sha256": {
"approval_auth.py": "6f3b033e7928e1c527bc19f5a1e01bf243540769a8646bd8cd47268da25637b5",
"approval_consume.py": "9ccc6997fd4c1c82af8cf3dd440daf7b695d6272bb302eb083b73a2fe3674345",
"approval_claim.py": "54dd469e4e3ac9472c4e21222d5a08f70723a63f01904a35922fcc0a07a41541",
"authorization.py": "0656589832b7218cc1603890e93a3e09513af8b59694f279defa764a1edb30c9",
"config.py": "2f2f1b60664d89bbb806aed0c768378923062077740e1f96e4c359238eb06955",
"service_auth.py": "653723ef5babce2157771416d93cb15cdbb7caca3c45509c3730520c55e4515c",
"cli.py": "1147d0e60850cfc38ee21e8564f51656d364ddc3cd8d6353a0c2dd6a0b78b8ec",
"catalog.py": "7e77c89a2543e3759f1322aca9b9167b904bb30e1aec867c4415dfde4bddd5fa",
"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"
],
"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,
"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
},
"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-10T07:16:09.750288+00:00"
}

View file

@ -0,0 +1,93 @@
# Bind native exec delivery to its reviewed recipient
SECRETS-WP-0009-T03. Implemented 2026-09-10. This constrains delivery; it is not
an approval or proof of native credential access.
Previously `exec` consumed approval for a catalog/action/field, then accepted an
arbitrary child command and copied the invoking engine's full environment. The
factory recipient is now a pinned metered owner outside the sandbox. A different
command or inherited engine credential would violate that boundary.
Catalog `delivery_config.exec_owner` is optional for existing lanes. The Claude
factory lane explicitly requires it and currently declares `status: pending`,
`owner` and `reason`. Pending means no exec: refusal precedes approval consumption,
backend opening and secret retrieval. Routing stays unready even if custody exists.
A reviewed binding uses exactly these keys:
| Key | Required content |
| --- | --- |
| `status` | `configured`; this describes configuration, not authorization |
| `owner` | Named trusted recipient |
| `command` | Exact argv; absolute executable, no caller-selected additional arguments |
| `cwd` | Exact private owner directory |
| `environment` | Complete non-secret environment; no inheritance from the engine |
| `files` | Absolute path → `{sha256: <64 lowercase hex>, private: <boolean>}` |
The executable and every absolute file argument require pins. Include the exact
owner JSON and all immutable files it references, such as the spend-policy and
accepted profile/descriptor configuration. Mutable ledgers are private state,
not immutable file pins. The runtime owner retains whole-artifact and operational
profile verification; hashing an interpreter alone does not verify its packages.
File checks refuse symlinks, nonregular inputs, untrusted owners, group/world
writable paths and ancestors, changed bytes and exposed private inputs. Root-owned
sticky temporary ancestors are allowed for contained proof. The working directory
is private. The engine and configured owner UID remain trusted: this does not
protect against that same trusted UID replacing files between checks and launch.
Runtime and native service admission must preserve this trust boundary.
Only exec-env is allowed with this binding. The child receives the fixed environment
plus the selected declared field; loader overrides and engine/provider auth
variables cannot be supplied as fixed environment configuration. No values belong
in the catalog. Queue/service credentials, if needed by the owner, require their
separate admitted custody path. Child stdin is closed; stdout/stderr retain the
existing value redactor. An arbitrary encoding by a malicious recipient is not
made safe by redaction; the recipient itself must be trusted and admitted.
SHA-256 of the complete canonical binding is carried as
`context.exec_owner_sha256` on the `exec` CheckRequest. The existing producer digest
and approval join bind it without introducing another decision type. Changing
command, file pins, environment, cwd or owner changes the request and requires new
exact-action approval. Local checks run before approval/backend, again before
retrieval, and after retrieval before launch; the admitted digest must still match.
Configured bindings still pass existing approval, consume, lane-state and scoped
backend checks. Other actions and lanes without this opt-in retain their contracts.
## Factory activation input
Use the installed artifact and paths in
`prj-helixforge-factory/evidence/2026-09-10-runtime-placement.json`. The intended argv:
```text
<protected-runtime>/bin/python3 -I -B -m rein_aharness.cli metered-once --owner-config <private-owner-config>
```
Do not use the rolling CLI alias or a persistent claim loop. Complete and pin the
private owner configuration, profile and spend inputs under HFACT-WP-0001-T01/T04;
bind the required worker environment explicitly. Then review the MessagesOwner
holder under this task and the existing native action/reader gates. The provider
key stays in the metered owner; the workload receives the opaque local route token.
The historical sandbox-helper child-key route is not this holder admission.
## Verification
The full suite passed 361 tests, including a real child with a synthetic key,
fixed environment, closed stdin, redaction and substituted/config-changed refusal.
The disposable integration exercise passed 18 checks using the pinned KeyCape
image, actual Approval Engine and compiled Flex Auth, including five new owner
checks: substituted argv refusal before consume/backend, changed-environment
replay refusal, consume-before-backend, isolated child environment and preserved
recipient digest. OpenBao and recipient are fixtures in this exercise. The
historical combined operator identity is a synthetic test issuer fixture, not a
request to restore CCR-2026-0020 or evidence of real human approval.
```bash
uv run --extra dev --with 'PyJWT[crypto]>=2.7,<3' python tools/exercise_approval_identity.py \
--keycape-source ../key-cape --approval-engine-source ../approval-engine \
--flex-auth-source ../flex-auth --exec-owner --receipt /tmp/<new-receipt>.json
```
Receipt: `docs/evidence/2026-09-10-exec-owner-approval-exercise.json`.
Native custody, exact operator group/file delivery, real human/audit/service path,
accepted factory configuration and paid execution remain open.

View file

@ -5,6 +5,13 @@ railiance-platform CCR-2026-0016; implementation/activation record SECRETS-WP-00
KV custody is already confirmed at version 2. Do not provision or rotate it as
part of native read-lane adoption.
2026-09-10: the factory continuation uses a metered MessagesOwner outside the
sandbox. Its exact runtime is installed and synthetically proved on Railiance.
The catalog now blocks exec with an explicit pending recipient binding until the
native holder and immutable configuration are admitted. See
[exec owner binding](exec-owner-binding.md). The older transport description
below records the original child-key route; it cannot admit the metered holder.
The generated plan checks existing mount `platform`, creates policy and AppRole
`se-prod-glas-claude-agent-dev-anthropic`, and grants read only on
`platform/data/workloads/glas-harness/claude-agent-dev`. Field ANTHROPIC_API_KEY
@ -37,7 +44,7 @@ catalog and service-jwt selection. No real value was requested.
Activation depends on SECRETS-WP-0007-T04 (exact production actions) and
SECRETS-WP-0008-T02/T06 (decision consumption and service authority). Require
canonical ActionAuthorization for each protected action, successful consume,
canonical validated DecisionEnvelope for each protected action, successful consume,
and exact scoped backend authority. This draft cannot authorize itself; an
operator browser token or unsafe-demo flag is not a runtime substitute.