diff --git a/docs/pdp-access-path.md b/docs/pdp-access-path.md index 88eac9d..0cc31d4 100644 --- a/docs/pdp-access-path.md +++ b/docs/pdp-access-path.md @@ -23,20 +23,20 @@ $ getent hosts this-service-does-not-exist.flex-auth.svc.cluster.local `*.svc.cluster.local` name answers with one unrelated public address. Sending there ships the CheckRequest body and our bearer token to a third party. -`flex-auth.decision-record.v1` supports a detached Ed25519 signature on the -producer side (FLEX-WP-0024), but this consumer does not yet verify it against -independently admitted keys. Without that verification, every binding digest -is either sent by us or published in flex-auth's repo, so a forger can -reproduce those digests. Digests establish integrity of the binding, never -authenticity of the source. As flex-auth put it in `FLEX-DEC-2026-010`: +As of source `ff1a13d` (2026-10-16), this consumer requires the producer's +detached Ed25519 signature using independently admitted local keys and exact +signed evaluator/mode/policy pin. The complete CLI wheel-plus-helper bundle and +strict task handoff are implemented in source. Native signer custody, key/pin +admission, installed placement and actual consumer receipts remain unaccepted; +source enforcement does not establish those facts. See +[the scoped native preparation](proposals/native-cli-admission/README.md). -> Fail-closed protects against a PDP that is ABSENT, not against one that LIES. - -The literal loopback address restriction limits the destination; it does not -prove responder identity. The operator must verify the cluster and named pod -behind the port-forward. Signed consumer enforcement, independently admitted -verification keys, rotation and downgrade tests remain open in SECRETS-WP-0014 -and Custodian G13. Producer support alone does not close that gap. +Historical 2026-10-12 finding: prior consumer source did not verify producer +signatures, so a forger could reproduce public request digests. The literal +loopback address restriction limited the destination and did not prove responder +identity. That source defect is repaired; FLEX-DEC-2026-010's historical warning that an absent +PDP and a lying responder require different controls remains relevant. The +independently admitted native trust and rollout obligations in SECRETS-WP-0014 T02/T03 remain open. The Check client disables automatic redirects, environment/system proxies and the process-global urllib opener. A 3xx response fails closed without contacting @@ -51,9 +51,12 @@ apply when the approval flow invokes the PDP client. Regression tests use disposable local HTTP servers and synthetic credentials; they do not demonstrate identity or signature verification on the native pin. -## The supported path +## Historical transport procedure and current admission gate -Use literal loopback `kubectl port-forward` to the admitted named pod after +The following transport example records the earlier supported access shape; it +is incomplete for current native use without independently admitted signing trust, +the reviewed CLI bundle and exact owner configuration. It grants no token mint, +installation or live action. Use literal loopback `kubectl port-forward` to the admitted named pod after verifying the cluster identity and pod identity. That path rides the Kubernetes API server's TLS with the operator's cluster credentials; the client cannot infer that binding from its local URL. Note this @@ -92,8 +95,10 @@ false` and no role bindings — it exists to be a caller identity and nothing el v1 shipped and was deployed with no `input.tenant` rule at all; a `rotate` under `tenant:coulomb` returned **allow**. v2 supersedes rather than amends it so the -change is visible in the version string, and this engine refuses a v1 decision -outright. See `docs/tenant-alignment.md`. +change is visible in the version string. Current consumer configuration and signed +trust must explicitly pin the admitted v2 artifact; the validator does not impose +a universal hard-coded package/version default. A v1 configuration is not admitted +by this proposal. See `docs/tenant-alignment.md`. ## The digest join, and why it is not a digest comparison @@ -114,19 +119,18 @@ and the fix follows it rather than inventing one: > statement of what it hashed. To recompute independently, hash the same > normalized tuple the binding carries. -`validate_decision_envelope` now does exactly that: +The bullets in earlier revisions described the September structured-enrichment +check. Current source has since moved to the producer's submitted-request replay +contract: `validate_decision_envelope` validates the exact submitted digest, +opaque enriched digest shape, approval-free correspondence, policy pin and +lifetime on an authenticated envelope. It does not independently reconstruct the +full enriched tuple or native five-field claim in the generic CLI path. -- **Structured correspondence.** Everything we proposed — tenant, action, - context, `subject.id`/`type`, `resource.id`/`type`/`system` and every - attribute we sent — must survive unchanged in the binding. -- **Enrichment only where the contract permits it.** A ref may gain `type`, - `tenant` and `attributes`; any other added field is refused. An enriched - `tenant` must be the request's tenant, so a cross-tenant binding cannot arrive - wearing our request's clothes. -- **Digest self-consistency.** `request_digest` is recomputed over the - normalized tuple the binding carries, per the contract's own instruction. It - is still checked — just for coherence of the binding rather than against - material we never sent. +The separate strict `task_execution_handoff` additionally recomputes the evaluated +and approval-free digests, verifies exact descriptor/context/native claim joins +(including the served native digest), and binds signed enforced caller provenance. +That source seam is not an `execute-ccr` CLI command and does not admit the proposed +service caller mapping or enable either task policy's runtime false gate. The lesson worth keeping: the replay fixtures could not catch this, because `_request_from()` rebuilds the request from the binding, so the tests hashed the diff --git a/docs/proposals/native-cli-admission/README.md b/docs/proposals/native-cli-admission/README.md new file mode 100644 index 0000000..3729cf6 --- /dev/null +++ b/docs/proposals/native-cli-admission/README.md @@ -0,0 +1,158 @@ +# Native CLI signer and consumer admission preparation + +This proposal covers the existing lifecycle CLI authentication path under +SECRETS-WP-0014. It grants no installation, key retrieval, caller mint, approval +consume, OpenBao effect or task-policy activation. All native acceptance counts +below are zero. Exact missing owner inputs are in `proposal.json`. + +## Current consumer and initial scope + +At source `ff1a13d`, the workstation has the repository's editable v0.1.0 CLI +entrypoint at `/home/worsch/secrets-engine/.venv/bin/secrets-engine`, importing +`secrets_engine.cli:main`. There is no global `~/.local/bin/secrets-engine` or uv +managed Secrets tool. Presence-only inspection of this session found none of the +PDP/trust/approval/policy/configuration variables set. This says nothing about +other sessions, private owner configuration or a remote installation. No credential +file, private configuration or process environment was inspected. + +Use a separately reviewed immutable wheel-plus-verifier bundle for proposed +adoption. The canonical source for the candidate build is **ff1a13d**, containing +both CLI packaging and strict R2 handoff; earlier c80-based proof bundles are +intermediate source evidence. Custodian `decision-native-preparation/` retains the +exact canonical bundle manifest and hashes. Nothing was installed by this step. + +Initial stage is signer-only existing lifecycle-pin admission plus offline +verification of captured native signed allow and deny records. Capturing those +records later needs its own admitted caller and exact source operation; this +proposal does not grant that capture. Use Access's one receipt verifier, +`tools/verify_native_signer_receipt.py`, with its reviewed admission file rather +than creating another consumer verifier or canonicalization implementation. +That tool is separate Access source preparation; its exact integrated revision +and reviewed admission file remain owner inputs, not part of this CLI install. + +The producer-owned offline pin is `secrets-engine.catalog-lane.lifecycle` v2, +`sha256:bd11c5fe77ce6439c65fea225ad6b71d2110efc5e7b5bc9b499c59cd0a53b8b4`, +evaluator `flex-auth/local`, mode `standalone`. A source digest is not proof of the +live image's source or policy. Access's live metadata records the current pin has +no signer arguments/mounts; no production kid/public key/fingerprint/custody +receipt or candidate signed-runtime OCI digest is admitted. The proposed signer +custody route is draft/nonresolvable. Do not fill those gaps from fixture keys or +from the same responder's keys endpoint. The independent receipt must bind signer +purpose/custody to this exact consumer pin and declare any sharing. A shared key +plus the generic evaluator name cannot prove an individual pod's identity; the +owner-bound tunnel and rollout identity still require separate verification. + +`lifecycle-trust.template.json` uses the existing runtime trust schema and the +producer-owned source pin, but deliberately has an empty key map. It **must +refuse** before caller credential access. It is not a deployable trust file. A +future owner-admitted copy must contain the independently authenticated actual +kid/key and exact pin, with its public-key fingerprint/custody provenance retained +outside this unadmitted template. The task-policy coordinate is not admitted here. + +## Exact PEP denominator + +The initial shared authentication implementation is one Check client reached +through `authorize_action` and `_require_lane_approval`. Native protected-effect +coverage remains **0 of 11 serving CLI call sites across 10 handlers**, not one +PEP per catalog row. The current lifecycle policy's action vocabulary has twelve +values; that is a separate count from handler/call-site coverage. + +| CLI path | Handler / delegated authorization site | PDP action | +| --- | --- | --- | +| apply, live only | `cmd_apply` | apply | +| provision | `cmd_provision` | provision | +| rotate, live only | `cmd_rotate` | rotate | +| verify | `cmd_verify` | verify | +| handoff | `cmd_handoff` | handoff | +| wrap | `cmd_wrap` | wrap | +| exec primary | `cmd_exec`, primary gate | exec | +| exec companion | `cmd_exec`, delegated companion gate | exec for each companion; separate claim/CAS, same call site | +| revoke, live only | `cmd_revoke` | deactivate | +| lifecycle compromise/reactivate, live only | `_cmd_lifecycle_state` | selected compromise/reactivate; local state mutation | +| lifecycle suspend/deactivate/destroy, live only | `cmd_lifecycle` | selected operation | + +`session revoke` is a separate stance/readiness-controlled backend path without +this served Check/CAS chain; it is excluded from this signer acceptance and still +refuses production under its stance. `service-auth probe-openbao` is an explicit +identity/login-self probe, not protected task adoption. `route` performs existing +backend readiness metadata probes through its ambient backend resolver; it is not +closed by this signer proposal. Dry-run/plan/catalog/audit/source evidence commands +are not protected-effect proof. These exclusions must remain visible in any claim +about the whole repository's PEP coverage. + +The existing CLI handlers still use the generic `require_production_consume` +response contract. Strict R2 task consumption is a separate owner API, not a +retrofit of all eleven CLI sites. Native effect acceptance must review the actual +selected handler/consume contract and caller scope rather than borrow the task +fixture proof. + +No production effect is authorized merely because a handler shares the signed +client. In particular, configured `service-jwt` still refuses protected CLI work +before approval/CAS/backend because CCR38 is identity-only. Do not select +bootstrap/env, alter the stance or enable unsafe-demo to manufacture acceptance. + +## Owner-controlled placement and minimum configuration + +The deploying owner must select the runtime UID, fresh release prefix, configuration +parent and exact runtime paths; none is agreed by this proposal. The future +admitted executable is `/bin/secrets-engine`, whose wrapper fixes the +bundle helper and checks its digest before CLI import. The helper's source/binary +hash is artifact integrity, not independent package or key admission. Do not use +the editable checkout, a rolling alias, a synthetic test prefix or an internal +venv entrypoint as if it were that admission. + +Explicit absolute owner-admitted catalog, policy, `SECRETS_ENGINE_PEP_STANCE`, +trust and evidence/outbox locations are needed. Installed-package defaults fall +back to working-directory metadata and are not an admitted native configuration. +The total existing stance remains prod fail_closed. Config needs the exact +producer policy/version, service subject, loopback owner-bound PDP tunnel and +separately admitted bounded audience `flex-auth` caller-file lifetime. Approval +endpoint and its existing separately scoped credential delivery must be admitted +independently. Both approval credential providers may not be configured together. +The bundle helper is not selected by an ambient override. Runtime credentials and +keys are not placed in this proposal or release bundle. + +Acceptance order is: admit exact package/source/install/config; obtain independent +signer/key/pin custody return and exact signed producer rollout candidate; under +that separately reviewed rollout capture bounded native records; run Access's +single offline receipt verifier against the fixed installed helper and admitted +trust; prove forged/altered/unknown/unsigned/wrong-pin/expired refusal and exact +old/new-key overlap then removed-key refusal. Also close the producer's missing +native durable log/outbox/audit path under its owner. No install or rollout is +performed here, and shared-source tests do not fill native effect coverage. + +Rollback retains the reviewed signed producer and admitted overlap or stops the +consumer. Rolling back to an unsigned image is an outage, not permission to turn +off verification. Removing keys, changing policy pins or restoring removed keys +needs exact owner review; no discovery/cached-key fallback or blind consume retry. + +## Separate task-execution gap + +Strict `task_execution_handoff` exists and Platform's independently confirmed +journal/native fixture path has actual source-server proof. Neither creates an +existing `execute-ccr` CLI command: the current parser has none. Proposed task +caller mapping/request join, policy admission, production source/Plan/grant and +installation/journal/cleanup placement remain separate owner decisions. Both +Access task-policy runtime false gates remain unchanged; lifecycle apply is not +a substitute for execute-ccr. Platform has selected no fresh approved real +CCR/catalogue/descriptor/grant. CCR42 is in_flight and lacks a matching Secrets +catalog; synthetic CCR2/issue-core fixture bytes and temporary paths are not native +inputs. Actual before/after bytes for the exact metadata targets and independent +readback/cleanup receipts must come from Platform's eventual owner-selected plan. + +For future server-owned Approval facts, strict R2 deliberately requires the +returned binding context to equal the originally submitted context. B1 caller +join remains signed-DENY and must preserve that context. Replacing the carried +claim with a freshly observed blob would refuse because its freshness fields +change; no generic equality relaxation is proposed. Access's current review +preference is to validate fresh authoritative facts out of band while retaining +the submitted context, with reviewed producer-owned signed source/receipt evidence. +Exact stable fact/freshness and provenance correspondence requires Approval and +Access review before B2/B3; no new fields or behavior are implemented here. + +The Approval owner's pending `approval-fact-contract/consumer-contract.md` and +`golden-vectors.json` in the Custodian target evidence name this correspondence. +They require both original/fresh windows and exact nonfreshness authority facts. +Their Python native numeric canonical vectors still need producer conformance; +no silent digest translation or new target numeric restriction is admitted. +The proposal pins those owner artifacts for review, not as B2 implementation. diff --git a/docs/proposals/native-cli-admission/lifecycle-trust.template.json b/docs/proposals/native-cli-admission/lifecycle-trust.template.json new file mode 100644 index 0000000..22fc99a --- /dev/null +++ b/docs/proposals/native-cli-admission/lifecycle-trust.template.json @@ -0,0 +1,9 @@ +{ + "schema": "secrets-engine.pdp-trust.v1", + "evaluator": "flex-auth/local", + "mode": "standalone", + "policy_package": "secrets-engine.catalog-lane.lifecycle", + "policy_version": "v2", + "policy_package_digest": "sha256:bd11c5fe77ce6439c65fea225ad6b71d2110efc5e7b5bc9b499c59cd0a53b8b4", + "keys": {} +} diff --git a/docs/proposals/native-cli-admission/proposal.json b/docs/proposals/native-cli-admission/proposal.json new file mode 100644 index 0000000..d5c50c2 --- /dev/null +++ b/docs/proposals/native-cli-admission/proposal.json @@ -0,0 +1,133 @@ +{ + "proposal_id": "SECRETS-WP-0014-native-cli-20261016", + "status": "preparation only; not installable or executable authorization", + "source_base": "ff1a13dabd44ba02ddd6bc26ad75568f6d2e6225", + "workplans": [ + "SECRETS-WP-0014-T02", + "SECRETS-WP-0014-T03", + "SECRETS-WP-0013-T01", + "SECRETS-WP-0013-T03" + ], + "initial_scope": { + "producer": "existing flex-auth/flex-auth-secrets-engine lifecycle pin", + "consumer": "existing Secrets CLI serving authorization workflow, prospective reviewed release-bundle entrypoint only", + "stage1": "independent signer/package/trust admission and offline captured native allow+deny verification; zero protected effects", + "native_effects_admitted": 0, + "task_execution_enabled": false + }, + "owner_returns": { + "access": "Custodian docs/changes/netkingdom-target-2026-10-16/access-native-preparation/native-admission-proposal-r1.json and source-policy-pins.json", + "platform": "No selected actual approved CCR/catalog/Plan/descriptor/grant/install placement; CCR-2026-0042 remains in_flight without matching catalog. Disposable source proofs are not production inputs." + }, + "producer_pin": { + "evaluator": "flex-auth/local", + "mode": "standalone", + "policy_package": "secrets-engine.catalog-lane.lifecycle", + "policy_version": "v2", + "policy_package_digest": "sha256:bd11c5fe77ce6439c65fea225ad6b71d2110efc5e7b5bc9b499c59cd0a53b8b4" + }, + "independent_admission": { + "production_kid": null, + "public_key": null, + "public_key_sha256": null, + "custody_receipt": null, + "candidate_producer_oci_digest": null, + "rule": "No responder keys endpoint, synthetic fixture key or deployment metadata substitutes for independent owner admission", + "receipt_verifier_integrated_revision": null, + "signer_purpose_pin_and_sharing_receipt": null + }, + "placement": { + "owner": "Secrets consumer/deploying owner; exact runtime UID and paths not yet agreed", + "cli_release_prefix": null, + "cli_entrypoint": "/bin/secrets-engine", + "fixed_verifier": "/libexec/secrets-engine-pdp-verify", + "config_parent": null, + "trust_file": null, + "catalog_directory": null, + "policy_directory": null, + "pep_stance_file": null, + "evidence_directory": null, + "constraints": [ + "new owner-controlled immutable release prefix; no overwrite or rolling source alias", + "absolute independently reviewed config/catalog/policy/stance/trust paths; no working-directory defaults for native use", + "trust regular non-symlink, not group/world writable; key admission not file-presence inference", + "owner retains manifest/admission/installation receipts and same-UID control boundary" + ] + }, + "configuration_contract": { + "SECRETS_ENGINE_PDP_URL": "literal loopback bare origin bound to independently verified cluster and named producer pod; exact native port awaiting owner placement", + "SECRETS_ENGINE_PDP_TOKEN_FILE": "admitted bounded Secrets ServiceAccount caller file outside Git; no mint/read here", + "SECRETS_ENGINE_PDP_TRUST_FILE": "absolute independently admitted lifecycle trust path; empty-key template deliberately refuses", + "SECRETS_ENGINE_PDP_VERIFIER": "bundle wrapper fixes installed helper; no ambient override or source-checkout helper", + "SECRETS_ENGINE_AUTHORIZATION_SUBJECT_ID": "secrets-engine", + "SECRETS_ENGINE_AUTHORIZATION_SUBJECT_TYPE": "service", + "SECRETS_ENGINE_AUTHORIZATION_POLICY_PACKAGE": "secrets-engine.catalog-lane.lifecycle", + "SECRETS_ENGINE_AUTHORIZATION_POLICY_VERSION": "v2", + "SECRETS_ENGINE_APPROVAL_URL": "independently admitted Approval endpoint/owner-bound tunnel; not yet supplied for this session", + "SECRETS_ENGINE_APPROVAL_CLIENT_SECRET_FILE": "separately admitted attended provider lifetime from existing custody contract; no read here", + "SECRETS_ENGINE_APPROVAL_TOKEN_FILE": "unset when client-secret provider selected; no simultaneous providers", + "SECRETS_ENGINE_CATALOG": "absolute owner-admitted metadata directory; initial actual lane unselected", + "SECRETS_ENGINE_POLICIES": "absolute owner-admitted metadata/policy directory", + "SECRETS_ENGINE_PEP_STANCE": "absolute hash-pinned existing total stance map; prod remains fail_closed", + "SECRETS_ENGINE_EVIDENCE": "absolute owner-private evidence/outbox path with declared custody/delivery", + "SECRETS_ENGINE_UNSAFE_DEMO": "unset; no native exception", + "backend_provider": "no new selection/entitlement; configured service-jwt protected handlers remain blocked; do not switch to bootstrap/env as workaround" + }, + "rotation": { + "admit": "owner reviews independent new kid/public key/custody receipt and bounded overlap, preserving exact issuer/policy artifact pin", + "roll": "separate exact producer candidate digest/seed projection rollout with native signed receipts; never fetch discovery keys", + "remove": "after new-key native receipt/consumer acceptance, remove old kid and prove old-key refusal", + "rollback": "retain reviewed signed producer/key overlap or stop/refuse. An unsigned old deployment is an outage; never disable consumer verification, restore removed key without review, relax pin, widen backend grants or blind retry consumed operation" + }, + "task_mapping_gap": { + "existing_cli_execute_ccr_command": false, + "source_handoff": "secrets_engine.task_execution_handoff authorize_task_execution/consume_task_execution", + "platform_source_mediator": "railiance-platform/scripts/task_execution_mediator.py run_native_fixture_task; source proof only", + "unadmitted_inputs": [ + "real service caller-to-subject server mapping and request/service binding join", + "actual task policy candidate and independently reviewed source/runtime admission; both false gates unchanged", + "owner-selected fresh approved CCR/catalog/execution-grant, compiled Plan/whole descriptor and operation UUID", + "independent expected-before/after bytes for exact two metadata targets and actual estate/backend origin", + "actual source/Plan/install/journal/cleanup placement and trusted provider endpoints/credentials/custody", + "load-bearing audit/outbox cadence and durable receipt correlation", + "Approval/Access reviewed out-of-band fresh-fact versus original carried-claim correspondence and signed provenance; strict context equality remains unchanged" + ], + "approval_fact_interface_review": { + "status": "review preference only; no implementation/admission", + "preserve": "strict binding.context equality and original submitted/approval-free/native joins", + "direction": "Access prefers out-of-band server-fetched authoritative fact checking while retaining original carried context, then reviewed producer-owned signed provenance/audit evidence", + "required_review": [ + "Approval fact/freshness semantic correspondence", + "Access source receipt/provenance binding and exact request digests" + ], + "b1": "signed-DENY caller join only; no context replacement", + "b2_b3": "not enabled or implemented here" + }, + "approval_fact_contract": { + "artifact": "the-custodian/docs/changes/netkingdom-target-2026-10-16/approval-fact-contract/consumer-contract.md", + "sha256": "3dfb7987a4d9fe461b917cfa5bae7beef61bc4d9a4561fdded3e90128f5966de", + "vectors_artifact": "the-custodian/docs/changes/netkingdom-target-2026-10-16/approval-fact-contract/golden-vectors.json", + "vectors_sha256": "dfb0a8810cd91847d7af6a7af6a51607a67a66fad7b86fc57365308c36bd9323", + "status": "owner source contract pending integration; no Go conformance or B2 behavior admitted", + "required": "preserve original fact/context/freshness, independently validate fresh fact window and exact nonfreshness authority; do not translate native numeric digests or invent target restrictions" + } + }, + "approval_state": "no owner assent, key admission, install, caller token, operation grant or live change requested/executed by this preparation", + "denominator": { + "shared_check_implementation": 1, + "serving_cli_call_sites": 11, + "serving_cli_handlers": 10, + "lifecycle_pdp_action_values": 12, + "native_effect_call_sites_accepted": 0, + "excluded": [ + "session revoke stance-only backend path", + "service-auth explicit identity probes", + "route ambient-backend readiness probes", + "dry-run/non-effect reporting" + ], + "task_cli_command_count": 0, + "platform_source_mediator_native_acceptance": false, + "generic_cli_consume_is_strict_task_handoff": false, + "effect_acceptance_required": "Review actual selected handler/generic consume response and caller scope separately; strict Platform fixture proof does not close existing CLI effects" + } +} diff --git a/src/secrets_engine/cli.py b/src/secrets_engine/cli.py index d60988d..af65388 100644 --- a/src/secrets_engine/cli.py +++ b/src/secrets_engine/cli.py @@ -119,13 +119,12 @@ def _require_lane_approval( ): """Apply published PEP stance, resolve lane approval, then CAS-consume. - Production ``fail_closed`` is read from ``pep-stance.yaml``. The durable - access-engine decision record is not served yet, so that row refuses live - production work. If that residue is ever bypassed, GH-DEC-2026-003 still - requires a successful approval-engine consume before any OpenBao call. - The three-factor unsafe-demo exception is not a stance row and is not a - consume path. Build/test ``fail_open`` still requires the existing - lane-approval check — a tracked gap until SECRETS-WP-0008-T02. + Production ``fail_closed`` is read from ``pep-stance.yaml``. A configured + serving path requires a fresh approval claim and independently authenticated + signed PDP envelope, then successful CAS before the backend. Missing runtime + trust/configuration still refuses production; source support is not native + admission. Build/test engine-unreachable residue retains the explicit legacy + lane check. The three-factor unsafe-demo exception grants no native adoption. """ # Steps 1 and 2 first: a validated claim and decision are what make the # unreachable-engine residue inapplicable. Absent configuration returns diff --git a/workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md b/workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md index 886a0f6..28102cf 100644 --- a/workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md +++ b/workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md @@ -102,3 +102,15 @@ admitted signer, reject forgery/downgrade, rotate without accepting removed keys and preserve request/approval binding, lifetime and single-use consumption. Retain rollback and failure evidence. Update CUST-WP-0080 G13 only with these native receipts; do not equate passing transport tests with closure. + + +2026-10-16 native preparation (no rollout): `docs/proposals/native-cli-admission/` +now scopes the existing CLI/lifecycle signer stage, exact delegated PEP denominator, +independent key/policy admission, owner-controlled bundle/config placement and +rotation/rollback refusal. Canonical ff1a13d (packaging plus strict handoff) was +rebuilt in an isolated clean checkout; artifact receipts are in Custodian +`decision-native-preparation/`. Production kid/public fingerprint/custody receipt, +producer candidate OCI and actual runtime/config placement remain missing. The +empty-key trust template deliberately refuses. No install, key read, caller mint, +protected effect, policy switch or trust admission occurred. T02 remains progress, +T03 wait; task source/live obligations remain separately in SECRETS-WP-0013.