Prepare closed service task execution input and policy contract
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
parent
077eb0a63c
commit
bc92f95e5f
12 changed files with 639 additions and 57 deletions
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"schema": "source-fixture-compatibility/v1",
|
||||
"previous_service_manifest_sha256": "98142d4b03d13eccde813483c88ada7d5412c397334e086df6ba64ee89f79d86",
|
||||
"original_human_generator_sha256": "3015561cd4b1120177605a23f874220bb34a90548ea0fee5a158f3d16a9b5743",
|
||||
"original_human_policy_sha256": "a790ecfbc8906c5a30e3eb066f391330d73d19b8cd46814d1d9778f24774d9e7",
|
||||
"original_shape": {
|
||||
"field": "task_execution_projection.not_after_ns",
|
||||
"representation": "int(epoch_seconds)*1000000000",
|
||||
"exact_profile": "unsupported Python integer magnitude > 2^53-1"
|
||||
},
|
||||
"resolution": "Preserve original projection as explicitly refused counterexample; descriptor-only canonical generator, unchanged closed human policy. No schema relabeling/rounding/RFC3339 identity rewrite.",
|
||||
"source_tests_pass_events": 133,
|
||||
"source_tests_failures": 0,
|
||||
"source_test_command": "SECRETS_ENGINE_SOURCE=/tmp/access-secrets-canonical-review/source GOCACHE=/tmp/access-taskexecution-go-cache go test -json ./internal/taskexecution ./internal/policy ./pkg/api -count=1",
|
||||
"identity_contract_changed": false,
|
||||
"human_policy_changed": false,
|
||||
"policy_constant_flipped": false,
|
||||
"native_execution": false,
|
||||
"service_scope": "structural characterization and TokenReview input preparation; no exact approval/PDP/consume/journal/grant join or operational readiness"
|
||||
}
|
||||
141
docs/service-task-execution-contract.md
Normal file
141
docs/service-task-execution-contract.md
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
# Proposed faithful Secrets service task execution successor
|
||||
|
||||
Source component for existing SECRETS-WP-0013 and RPF-WP-0035-T12.
|
||||
Based on accepted-intent technical assessment in
|
||||
/tmp/execute-ccr-accepted-intent-assessment.json. This is neither foreign owner
|
||||
acceptance nor a new doctrine choice, live caller mapping or native permission.
|
||||
|
||||
## Principal and scope
|
||||
|
||||
The initiating/represented principal for this first pilot is the admitted Secrets
|
||||
service itself. It does not claim to represent a named human. The operation still
|
||||
declares human-control approval; the authenticated human approver is a separate
|
||||
principal and cannot supply service caller authentication. Accepted v0.8/GH013/
|
||||
GH016 do not impose universal human initiation/User/Tenant membership on every
|
||||
metadata action. Operations deliberately representing a human or relying on human
|
||||
membership need their own verified initiating/delegation/provider contract.
|
||||
|
||||
The prior proposed human package secrets-engine.task-execution v1 and its literal
|
||||
false gate remain byte-for-byte unchanged. This separate proposed
|
||||
secrets-engine.task-execution.service-pilot v1 package is not a toggle of that
|
||||
variant, not legacy lifecycle v2 apply and not whole successor-standard acceptance.
|
||||
Its literal runtime_admission=false keeps every runtime policy evaluation closed.
|
||||
Candidate-predicate characterization never flips that constant or grants an act.
|
||||
|
||||
## Concrete authenticated source input component
|
||||
|
||||
internal/taskexecution.ServicePilotInputs uses actual existing callerauth
|
||||
Authenticator.Authorize/TokenReview machinery, fixed enforce mode, flex-auth
|
||||
audience and the explicitly proposed mapping:
|
||||
|
||||
system:serviceaccount:secrets-engine:secrets-engine -> secrets-engine/type service,
|
||||
protected system secrets-engine, tenant:platform.
|
||||
|
||||
The transport/system association is present in current values/secrets-engine.yaml;
|
||||
the explicit transport-to-subject association here is new proposed source and still
|
||||
needs owner/runtime admission. A2 system mapping alone does not prove arbitrary
|
||||
request subjects. The source constructor accepts only an owner-installed reviewer,
|
||||
never a request-selected principal or warn/disabled mode. The unexported ServiceInput
|
||||
records actual successful review, fixed matching subject/type and nonzero future
|
||||
transport expiry; zero/default input refuses. Its detached request snapshot never
|
||||
contains a bearer token or an unsigned authenticated flag.
|
||||
|
||||
service_actor_binding is PUBLIC DECLARED metadata included before approval issue:
|
||||
version proposed-service-task-caller/v1, exact principal/subject/type/tenant. It is
|
||||
not authentication evidence. Prepare compares it to the independently authenticated
|
||||
caller and source mapping. Incorrect/missing/extra binding fields refuse. Claimed
|
||||
human/delegation/projection/verified/owner_admission fields refuse rather than being
|
||||
interpreted as authority. Deadline must be live and no later than actual reviewed
|
||||
transport expiry. The returned input is eligibility preparation, not a PDP allow,
|
||||
trusted served approval, consume confirmation or operational entitlement.
|
||||
|
||||
Maker tests use a synthetic TokenReviewer, not actual Kubernetes authentication.
|
||||
Actual deployed TokenReview origin/CA/RBAC/audience/projection rotation and mapping
|
||||
admission must be proved before runtime use. The adapter is not wired into HTTP
|
||||
routes, decision engine evaluation or a native executor; source package remains
|
||||
hard-closed. A forged public service_actor_binding alone remains insufficient.
|
||||
|
||||
## Exact operation and independent gates
|
||||
|
||||
Owner compiler derives exact metadata CCR/catalogue/source/body/target plan. Whole
|
||||
SECRETS-EXEC-20261011-v1 descriptor binds unique operation UUID, CCR/grant immutable
|
||||
hashes, consumer thirteen-field local catalogue fingerprint, independently pinned
|
||||
source roles, estate/origin, expected before/after states, six GET/PUT/GET reader
|
||||
ACL then GET/PUT/GET role operations, bounded deadline and 120s/12-use ceilings.
|
||||
Platform rederives exact body bytes before each call. This source package models
|
||||
shape, service declaration, production tenant/stage and human-control claim shape;
|
||||
it neither authenticates sources nor compiles full baseline/grant/estate/deadline.
|
||||
|
||||
Required sequence remains:
|
||||
|
||||
1. Authenticate the admitted service caller and explicitly bind its subject; obtain
|
||||
exact owner-derived complete request before approval issue. Local/public discovery
|
||||
only precedes consume. No caller projection or founder bootstrap substitutes.
|
||||
2. Obtain live served approval from independently authenticated Approval Engine
|
||||
origin; require declared human_control with verified human approver under GH016,
|
||||
fresh validity and canonical PDP path. Approval is a fact, never a decision.
|
||||
3. Access renders fresh exact package/version result over authenticated caller,
|
||||
owner operation and served facts; decision binds full enriched request, exact
|
||||
submitted request, and approval-free request. The claim's recorded pdp_digest
|
||||
must equal served binding.approval_binding_digest. Use repaired Go-compatible
|
||||
canonical serialization; do not translate Approval native digest or rewrite old
|
||||
claims. Server must make trusted input provenance reconstructable and prevent
|
||||
caller substitution. This source candidate does not install that server join.
|
||||
4. PEP obtains authenticated successful consume for exactly approval/request/decision
|
||||
before any protected consumer login/effect. Platform independently confirms original
|
||||
consumption using trusted provider transport; supplied booleans/receipts and
|
||||
same-digest CAS retry are not a fresh execution grant.
|
||||
5. Owner-private durable journal reserves the same operation once, maintains exclusive
|
||||
admission and pending intent before each exact phase/call, and refuses replay or
|
||||
unknown recovery. Whole canonical request, caller mapping, body/plan and source
|
||||
correspondence remain unchanged across reserve/consume/applying/native phases.
|
||||
6. Independently authenticate CCR38/OpenBao service provenance after consume. Owner
|
||||
separately admits task-execution-grant CCR, exact disposable target/estate/route
|
||||
and bounded owner-held ephemeral token. Token is never exported to the consumer;
|
||||
native ACL alone cannot constrain policy/role bodies. Mediator enforces exact body
|
||||
equality, real expiry/use budget, native readback, revoke and temporary cleanup.
|
||||
7. Lost/uncertain response, crash, incomplete revoke or cleanup records unknown and
|
||||
does not auto-retry. Owner reconciliation plus fresh exact authorization governs
|
||||
another action. Actual positive/negative/interruption proofs and owner acceptance
|
||||
are required before pilot completion, then separately reviewed lifecycle adoption.
|
||||
|
||||
The pure candidate predicate's syntactic pdp_digest/freshness checks do not validate
|
||||
live provider provenance, exact digest equality, human approver identity or consume.
|
||||
They are source shape characterization only. Literal runtime_admission=false enforces
|
||||
that absence. Authentication plus approval alone cannot enable it. Future source
|
||||
successor must integrate all applicable gates, not expose an enable flag.
|
||||
|
||||
## Verification and limits
|
||||
|
||||
Maker source tests verify supported synthetic authenticated-service input binding,
|
||||
wrong transport/subject/type/audience/tenant, missing/expired transport, deadline,
|
||||
forged binding/delegation/flags and detached snapshot/zero-input refusal. Actual
|
||||
Secrets ExecutionContract parser generates complete six-call synthetic input;
|
||||
OPA candidate predicate is queried directly for eligible/negative shapes while
|
||||
normal policy evaluation remains deny. Old human gate is unchanged. Source
|
||||
fixtures register synthetic attributes solely for package-validation checks,
|
||||
not an actual live catalogue or estate registry. No runtime image, credential,
|
||||
provider admission, API change or native effect occurs.
|
||||
|
||||
|
||||
## Exact component omissions (not completion evidence)
|
||||
|
||||
This source candidate is STRUCTURAL CHARACTERIZATION and authenticated-input
|
||||
preparation only. Its predicate checks a syntactically tagged pdp_digest, not its
|
||||
actual equality to enriched approval_binding_digest. It does not prove served
|
||||
claim origin or verified approver identity, reconstruct canonical native claim
|
||||
binding, validate full submitted/enriched DecisionEnvelope or consumption triplet,
|
||||
bind actual compiler bytes to the whole descriptor, enforce journal phase/order,
|
||||
admit grant/baseline/estate or perform an effect. Those are explicit implementation
|
||||
requirements; a matching predicate and reviewed TokenReview input are insufficient.
|
||||
The service adapter carries authenticated transport evidence outside the canonical
|
||||
request but is not connected to HTTP evaluation/provider validation. A caller's
|
||||
service_actor_binding remains a public declaration independently compared by the
|
||||
adapter, never a substitute for runtime provenance or exact operation authority.
|
||||
|
||||
The old human fixture's epoch nanosecond integer exceeds the repaired consumer's
|
||||
safe integer profile. Compatibility repair preserves that original projection as
|
||||
an explicitly refused counterexample and tests descriptor-only canonical parity.
|
||||
The old human package/identity schema are unchanged; no nanoseconds are rounded or
|
||||
relabeled, no RFC3339 projection contract is invented, and no constant is flipped.
|
||||
Any future human identity shape needs separate owner-reviewed source integration.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
- id: unsigned-service-caller-not-authority
|
||||
request:
|
||||
tenant: tenant:platform
|
||||
subject: {id: secrets-engine, type: service}
|
||||
action: execute-ccr
|
||||
resource: {id: catalog:test, type: secret-catalog-lane, system: secrets-engine}
|
||||
context: {human_control: true, runtime_admission: true, verified: true}
|
||||
expect: {effect: deny, reason: service_execution_integration_unadmitted}
|
||||
118
examples/secrets-engine-service-task-execution/policy_package.md
Normal file
118
examples/secrets-engine-service-task-execution/policy_package.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
---
|
||||
id: secrets-engine.task-execution.service-pilot
|
||||
name: Secrets admitted service task execution
|
||||
namespace: secrets-engine:secret-catalog-lane
|
||||
version: v1
|
||||
status: proposed
|
||||
package: flexauth.secrets_engine.service_task_execution
|
||||
allow_ttl: 15s
|
||||
actions: [execute-ccr]
|
||||
owner: team:platform-security
|
||||
fixtures: [policy_fixtures.yaml]
|
||||
caring:
|
||||
profile: caring-0.4.0-rc2
|
||||
enforce: false
|
||||
activation:
|
||||
mode: local
|
||||
---
|
||||
|
||||
# Proposed faithful service pilot successor
|
||||
|
||||
A separate source package for an admitted Secrets service as the initiating and
|
||||
represented principal. It imposes no universal human initiator/User/Tenant gate.
|
||||
It still requires the operation's declared human-control approval. The human
|
||||
approver is not the service caller and does not supply service authentication.
|
||||
|
||||
Current runtime_admission is literal false because authenticated server mapping,
|
||||
served claim validation, exact PDP joins and Platform executor integration are not
|
||||
installed. Request flags cannot enable it. candidate_matches is source contract
|
||||
characterization, not authority; positive predicate tests never flip the constant.
|
||||
Raw caller metadata is not a verified identity. See docs/service-task-execution-contract.md.
|
||||
|
||||
```rego
|
||||
runtime_admission := false
|
||||
|
||||
default decision := {"effect": "deny", "reason": "service_execution_integration_unadmitted"}
|
||||
|
||||
decision := {"effect": "allow", "reason": "exact_task_execution_matched"} {
|
||||
runtime_admission
|
||||
candidate_matches
|
||||
}
|
||||
|
||||
hash_ok(x) { is_string(x); regex.match("^sha256:[0-9a-f]{64}$", x) }
|
||||
|
||||
candidate_matches {
|
||||
input.action == "execute-ccr"
|
||||
input.tenant == "tenant:platform"
|
||||
input.subject.id == "secrets-engine"
|
||||
input.subject.type == "service"
|
||||
input.resource.system == "secrets-engine"
|
||||
input.resource.type == "secret-catalog-lane"
|
||||
input.context.human_control == true
|
||||
c := input.context.execution_contract
|
||||
c.contract_version == "SECRETS-EXEC-20261011-v1"
|
||||
c.operation == "metadata-apply-ccr"
|
||||
c.execution_actor == "service:secrets-engine"
|
||||
regex.match("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", c.operation_id)
|
||||
c.ccr_id != c.execution_grant_ccr_id
|
||||
hash_ok(c.ccr_immutable_sha256)
|
||||
hash_ok(c.grant_immutable_sha256)
|
||||
hash_ok(c.catalog_sha256)
|
||||
hash_ok(c.expected_before)
|
||||
hash_ok(c.expected_after)
|
||||
c.backend_budget.ttl_seconds <= 120
|
||||
c.backend_budget.ttl_seconds >= 30
|
||||
c.backend_budget.uses == 12
|
||||
count(c.operations) == 6
|
||||
c.operations[0].method == "GET"
|
||||
c.operations[1].method == "PUT"
|
||||
c.operations[2].method == "GET"
|
||||
c.operations[3].method == "GET"
|
||||
c.operations[4].method == "PUT"
|
||||
c.operations[5].method == "GET"
|
||||
regex.match("^sys/policies/acl/[A-Za-z0-9_-]+$", c.operations[0].path)
|
||||
regex.match("^auth/[A-Za-z0-9_-]+/role/[A-Za-z0-9_-]+$", c.operations[3].path)
|
||||
c.operations[0].path == c.operations[1].path
|
||||
c.operations[1].path == c.operations[2].path
|
||||
c.operations[3].path == c.operations[4].path
|
||||
c.operations[4].path == c.operations[5].path
|
||||
every_operation_hash_valid
|
||||
b := input.context.service_actor_binding
|
||||
count(b) == 5
|
||||
b.version == "proposed-service-task-caller/v1"
|
||||
b.transport_principal == "system:serviceaccount:secrets-engine:secrets-engine"
|
||||
b.subject_id == input.subject.id
|
||||
b.subject_type == "service"
|
||||
b.tenant == input.tenant
|
||||
not input.context.task_execution_projection
|
||||
not input.context.initiator
|
||||
not input.context.represented_principal
|
||||
not input.context.delegation
|
||||
input.resource.attributes.stage == "prod"
|
||||
time.parse_rfc3339_ns(c.operation_deadline) > time.now_ns()
|
||||
input.context.approval.schema_version == "0.1"
|
||||
input.context.approval.kind == "approval-claim"
|
||||
input.context.approval.issuer == "approval-engine"
|
||||
input.context.approval.valid_now == true
|
||||
input.context.approval.consumed == false
|
||||
input.context.approval.reason_code == "ok"
|
||||
input.context.approval.binding.pdp_path == true
|
||||
hash_ok(input.context.approval.binding.pdp_digest)
|
||||
time.parse_rfc3339_ns(input.context.approval.freshness.not_after) > time.now_ns()
|
||||
time.parse_rfc3339_ns(input.context.approval.validity.expires_at) >= time.parse_rfc3339_ns(c.operation_deadline)
|
||||
input.context.approval.binding.human_control == true
|
||||
}
|
||||
|
||||
every_operation_hash_valid {
|
||||
count([x | x := input.context.execution_contract.operations[_]; hash_ok(x.payload_sha256)]) == 6
|
||||
}
|
||||
```
|
||||
|
||||
```rego test
|
||||
import data.flexauth.secrets_engine.service_task_execution
|
||||
|
||||
test_unsigned_flags_cannot_enable {
|
||||
service_task_execution.decision.effect == "deny"
|
||||
with input as {"context": {"runtime_admission": true, "verified": true}}
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
# Synthetic source-validation fixture only; no estate registry admission.
|
||||
resources:
|
||||
- id: catalog:synthetic
|
||||
system: secrets-engine
|
||||
type: secret-catalog-lane
|
||||
attributes: {stage: prod}
|
||||
69
internal/policy/service_task_execution_test.go
Normal file
69
internal/policy/service_task_execution_test.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package policy_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/netkingdom/access-engine/internal/policy"
|
||||
"github.com/netkingdom/access-engine/pkg/api"
|
||||
"github.com/open-policy-agent/opa/rego"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServiceTaskExecutionSourcePredicateAndHardRefusal(t *testing.T) {
|
||||
p, e := policy.LoadAndValidateFile(context.Background(), filepath.Join("..", "..", "examples", "secrets-engine-service-task-execution", "policy_package.md"))
|
||||
if e != nil || !p.Valid {
|
||||
t.Fatalf("package %v %+v", e, p.Validation)
|
||||
}
|
||||
out, e := exec.Command("/home/worsch/secrets-engine/.venv/bin/python", "../../tools/service_task_execution_fixture.py").Output()
|
||||
if e != nil {
|
||||
t.Fatal("actual Secrets descriptor generator", e)
|
||||
}
|
||||
var f struct {
|
||||
Request api.CheckRequest `json:"request"`
|
||||
}
|
||||
if json.Unmarshal(out, &f) != nil {
|
||||
t.Fatal("fixture")
|
||||
}
|
||||
candidate := func(r api.CheckRequest) bool {
|
||||
b, _ := json.Marshal(r)
|
||||
var input map[string]any
|
||||
json.Unmarshal(b, &input)
|
||||
result, e := rego.New(rego.Query("data.flexauth.secrets_engine.service_task_execution.candidate_matches"), rego.Module("candidate.rego", p.RegoModule), rego.Input(input)).Eval(context.Background())
|
||||
if e != nil {
|
||||
t.Fatal(e)
|
||||
}
|
||||
return len(result) > 0
|
||||
}
|
||||
if !candidate(f.Request) {
|
||||
t.Fatal("supported synthetic service contract failed predicate")
|
||||
}
|
||||
d, e := p.Evaluate(context.Background(), f.Request)
|
||||
if e != nil || d.Effect != api.DecisionEffectDeny || d.Reason != "service_execution_integration_unadmitted" {
|
||||
t.Fatal("unintegrated source package opened")
|
||||
}
|
||||
cases := map[string]func(*api.CheckRequest){"human": func(r *api.CheckRequest) { r.Subject.Type = "human" }, "foreigntenant": func(r *api.CheckRequest) { r.Tenant = "tenant:coulomb" }, "apply": func(r *api.CheckRequest) { r.Action = "apply" }, "servicecaller": func(r *api.CheckRequest) {
|
||||
r.Context["service_actor_binding"].(map[string]any)["transport_principal"] = "another"
|
||||
}, "missing human control": func(r *api.CheckRequest) {
|
||||
r.Context["approval"].(map[string]any)["binding"].(map[string]any)["human_control"] = false
|
||||
}, "consumed": func(r *api.CheckRequest) { r.Context["approval"].(map[string]any)["consumed"] = true }, "PDP digest": func(r *api.CheckRequest) {
|
||||
r.Context["approval"].(map[string]any)["binding"].(map[string]any)["pdp_digest"] = ""
|
||||
}, "expired observation": func(r *api.CheckRequest) {
|
||||
r.Context["approval"].(map[string]any)["freshness"].(map[string]any)["not_after"] = "2000-01-01T00:00:00Z"
|
||||
}, "wrong operation": func(r *api.CheckRequest) {
|
||||
r.Context["execution_contract"].(map[string]any)["operation"] = "generic-apply"
|
||||
}}
|
||||
for name, mutate := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var f struct {
|
||||
Request api.CheckRequest `json:"request"`
|
||||
}
|
||||
json.Unmarshal(out, &f)
|
||||
mutate(&f.Request)
|
||||
if candidate(f.Request) {
|
||||
t.Fatal("unsupported source contract matched")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -35,70 +35,47 @@ func TestTaskExecutionSourceHasNoActivationSwitch(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTaskExecutionPythonDescriptorAndSyntheticFutureProjection(t *testing.T) {
|
||||
// The prior human projection contains epoch nanoseconds outside the exact
|
||||
// cross-runtime integer profile. Preserve/refuse it; no identity schema change.
|
||||
func TestTaskExecutionDescriptorOnlyAndRefusedHumanProjection(t *testing.T) {
|
||||
output, e := exec.Command("/home/worsch/secrets-engine/.venv/bin/python", "../../tools/task_execution_interop_fixture.py").Output()
|
||||
if e != nil {
|
||||
t.Fatal("Python actual descriptor/canonical generator failed:", e)
|
||||
t.Fatal("actual descriptor/canonical generator failed:", e)
|
||||
}
|
||||
var fixture struct {
|
||||
Request api.CheckRequest `json:"request"`
|
||||
RequestDigest string `json:"request_digest"`
|
||||
ApprovalDigest string `json:"approval_binding_digest"`
|
||||
DescriptorDigest string `json:"descriptor_digest"`
|
||||
var f struct {
|
||||
Request api.CheckRequest `json:"request"`
|
||||
RequestDigest string `json:"request_digest"`
|
||||
ApprovalDigest string `json:"approval_binding_digest"`
|
||||
DescriptorDigest string `json:"descriptor_digest"`
|
||||
OriginalProjection map[string]any `json:"original_nanosecond_projection"`
|
||||
Refused bool `json:"original_projection_refused"`
|
||||
IdentityChanged bool `json:"identity_contract_changed"`
|
||||
}
|
||||
if json.Unmarshal(output, &fixture) != nil {
|
||||
if json.Unmarshal(output, &f) != nil {
|
||||
t.Fatal("fixture JSON")
|
||||
}
|
||||
r := fixture.Request
|
||||
if api.RequestDigest(r) != fixture.RequestDigest || api.ApprovalBindingDigest(r) != fixture.ApprovalDigest || api.CanonicalDigest(r.Context["execution_contract"]) != fixture.DescriptorDigest {
|
||||
t.Fatal("actual Python/Go canonical mismatch")
|
||||
if !f.Refused || f.IdentityChanged || f.OriginalProjection["not_after_ns"].(float64) <= float64(1<<53) {
|
||||
t.Fatal("unsupported original nanosecond projection was not explicitly preserved/refused")
|
||||
}
|
||||
raw, e := os.ReadFile(filepath.Join("..", "..", "examples", "secrets-engine-task-execution", "policy_package.md"))
|
||||
if e != nil {
|
||||
t.Fatal(e)
|
||||
if _, found := f.Request.Context["task_execution_projection"]; found {
|
||||
t.Fatal("unsupported projection entered descriptor-only request")
|
||||
}
|
||||
// This source replacement is intentionally test-only; no caller/config flag
|
||||
// can change the production package's hard admission=false constant.
|
||||
raw = []byte(strings.Replace(string(raw), "owner_admission := false", "owner_admission := true", 1))
|
||||
p, e := policy.Load(raw, "synthetic-future-provider-test.md")
|
||||
if e != nil {
|
||||
t.Fatal(e)
|
||||
if api.RequestDigest(f.Request) != f.RequestDigest || api.ApprovalBindingDigest(f.Request) != f.ApprovalDigest || api.CanonicalDigest(f.Request.Context["execution_contract"]) != f.DescriptorDigest {
|
||||
t.Fatal("actual descriptor-only Python/Go mismatch")
|
||||
}
|
||||
d, e := p.Evaluate(context.Background(), r)
|
||||
if e != nil || d.Effect != api.DecisionEffectAllow {
|
||||
t.Fatalf("synthetic future projection did not match: %v %+v", e, d)
|
||||
p, e := policy.LoadAndValidateFile(context.Background(), filepath.Join("..", "..", "examples", "secrets-engine-task-execution", "policy_package.md"))
|
||||
if e != nil || !p.Valid {
|
||||
t.Fatal("unchanged human source package")
|
||||
}
|
||||
cases := map[string]func(*api.CheckRequest){
|
||||
"action": func(r *api.CheckRequest) { r.Action = "apply" }, "service subject": func(r *api.CheckRequest) { r.Subject.ID = "other" }, "foreign tenant": func(r *api.CheckRequest) { r.Tenant = "tenant:coulomb" },
|
||||
"plan hash": func(r *api.CheckRequest) {
|
||||
r.Context["execution_contract"].(map[string]any)["expected_after"] = "sha256:" + strings.Repeat("b", 64)
|
||||
},
|
||||
"unsigned human": func(r *api.CheckRequest) { delete(r.Context, "task_execution_projection") },
|
||||
"registered tenant": func(r *api.CheckRequest) {
|
||||
r.Context["task_execution_projection"].(map[string]any)["tenant_source"] = "registration"
|
||||
},
|
||||
"membership": func(r *api.CheckRequest) {
|
||||
r.Context["task_execution_projection"].(map[string]any)["member_active"] = false
|
||||
},
|
||||
"transport": func(r *api.CheckRequest) {
|
||||
r.Context["task_execution_projection"].(map[string]any)["transport_principal"] = "other"
|
||||
},
|
||||
"expiry": func(r *api.CheckRequest) {
|
||||
r.Context["task_execution_projection"].(map[string]any)["not_after_ns"] = float64(1)
|
||||
},
|
||||
"no human control": func(r *api.CheckRequest) { r.Context["human_control"] = false },
|
||||
d, e := p.Evaluate(context.Background(), f.Request)
|
||||
if e != nil || d.Effect != api.DecisionEffectDeny || d.Reason != "initiating_provider_unadmitted" {
|
||||
t.Fatal("closed human package was enabled")
|
||||
}
|
||||
for name, mutate := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var f struct {
|
||||
Request api.CheckRequest `json:"request"`
|
||||
}
|
||||
json.Unmarshal(output, &f)
|
||||
mutate(&f.Request)
|
||||
d, e := p.Evaluate(context.Background(), f.Request)
|
||||
if e != nil || d.Effect != api.DecisionEffectDeny {
|
||||
t.Fatalf("mutation allowed: %v %+v", e, d)
|
||||
}
|
||||
})
|
||||
// No literal is flipped. Restoring the unsupported caller projection does
|
||||
// not turn the unchanged package into a grant either.
|
||||
f.Request.Context["task_execution_projection"] = f.OriginalProjection
|
||||
d, e = p.Evaluate(context.Background(), f.Request)
|
||||
if e != nil || d.Effect != api.DecisionEffectDeny {
|
||||
t.Fatal("old caller projection opened package")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
101
internal/taskexecution/service_input.go
Normal file
101
internal/taskexecution/service_input.go
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package taskexecution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/netkingdom/access-engine/internal/callerauth"
|
||||
"github.com/netkingdom/access-engine/pkg/api"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrServiceInput = errors.New("service task execution input refused")
|
||||
|
||||
const ServicePilotMappingVersion = "proposed-service-task-caller/v1"
|
||||
const ServicePilotPrincipal = "system:serviceaccount:secrets-engine:secrets-engine"
|
||||
|
||||
// ServicePilotInputs is source preparation only. It installs the explicit
|
||||
// proposed fixed subject-to-transport mapping, never a request-selected mapping.
|
||||
// No constructor parameter can select warn/disabled mode or another subject.
|
||||
type ServicePilotInputs struct{ auth *callerauth.Authenticator }
|
||||
|
||||
func NewServicePilotInputs(reviewer callerauth.TokenReviewer) (*ServicePilotInputs, error) {
|
||||
a, e := callerauth.New(callerauth.ModeEnforce, reviewer, "flex-auth", map[string]string{"secrets-engine": ServicePilotPrincipal}, nil)
|
||||
if e != nil {
|
||||
return nil, ErrServiceInput
|
||||
}
|
||||
return &ServicePilotInputs{auth: a}, nil
|
||||
}
|
||||
|
||||
// ServiceInput cannot be fabricated through exported fields. It proves only
|
||||
// source input preparation through TokenReview, not approval provenance/consume
|
||||
// or execution authority. Default zero value is not an authenticated input.
|
||||
type ServiceInput struct {
|
||||
serialized []byte
|
||||
caller callerauth.Record
|
||||
}
|
||||
|
||||
func (s ServiceInput) Request() (api.CheckRequest, error) {
|
||||
if s.caller.Mode != callerauth.ModeEnforce || s.caller.Principal != ServicePilotPrincipal || len(s.serialized) == 0 {
|
||||
return api.CheckRequest{}, ErrServiceInput
|
||||
}
|
||||
var r api.CheckRequest
|
||||
if json.Unmarshal(s.serialized, &r) != nil {
|
||||
return r, ErrServiceInput
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
func (s ServiceInput) Caller() callerauth.Record { return s.caller }
|
||||
|
||||
// DeclaredServiceBinding is public immutable metadata to bind at approval issue.
|
||||
// It is not authentication evidence; Prepare independently verifies its principal.
|
||||
func DeclaredServiceBinding() map[string]any {
|
||||
return map[string]any{"version": ServicePilotMappingVersion, "transport_principal": ServicePilotPrincipal, "subject_id": "secrets-engine", "subject_type": "service", "tenant": "tenant:platform"}
|
||||
}
|
||||
func (s *ServicePilotInputs) Prepare(ctx context.Context, authorization string, r api.CheckRequest, now time.Time) (ServiceInput, error) {
|
||||
refuse := func() (ServiceInput, error) { return ServiceInput{}, ErrServiceInput }
|
||||
if s == nil || s.auth == nil || now.IsZero() || r.Action != "execute-ccr" || r.Tenant != "tenant:platform" || r.Subject.ID != "secrets-engine" || r.Subject.Type != "service" || r.Resource.System != "secrets-engine" || r.Resource.Type != "secret-catalog-lane" || r.Resource.Attributes["stage"] != "prod" || r.Context["human_control"] != true {
|
||||
return refuse()
|
||||
}
|
||||
for _, key := range []string{"task_execution_projection", "initiator", "represented_principal", "delegation", "verified", "owner_admission"} {
|
||||
if _, found := r.Context[key]; found {
|
||||
return refuse()
|
||||
}
|
||||
}
|
||||
if _, found := r.Subject.Attributes["principal"]; found {
|
||||
return refuse()
|
||||
}
|
||||
supplied, err := json.Marshal(r.Context["service_actor_binding"])
|
||||
if err != nil {
|
||||
return refuse()
|
||||
}
|
||||
wanted, _ := json.Marshal(DeclaredServiceBinding())
|
||||
if string(supplied) != string(wanted) {
|
||||
return refuse()
|
||||
}
|
||||
identity, err := s.auth.Authorize(ctx, authorization, []string{r.Resource.System})
|
||||
if err != nil {
|
||||
return refuse()
|
||||
}
|
||||
record := s.auth.Record(identity)
|
||||
if record.Mode != callerauth.ModeEnforce || record.Principal != ServicePilotPrincipal || record.Audience != "flex-auth" || record.NotAfter.IsZero() || !record.NotAfter.After(now) {
|
||||
return refuse()
|
||||
}
|
||||
c, ok := r.Context["execution_contract"].(map[string]any)
|
||||
if !ok || c["contract_version"] != "SECRETS-EXEC-20261011-v1" || c["operation"] != "metadata-apply-ccr" || c["execution_actor"] != "service:secrets-engine" {
|
||||
return refuse()
|
||||
}
|
||||
deadline, ok := c["operation_deadline"].(string)
|
||||
if !ok {
|
||||
return refuse()
|
||||
}
|
||||
end, err := time.Parse(time.RFC3339Nano, deadline)
|
||||
if err != nil || !end.After(now) || end.After(record.NotAfter) {
|
||||
return refuse()
|
||||
}
|
||||
raw, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return refuse()
|
||||
}
|
||||
return ServiceInput{serialized: raw, caller: record}, nil
|
||||
}
|
||||
81
internal/taskexecution/service_input_test.go
Normal file
81
internal/taskexecution/service_input_test.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package taskexecution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/netkingdom/access-engine/internal/callerauth"
|
||||
"github.com/netkingdom/access-engine/pkg/api"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type serviceReviewer struct {
|
||||
identity callerauth.Identity
|
||||
err error
|
||||
calls int
|
||||
}
|
||||
|
||||
func (r *serviceReviewer) Review(_ context.Context, _ string) (callerauth.Identity, error) {
|
||||
r.calls++
|
||||
return r.identity, r.err
|
||||
}
|
||||
func serviceRequest(t *testing.T, now time.Time) api.CheckRequest {
|
||||
t.Helper()
|
||||
r := api.CheckRequest{Tenant: "tenant:platform", Subject: api.SubjectRef{ID: "secrets-engine", Type: "service"}, Action: "execute-ccr", Resource: api.ResourceRef{ID: "catalog:synthetic", Type: "secret-catalog-lane", System: "secrets-engine", Attributes: map[string]any{"stage": "prod"}}, Context: map[string]any{"human_control": true, "service_actor_binding": DeclaredServiceBinding(), "execution_contract": map[string]any{"contract_version": "SECRETS-EXEC-20261011-v1", "operation": "metadata-apply-ccr", "execution_actor": "service:secrets-engine", "operation_deadline": now.Add(60 * time.Second).Format(time.RFC3339Nano)}}}
|
||||
return r
|
||||
}
|
||||
func TestServicePilotAuthenticatedBinding(t *testing.T) {
|
||||
now := time.Now()
|
||||
reviewer := &serviceReviewer{identity: callerauth.Identity{Username: ServicePilotPrincipal, Audiences: []string{"flex-auth"}, NotAfter: now.Add(120 * time.Second)}}
|
||||
a, e := NewServicePilotInputs(reviewer)
|
||||
if e != nil {
|
||||
t.Fatal(e)
|
||||
}
|
||||
r := serviceRequest(t, now)
|
||||
s, e := a.Prepare(context.Background(), "Bearer synthetic", r, now)
|
||||
if e != nil || reviewer.calls != 1 {
|
||||
t.Fatal("source TokenReview path")
|
||||
}
|
||||
out, e := s.Request()
|
||||
if e != nil || api.RequestDigest(out) != api.RequestDigest(r) || s.Caller().Principal != ServicePilotPrincipal {
|
||||
t.Fatal("binding changed")
|
||||
}
|
||||
r.Context["service_actor_binding"].(map[string]any)["subject_id"] = "mutated"
|
||||
again, _ := s.Request()
|
||||
if again.Context["service_actor_binding"].(map[string]any)["subject_id"] != "secrets-engine" {
|
||||
t.Fatal("opaque input retained mutable caller map")
|
||||
}
|
||||
if _, e := (ServiceInput{}).Request(); e == nil {
|
||||
t.Fatal("zero input trusted")
|
||||
}
|
||||
}
|
||||
func TestServicePilotRefusals(t *testing.T) {
|
||||
now := time.Now()
|
||||
cases := map[string]func(*api.CheckRequest, *serviceReviewer){"human": func(r *api.CheckRequest, _ *serviceReviewer) { r.Subject.Type = "human" }, "subject": func(r *api.CheckRequest, _ *serviceReviewer) { r.Subject.ID = "another" }, "legacy apply": func(r *api.CheckRequest, _ *serviceReviewer) { r.Action = "apply" }, "foreigntenant": func(r *api.CheckRequest, _ *serviceReviewer) { r.Tenant = "tenant:coulomb" }, "wrong service principal": func(_ *api.CheckRequest, p *serviceReviewer) {
|
||||
p.identity.Username = "system:serviceaccount:other:other"
|
||||
}, "wrong audience": func(_ *api.CheckRequest, p *serviceReviewer) { p.identity.Audiences = []string{"openbao"} }, "expired transport": func(_ *api.CheckRequest, p *serviceReviewer) { p.identity.NotAfter = now }, "missing expiry": func(_ *api.CheckRequest, p *serviceReviewer) { p.identity.NotAfter = time.Time{} }, "caller verified": func(r *api.CheckRequest, _ *serviceReviewer) { r.Context["verified"] = true }, "human projection": func(r *api.CheckRequest, _ *serviceReviewer) {
|
||||
r.Context["task_execution_projection"] = map[string]any{"subject": "human"}
|
||||
}, "delegation": func(r *api.CheckRequest, _ *serviceReviewer) { r.Context["delegation"] = false }, "forged binding": func(r *api.CheckRequest, _ *serviceReviewer) {
|
||||
r.Context["service_actor_binding"].(map[string]any)["subject_id"] = "other"
|
||||
}, "lifetime": func(r *api.CheckRequest, _ *serviceReviewer) {
|
||||
r.Context["execution_contract"].(map[string]any)["operation_deadline"] = now.Add(240 * time.Second).Format(time.RFC3339Nano)
|
||||
}}
|
||||
for name, mutate := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := serviceRequest(t, now)
|
||||
p := &serviceReviewer{identity: callerauth.Identity{Username: ServicePilotPrincipal, Audiences: []string{"flex-auth"}, NotAfter: now.Add(120 * time.Second)}}
|
||||
mutate(&r, p)
|
||||
a, _ := NewServicePilotInputs(p)
|
||||
if _, e := a.Prepare(context.Background(), "Bearer synthetic", r, now); e == nil {
|
||||
t.Fatal("invalid input accepted")
|
||||
}
|
||||
})
|
||||
}
|
||||
p := &serviceReviewer{identity: callerauth.Identity{Username: ServicePilotPrincipal, Audiences: []string{"flex-auth"}, NotAfter: now.Add(time.Minute)}}
|
||||
a, _ := NewServicePilotInputs(p)
|
||||
if _, e := a.Prepare(context.Background(), "", serviceRequest(t, now), now); e == nil {
|
||||
t.Fatal("missing header accepted")
|
||||
}
|
||||
if _, e := NewServicePilotInputs(nil); e == nil {
|
||||
t.Fatal("missing owner reviewer accepted")
|
||||
}
|
||||
}
|
||||
13
tools/service_task_execution_fixture.py
Normal file
13
tools/service_task_execution_fixture.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
"""Synthetic interoperability generator; never obtains credentials or native state."""
|
||||
import hashlib, json, sys
|
||||
from datetime import datetime, timedelta, timezone
|
||||
sys.path.insert(0, '/home/worsch/secrets-engine/src')
|
||||
from secrets_engine.execution_contract import ExecutionContract, catalog_target_digest
|
||||
from secrets_engine.authorization import request_digest, approval_binding_digest
|
||||
h='sha256:'+'a'*64
|
||||
catalog={'lane':'synthetic','stage':'prod'}
|
||||
c={'contract_version':'SECRETS-EXEC-20261011-v1','operation_id':'cbfbced0-09d5-48c8-a1e7-a2ea4dc69153','operation':'metadata-apply-ccr','execution_actor':'service:secrets-engine','ccr_id':'CCR-2099-0001','execution_grant_ccr_id':'CCR-2099-0002','ccr_immutable_sha256':h,'grant_immutable_sha256':h,'catalog_sha256':catalog_target_digest(catalog),'expected_before':h,'expected_after':h,'source_bundle':{r:{'path':'/synthetic/'+r+'.py','sha256':h} for r in ['engine_dispatcher','platform_mediator','typed_ccr','policy_auth']},'backend_origin':'http://127.0.0.1:18200','cluster_uid':'synthetic-not-native','backend_budget':{'ttl_seconds':120,'uses':12},'operation_deadline':(datetime.now(timezone.utc)+timedelta(seconds=100)).isoformat(),'operations':[{'method':method,'path':path,'payload_sha256':h} for path in ['sys/policies/acl/synthetic','auth/synthetic/role/synthetic'] for method in ['GET','PUT','GET']]}
|
||||
c=ExecutionContract.parse(c).as_dict()
|
||||
p={'version':'proposed-service-task-caller/v1','transport_principal':'system:serviceaccount:secrets-engine:secrets-engine','subject_id':'secrets-engine','subject_type':'service','tenant':'tenant:platform'}
|
||||
r={'tenant':'tenant:platform','subject':{'id':'secrets-engine','type':'service'},'action':'execute-ccr','resource':{'id':'catalog:synthetic','type':'secret-catalog-lane','system':'secrets-engine','attributes':{'stage':'prod'}},'context':{'execution_contract':c,'catalog_target':catalog,'human_control':True,'service_actor_binding':p,'approval':{'schema_version':'0.1','kind':'approval-claim','issuer':'approval-engine','approval_id':'synthetic','valid_now':True,'consumed':False,'reason_code':'ok','binding':{'human_control':True,'pdp_path':True,'pdp_digest':h},'freshness':{'not_after':(datetime.now(timezone.utc)+timedelta(seconds=60)).isoformat()},'validity':{'expires_at':(datetime.now(timezone.utc)+timedelta(seconds=120)).isoformat()}}}}
|
||||
print(json.dumps({'request':r,'request_digest':request_digest(r),'approval_binding_digest':approval_binding_digest(r),'descriptor_digest':catalog_target_digest(c)}))
|
||||
|
|
@ -1,13 +1,29 @@
|
|||
"""Synthetic interoperability generator; never obtains credentials or native state."""
|
||||
import hashlib, json, sys
|
||||
import hashlib, json, os, sys
|
||||
from datetime import datetime, timedelta, timezone
|
||||
sys.path.insert(0, '/home/worsch/secrets-engine/src')
|
||||
sys.path.insert(0, os.environ.get('SECRETS_ENGINE_SOURCE', '/home/worsch/secrets-engine') + '/src')
|
||||
from secrets_engine.execution_contract import ExecutionContract, catalog_target_digest
|
||||
from secrets_engine.authorization import request_digest, approval_binding_digest
|
||||
from secrets_engine.errors import DecisionError
|
||||
h='sha256:'+'a'*64
|
||||
catalog={'lane':'synthetic','stage':'prod'}
|
||||
c={'contract_version':'SECRETS-EXEC-20261011-v1','operation_id':'cbfbced0-09d5-48c8-a1e7-a2ea4dc69153','operation':'metadata-apply-ccr','execution_actor':'service:secrets-engine','ccr_id':'CCR-2099-0001','execution_grant_ccr_id':'CCR-2099-0002','ccr_immutable_sha256':h,'grant_immutable_sha256':h,'catalog_sha256':catalog_target_digest(catalog),'expected_before':h,'expected_after':h,'source_bundle':{r:{'path':'/synthetic/'+r+'.py','sha256':h} for r in ['engine_dispatcher','platform_mediator','typed_ccr','policy_auth']},'backend_origin':'http://127.0.0.1:18200','cluster_uid':'synthetic-not-native','backend_budget':{'ttl_seconds':120,'uses':12},'operation_deadline':(datetime.now(timezone.utc)+timedelta(seconds=100)).isoformat(),'operations':[{'method':method,'path':path,'payload_sha256':h} for path in ['sys/policies/acl/synthetic','auth/synthetic/role/synthetic'] for method in ['GET','PUT','GET']]}
|
||||
c=ExecutionContract.parse(c).as_dict()
|
||||
p={'version':'proposed-task-execution-projection/v1','subject':'synthetic-human','principal_type':'human','tenant':'tenant:platform','tenant_source':'directory','mfa':True,'transport_principal':'system:serviceaccount:secrets-engine:secrets-engine','execution_contract_digest':catalog_target_digest(c),'resource_id':'catalog:synthetic','membership_source':'user-engine','tenant_state_source':'tenant-engine','member_active':True,'tenant_active':True,'not_after_ns':int((datetime.now(timezone.utc)+timedelta(seconds=60)).timestamp())*1000000000}
|
||||
r={'tenant':'tenant:platform','subject':{'id':'secrets-engine','type':'service'},'action':'execute-ccr','resource':{'id':'catalog:synthetic','type':'secret-catalog-lane','system':'secrets-engine'},'context':{'execution_contract':c,'catalog_target':catalog,'human_control':True,'task_execution_projection':p,'approval':{'kind':'approval-claim','binding':{'human_control':True}}}}
|
||||
print(json.dumps({'request':r,'request_digest':request_digest(r),'approval_binding_digest':approval_binding_digest(r),'descriptor_digest':catalog_target_digest(c)}))
|
||||
# Preserve the exact earlier shape as an explicit unsupported counterexample.
|
||||
# It is NOT rounded, relabeled as RFC3339 or admitted into the old human policy.
|
||||
original_projection = p
|
||||
try:
|
||||
request_digest(r)
|
||||
original_projection_refused = False
|
||||
except DecisionError:
|
||||
original_projection_refused = True
|
||||
# Descriptor-only interoperability is independent of a missing identity contract.
|
||||
del r['context']['task_execution_projection']
|
||||
print(json.dumps({'request':r,'request_digest':request_digest(r),
|
||||
'approval_binding_digest':approval_binding_digest(r),
|
||||
'descriptor_digest':catalog_target_digest(c),
|
||||
'original_nanosecond_projection':original_projection,
|
||||
'original_projection_refused':original_projection_refused,
|
||||
'identity_contract_changed':False}))
|
||||
|
|
|
|||
|
|
@ -138,3 +138,35 @@ Any formal source receipt must follow persistence of this exact own-repo record.
|
|||
No operational milestone closes; authoritative issuer/client, User/Tenant
|
||||
membership and representation/server injection, served approval joins and native
|
||||
execution remain on the existing drivers.
|
||||
|
||||
|
||||
## Prepare faithful service task execution source successor
|
||||
|
||||
```task
|
||||
id: FLEX-WP-ADHOC-2026-10-11-T05
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
Completed bounded source preparation based on accepted v0.8/GH013/GH016 intent
|
||||
assessment for existing SECRETS-WP-0013/RPF-WP-0035-T12 drivers. Prepared separate
|
||||
proposed service-pilot package with literal runtime-admission refusal, concrete
|
||||
source TokenReview enforce adapter binding exact admitted service transport to
|
||||
Secrets subject/type and immutable public declared mapping before approval issue,
|
||||
plus maker positive-input/refusal and pure candidate-shape tests. No universal
|
||||
human initiator/User/Tenant gate is imposed; a declared human-control approver
|
||||
remains distinct from service initiator. Old proposed human package stays unchanged.
|
||||
|
||||
This completes source component preparation only. No formal owner receipt, live
|
||||
mapping/provider admission, policy activation, exact served approval/PDP/consume/
|
||||
journal/task-grant/executor integration, credential or native action is completed.
|
||||
Operational drivers remain open; no clone workplan or source-policy enable switch
|
||||
is introduced. Synthetic successful input eligibility is not runtime allowance.
|
||||
|
||||
|
||||
T05 preparation refinement: preserved the original unadmitted human nanosecond
|
||||
projection as explicitly refused by the repaired canonical profile; converted its
|
||||
interop test to descriptor-only parity and unchanged hard-denial evidence. No old
|
||||
human policy or identity contract changes and no source constant flips. Service
|
||||
candidate remains structural characterization, not served approval/PDP/consume/
|
||||
compiler/journal/grant correspondence or operational readiness.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue