Publish reviewed exact task execution PDP binding contract
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 1m33s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
tegwick 2026-10-11 15:03:03 +02:00
parent f30e08cc96
commit 7ad8dec85e
5 changed files with 286 additions and 1 deletions

View file

@ -0,0 +1,88 @@
# Access owner review: exact task-execution PDP source preparation
reviewer: access-engine-owner (agent access-engine, codex)
decision: approved
work_item: FLEX-WP-ADHOC-2026-10-11-T02
scope: proposed integration direction and bounded source characterization only
anchor_commit: f30e08cc96634d48987fb7203b71961437119535
Comment: Access INTENT.md, Responsibility Boundary / Flex-Auth Owns the Decision
and Protected Systems Own Enforcement, reserves policy evaluation exclusively to
Access and places enforcement/lifecycle/custody downstream. The reviewed design
uses the existing CheckRequest/DecisionEnvelope and served approval interfaces;
Access does not mint OpenBao entitlements or operate a new grant service. The
source contract accurately distinguishes digest binding from policy authority,
transport caller authentication from initiating-principal identity, and source
preparation from actual native lifecycle adoption. I approve that proposed
integration direction and the exact characterization artifacts below, under the
completed own-repo task above persisted before this review. Only Access's owner
role is reviewed here.
## Exact reviewed revisions
| Artifact | SHA256 |
| --- | --- |
| Access candidate docs/task-execution-pdp-consumer-contract.md | 6a08b5cf91cf4507865aeb950cd448da93778772530b45861bf18f09cddf6263 |
| Access candidate pkg/api/execution_contract_test.go | 9e5f0df4b8cdd526747d2cffb31492c6c6fc1ecc68675b505c3ba0f432a5fa25 |
| Access candidate internal/policy/secrets_execution_gap_test.go | 643e7b85b6a0cb9fb85d02b5f2b237d97c9a0c872f315208cf100f82d9936739 |
| Platform docs/credential-lane-designs/secrets-engine-task-execution-entitlement.md | 180b979d18b3f145993575899fac8681fc9865b8c218638bb62b068ba5337bf4 |
| Secrets docs/task-scoped-openbao-execution-contract.md | e4b72d425491530aa9ebc7c9f3cec5f4408a247cba46ae38e94721e69887c5e6 |
Access source behavior tested from baseline
c829e530309d4a885a7dbe34ddc316e0c25d205f in isolated /tmp staging.
`go test ./pkg/api ./internal/policy -run ExecutionContract -count=1` passed.
The candidates have not been applied to the actual checkout or published.
The completed review anchor is not a runtime admission field.
## Exact consumer builder integration required
Implement one keyword-only `execution_contract` argument on
`authorization.build_action_request`, `approval_consume._expected_request`,
`resolve_approval_observation`, and `authorize_action`. The owner compiler returns
one schema-validated, independently source-reconstructed contract. Each function
must pass that same semantic value unchanged; `build_action_request` deep-copies
it into `context.execution_contract` before any claim lookup or Check.
No caller-written arbitrary CheckRequest parameter replaces reconstruction.
The new CLI sends PDP action `execute-ccr`, not `apply`. Reject execute-ccr without
its complete contract; reject attaching this contract to existing apply or any
other legacy action. Force `context.human_control = true` for execute-ccr even
when a legacy catalog does not declare it. Retain the complete existing
`context.catalog_target`, catalog purpose, resource targets and stage. Production
owner boundary supplies verified identity; environment/cfg subject strings alone
cannot satisfy that requirement. A separate policy publication/identity review is
required before a human initiating-principal mapping becomes executable.
All request-semantic fields, including operation UUID and exact target/body/
catalog/source hashes, must exist before claim-free issue Check. Only top-level
`context.approval` is excluded by ApprovalBindingDigest. Validate local submitted
request against `binding.submitted_request_digest`; validate the enriched returned
binding's full digest; join served `claim.binding.pdp_digest` to evaluated
`binding.approval_binding_digest`. Pass the full enriched request digest and exact
decision ID to existing consume, and independently confirm the matching durable
consumption triple inside the admitted one-shot execution boundary. Do not use
locally rehashed unenriched approval-free request as that join.
Required consumer regression tests must intercept actual claim and PDP requests
and prove the compiled contract survives every builder unchanged; changed nested
operation/body/source/catalog fields fail the approval join before consume; missing
contract, wrong action or forged subject causes zero claim/PDP/consume/backend
calls; caller mutation after compilation cannot mutate the bound request.
Existing staged Access tests establish canonical API behavior and old-package
refusal/gaps, not those future consumer tests.
## Explicit limits on this review
This review approves no new executable package/action grant, representation
identity, service token, mediator, ledger, task-token ACL, native CCR, credential
request, production change, or lifecycle adoption. Shipped v2 admits only service
subject secrets-engine and its twelve original actions; it denies execute-ccr and
human principals, and existing apply ignores execution-contract contents. A new
exact owner-reviewed package/version and authenticated initiating-principal
correspondence must be reviewed and published separately. Historic enforced caller
route receipts are not current reachability evidence. No native calls were made.
Secrets T06 and Platform RPF35-T02 remain open. Later entitlement acceptance needs
the actual selected production workflow through its exact reviewed compiler,
consume/admission and restricted backend, with native effect, refusal/no-fallback,
and verified cleanup. A metadata trial does not adopt provision, rotation or exec.

View file

@ -0,0 +1,116 @@
# Exact execute-ccr PDP consumer integration (source preparation)
Access source baseline: c829e530309d4a885a7dbe34ddc316e0c25d205f.
No native readiness or formal owner assent is established by this staged artifact.
## Existing interface, without a new grant API
Use POST /v1/check with CheckRequest, DecisionEnvelope and the existing served
approval claim/consume APIs. pkg/api/canonical.go already hashes nested context
values, including an execution_contract object. No new canonical digest function
or access-engine execution ledger is needed. Access owns policy decisions only;
Secrets owns PEP lifecycle and one-shot admission, Platform owns OpenBao custody.
The published request action for the new CLI must be execute-ccr, resource
secret-catalog-lane under system secrets-engine, id catalog:<catalog id>, stage
prod and tenant tenant:platform. CLI execute-ccr must never send apply: shipped
lifecycle v2 accepts apply while ignoring all execution_contract contents. That
existing grant is not the reviewed metadata execution contract. Preserve existing
12-action behavior and add a separate owner-reviewed exact execute-ccr policy
version/action declaration and denial tests before publication.
The proposed policy must enforce human_control true, served approval kind/issuer/
valid_now/human_control/pdp_path, closed contract_version and metadata-apply-ccr,
nonempty exact operation_id, bounded deadline/budget, explicit target/body/catalog/
CCR/grant/source hashes and trusted principal representation. Hash existence is
shape, not provenance: body equality and owner-source reconstruction remain PEP
obligations. Policy cannot compare its own post-evaluation request digest.
Unknown action, missing contract/approval, foreign principal and older package
must refuse. A package/version pin is validated in envelope provenance, not hashed
as an authority field: api.RequestDigest excludes request.policy_version.
## Mandatory digest joins
1. Compile owner sources and catalog into the complete claim-free request.
All execution fields are inside context.execution_contract before issue Check.
Use context.purpose for consumer purpose. Top-level purpose is reserved for
advisory readback and enforcement /v1/check refuses it.
2. Issue approval against claim-free Check's enriched binding.request_digest.
Approval Engine records that value as claim.binding.pdp_digest.
3. Fetch the live served claim, attach it only at context.approval, and Check the
exact same request again. Retain the submitted request in owner memory.
4. PEP validates binding.submitted_request_digest against its submitted request;
binding.request_digest against the returned enriched binding material; and
claim.binding.pdp_digest against binding.approval_binding_digest. The latter
is the enriched request with only top-level context.approval removed. It does
not remove execution_contract, human_control, catalog_target or purpose.
5. Validate signature/served authenticity using existing configured PEP path,
provenance package/version, caller record, registry snapshot, allow lifetime,
live claim freshness, and exact subject/action/resource/tenant/context. Registry
enrichment can alter subject/resource attributes: do not compare locally
computed claim-free digest to claim.pdp_digest.
6. Consume once with approval_id, full enriched binding.request_digest and exact
decision_id. Approval Engine's consume checks request digest format/CAS, not
semantic correspondence to issue pdp_digest; steps 1–5 are mandatory. Independently
read the durable approval consumption triple through the authenticated owner
route and match it before OpenBao. Idempotent response is never fresh admission.
7. A changed operation UUID/method/path/body/source/catalog/subject yields a
different approval-free digest; require a fresh exact approval. Retries only
return final stored receipt. Unknown consume/backend outcomes require recovery.
## Minimal consumer code delta
Secrets authorization.build_action_request gains a strict optional keyword-only
execution_contract parameter. validate/compile it in Secrets' owner compiler,
then deep-copy it into context. Reject a contract on any action except execute-ccr,
reject execute-ccr without the contract. Set human_control true on this action
regardless of legacy catalog default. Catalog_target remains included.
Thread the SAME validated object through approval_consume._expected_request,
resolve_approval_observation and authorize_action. Today _expected_request rebuilds
from cfg/entry and drops any caller-added context; merely adding context in CLI
would not reach the claim/PDP join. No arbitrary caller request/body injection.
Require the execution boundary's verified initiator identity, not cfg/environment
strings, and exact package/version configuration for execute-ccr. Return the
existing ConsumeBinding and confirmed ConsumedApproval, never an opaque approval
label. require_production_consume runs only in owner child after admission reserve.
Platform independently recompiles exact operations and compares full digest,
then invokes the reviewed Secrets consume path at the actual effect boundary.
Its persistent one-shot ledger requires unique approval+digest and durable states
before each external call. This ledger and restricted backend do not currently
exist; audit outbox and bare consumed bool do not substitute. No unrestricted
subprocess, generic OpenBao apply, caller ACL/HCL, path override or bearer return.
## Principal and route truth
values/secrets-engine.yaml enforces Kubernetes TokenReview for
system:serviceaccount:secrets-engine:secrets-engine representing protected system
secrets-engine. This authenticates transport caller/system correspondence only:
internal/callerauth/auth.go does not bind CheckRequest.subject to that identity.
The v2 policy separately admits only subject secrets-engine/type service. A
caller-authored initiating human is neither authenticated by this path nor an
admitted v2 subject. An explicit identity-owner verified representation contract
plus policy grant is required before actual initiating-principal design can ship.
Do not rename service:secrets-engine to secrets-engine silently; authentication
service subject and PDP principal have different published vocabularies.
FLEX-WP-0023 records historic enforce-mode positive/negative native caller proof.
This is source evidence of an existing route, not a current live probe. Operator
CLI access needs attended admitted TokenRequest/tunnel/network path; in-cluster
DNS is not a workstation route. No token was requested and no native query ran.
FLEX-WP-0036 runtime rename remains active: keep existing flex-auth coordinates
until exact consumer transition is separately admitted. No new executor route,
metadata CCR, task execution grant, source pin, real native effect, cleanup proof,
principal representation or steady-state workflow adoption is supplied by this
stage. RPF35-T02 and Secrets T06 must remain open.
## Verified source tests
Run go test ./pkg/api ./internal/policy -run ExecutionContract -count=1 in staged
source. API tests cover ten changed semantic fields, claim attach/removal,
registry enrichment and correlation ID irrelevance. Policy test runs actual v2
Rego: execute-ccr denies unknown_action, fake execution context on apply still
allows (demonstrating the semantic gap), human principal denies wrong_subject_type.
These characterize shipped behavior and digest integration; they do not claim
new entitlement policy or executor is shipped.

View file

@ -0,0 +1,25 @@
package policy_test
import (
"context"
"path/filepath"
"testing"
"github.com/netkingdom/access-engine/internal/policy"
"github.com/netkingdom/access-engine/pkg/api"
)
func TestExecutionContractShippedPolicyDoesNotAdmitNewActionOrPrincipal(t *testing.T) {
pkg,err:=policy.LoadAndValidateFile(context.Background(),filepath.Join("..","..","examples","secrets-engine","policy_package.md"))
if err!=nil || !pkg.Valid {t.Fatalf("policy load: %v",err)}
r:=api.CheckRequest{Tenant:"tenant:platform",Subject:api.SubjectRef{ID:"secrets-engine",Type:"service"},Action:"execute-ccr",Resource:api.ResourceRef{ID:"catalog:test",Type:"secret-catalog-lane",System:"secrets-engine"},Context:map[string]any{"execution_contract":map[string]any{"operation":"metadata-apply-ccr"}}}
result,err:=pkg.Evaluate(context.Background(),r)
if err!=nil || result.Effect!=api.DecisionEffectDeny || result.Reason!="unknown_action" {t.Fatalf("new action: %+v %v",result,err)}
// Existing apply ignores execution_contract content; its allow is not exact task authority.
r.Action="apply"
r.Context["execution_contract"]=map[string]any{"operation":"arbitrary-mutation","payload_sha256":"forged"}
result,err=pkg.Evaluate(context.Background(),r)
if err!=nil || result.Effect!=api.DecisionEffectAllow {t.Fatalf("existing apply gap characterization: %+v %v",result,err)}
r.Subject=api.SubjectRef{ID:"founder-unregistered",Type:"human"}
result,err=pkg.Evaluate(context.Background(),r)
if err!=nil || result.Effect!=api.DecisionEffectDeny || result.Reason!="wrong_subject_type" {t.Fatalf("human principal: %+v %v",result,err)}
}

View file

@ -0,0 +1,52 @@
package api
import (
"encoding/json"
"testing"
)
func executionRequest(t *testing.T) CheckRequest {
t.Helper()
var r CheckRequest
err := json.Unmarshal([]byte(`{"tenant":"tenant:platform","subject":{"id":"secrets-engine","type":"service"},"action":"execute-ccr","resource":{"id":"catalog:test","type":"secret-catalog-lane","system":"secrets-engine","attributes":{"stage":"prod"}},"context":{"purpose":"metadata-apply-ccr","human_control":true,"execution_contract":{"contract_version":"SECRETS-EXEC-20261011-v1","operation_id":"018b3ff9-7470-470b-bf37-36d8b9b67eb1","catalog_sha256":"catalog-original","ccr_immutable_sha256":"ccr-original","source_bundle":[{"path":"/owner/mediator.py","sha256":"source-original"}],"operations":[{"method":"POST","path":"/v1/sys/policies/acl/exact","payload_sha256":"body-original"}]}}}`), &r)
if err != nil { t.Fatal(err) }
return r
}
func TestExecutionContractExactSemanticChangesInvalidateBinding(t *testing.T) {
original := executionRequest(t)
digest := RequestDigest(original)
cases := map[string]func(*CheckRequest){
"operation id":func(r *CheckRequest){r.Context["execution_contract"].(map[string]any)["operation_id"]="other"},
"catalog":func(r *CheckRequest){r.Context["execution_contract"].(map[string]any)["catalog_sha256"]="other"},
"ccr":func(r *CheckRequest){r.Context["execution_contract"].(map[string]any)["ccr_immutable_sha256"]="other"},
"source":func(r *CheckRequest){r.Context["execution_contract"].(map[string]any)["source_bundle"].([]any)[0].(map[string]any)["sha256"]="other"},
"method":func(r *CheckRequest){r.Context["execution_contract"].(map[string]any)["operations"].([]any)[0].(map[string]any)["method"]="DELETE"},
"target":func(r *CheckRequest){r.Context["execution_contract"].(map[string]any)["operations"].([]any)[0].(map[string]any)["path"]="/v1/sys/policies/acl/sibling"},
"body":func(r *CheckRequest){r.Context["execution_contract"].(map[string]any)["operations"].([]any)[0].(map[string]any)["payload_sha256"]="other"},
"principal":func(r *CheckRequest){r.Subject.ID="other"},
"action":func(r *CheckRequest){r.Action="apply"},
"tenant":func(r *CheckRequest){r.Tenant="other"},
}
for name, change := range cases {t.Run(name,func(t *testing.T){r:=executionRequest(t);change(&r);if RequestDigest(r)==digest || ApprovalBindingDigest(r)==digest {t.Fatal("semantic mutation retained binding")}})}
}
func TestExecutionContractApprovalJoinAndEnrichment(t *testing.T) {
issue:=executionRequest(t)
// Model the actual evaluator's tenant/registry overlay before issue Check.
issue.Subject.Tenant=issue.Tenant
issue.Subject.Attributes=map[string]any{"display_name":"Engine owner"}
issue.Resource.Tenant=issue.Tenant
submitted:=executionRequest(t)
submitted.Context["approval"]=map[string]any{"kind":"approval-claim","binding":map[string]any{"pdp_digest":RequestDigest(issue)}}
evaluated:=issue
evaluated.Context=map[string]any{}
for k,v:=range issue.Context {evaluated.Context[k]=v}
evaluated.Context["approval"]=submitted.Context["approval"]
binding:=NewDecisionBindingFor(evaluated,submitted)
if binding.SubmittedRequestDigest!=RequestDigest(submitted) {t.Fatal("submitted request not bound")}
if binding.ApprovalBindingDigest!=RequestDigest(issue) {t.Fatal("claim-free issue digest does not join")}
if binding.RequestDigest==binding.SubmittedRequestDigest {t.Fatal("test did not exercise enriched request")}
submitted.ID="different-correlation-id"
if RequestDigest(submitted)!=binding.SubmittedRequestDigest {t.Fatal("correlation id unexpectedly authorizes")}
}

View file

@ -64,4 +64,8 @@ record does not establish owner assent, a native entitlement, an authenticated
initiator representation, a mediator/ledger, exact native CCR/grant, or lifecycle
adoption. No native call, credential request, DB write, commit or source-policy
activation ran. Existing Secrets T06 and Platform RPF35-T02 remain open.
Formal own-role review can follow persistence of this completed work record.
Formal Access-own-role source review prepared after this completed anchor was
persisted in commit `f30e08cc96634d48987fb7203b71961437119535`: candidate
`docs/reviews/2026-10-11-task-execution-pdp-source.md`. The review approves only
the exact proposed integration direction and source characterization; it grants
no package/action, native entitlement, representation identity or lifecycle adoption.