feat: journal strict task consumption before native fixture effects
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
codex 2026-10-16 09:20:33 +02:00
parent d042d468df
commit e2b832b5d4
8 changed files with 717 additions and 2 deletions

View file

@ -0,0 +1,107 @@
# Strict task handoff to independent consumption confirmation
RPF-WP-0035-T12 source preparation, 2026-10-16. This seam calls only the existing
fixed disposable native adapter. It installs no production origin, identity,
permission, real grant, generic broker or backend default.
## Actual starting gaps and reused owner interfaces
At Platform source base d042d468 and Secrets c80a944 the native fixture used a
synthetic direct `consume-confirmed` journal transition. No actual strict Secrets
task handoff existed. Generic Secrets consume accepted a substituted approval ID,
coerced idempotent values and did not require the original exact decision. Those
are Secrets-owned defects; Platform did not copy its authorization policy or edit
that repository. The Secrets owner prepared a separate strict module under
SECRETS-WP-0013, referenced by exact hashes in this package's manifest.
Approval Engine already provides `ExecutionConfirmationClient.consume_exact` and
`confirm_consumption`. The latter performs an independently authenticated GET of
the durable original approval object and filters it to the original consumption
triplet/time. It is historical PIP evidence, not authorization. It neither validates
an Access decision nor makes a supplied receipt authoritative. Platform's adapter
previously assumed its first native call was journal ordinal zero, conflicting
with a preceding durable CAS/confirmation sequence.
`scripts/task_execution_mediator.py` now performs the narrow owner join:
1. Require the actual `secrets_engine.task_execution_handoff` dependency; absence
refuses before provider credentials, journal reservation or native effects.
The mediator itself calls `authorize_task_execution`. It accepts neither an
inbound authorization object nor a caller-selected authorizer/transport callback.
2. Independently compile the exact local catalogue/descriptor/grant and compare the
strict owner's detached handoff descriptor byte-for-byte. Only authorization_id
may be added to approval reference metadata; purpose and source semantics cannot
be substituted through an inbound catalogue object. Secrets owns signed Check,
claim/native-act/full and approval-free digest joins, caller/subject correspondence
and the strict prepared object. Platform does not render or duplicate that decision.
3. Bind the actual returned full canonical digest into the owner Plan. Reserve the
approval/request/operation/Plan tuple and the precommitted cleanup obligations
once while holding the same invocation lock through cleanup.
4. Commit a CAS call intent, invoke Secrets `consume_task_execution` once and require
its actual typed result with exact original approval/request/decision/time and
`idempotent is False`. A historical idempotent response cannot open native work.
5. Commit a separate read intent and invoke the actual Approval owner's default
isolated transport, with independently installed read credential and exact same
owner-admitted origin. Require `confirm_consumption` to match the native act,
approval-free digest and original exact triplet/time. Raw approval entries and
provider credentials never enter journal evidence or receipts.
6. Recheck original approval/decision/operation bounds using the existing Secrets
time adapter, then persist `consume-confirmed`. Any CAS/read failure, timeout,
denied read or mismatch records unknown and causes zero native execution. A
subsequent invocation cannot retry the consumed approval or persisted admission.
7. Only then enter the fixed native grant/metadata adapter. Its next business-call
ordinal comes from the same live journal, so CAS and GET occupy ordinals0/1 and
native calls continue at2. Pending/unknown/cleanup-closed state cannot supply a
next ordinal. Each native request retains its own durable intent and outcome.
8. Cleanup stays under the original distinct obligations even if business work
fails. Returned evidence explicitly says native apply is unverified: six successful
native calls do not establish total approved baseline/readback normalization,
atomic CAS, service-login provenance or native production owner acceptance.
The owner configuration selects provider route/read credential and the existing
Secrets configuration. These are independently installed runtime inputs, never
part of an HTTP body or authority derived from a caller string. Both providers use
real existing transports. Python import/file checks do not establish runtime
credential isolation; production custody/enforcement remains an external gate.
## Whole disposable source-server proof
Tests run the actual Access `serve` binary built from the owner source, with its
real Ed25519 signing implementation and enforce-mode TokenReview client. A local
synthetic reviewer independently admits only the explicitly fixed service token,
principal/audience and expiry. This is not actual Kubernetes identity proof.
Signing keys are generated in private temporary files; the public key and real
policy digest are independently installed in the Secrets trust file. The policy
digest comes from an owner-local actual source CLI before any network response.
The positive policy is a separately named local synthetic exact-descriptor Rego
fixture with a real deny fixture and Rego test. It never edits or enables the
actual task policy. The actual proposed service task package is exercised unchanged
and returns genuine signed DENY. There is no fabricated DecisionEnvelope or
model-only approval. Real Approval WSGI/SQLite plus distinct independently admitted
synthetic service/human identities create, approve, consume and serve the object.
The strict Secrets module uses its actual mandatory producer-type signature verifier,
retained request/claim/envelope and one-shot strict CAS, followed by the independent
Approval GET and real disposable OpenBao grant/token/metadata/cleanup requests.
Tests also prove actual independent read-scope denial after successful consume:
the durable approval is consumed, Platform remains unknown with pending read intent,
no target native objects exist and reinvocation cannot consume again. The native
journal is checked for known synthetic token leakage. A source purpose substitution
refuses before authorization/CAS, and a missing strict module refuses before any
credentials. Actual-policy denial leaves the approval approved and journal empty.
All identity, policy/registry admission, source-bundle/baseline digests and grant
approval in these tests are synthetic fixture inputs. These tests do not admit an
estate caller, real grant, production transport or actual protected custody.
## Remaining production work
Adopt/publish the exact strict Secrets dependency and this owner seam together;
admit the existing task-execution-grant source projection and actual identity,
policy package, provider origin/custody and complete source revisions. The current
actual policy remains hard-closed. Finish target CCR immutable semantics, total
native expected-state normalization/conflict control, CCR38 provenance, actual
per-call served-time/use enforcement, audit/outbox and protected uncertain/crash
recovery. Then obtain and execute the exact founder-scoped attended trial.
Approval replay prevention and uncertain native-effect reconciliation remain
separate guarantees. T12, Secrets WP13 and native adoption stay open.

View file

@ -231,6 +231,21 @@ class Journal:
return {"state": row[3], "evidence_digest": row[4], "dispatch_allowed": False,
"external_outcome_unknown": bool(pending)}
def next_call_ordinal(self, binding: Binding):
"""Continue the same admitted invocation after owner auth/consume calls.
This never grants dispatch or resumes a persisted admission. The actual
before_call transaction remains the final serialization/intent guard.
"""
if not self._held or self._admission != binding:
raise Refused("next call requires same live admission")
count,pending=self.db.execute("SELECT COUNT(*),COALESCE(SUM(outcome='pending'),0) FROM calls WHERE operation=?",(binding.operation_id,)).fetchone()
cleanup=self.db.execute("SELECT COUNT(*) FROM cleanup WHERE operation=? AND outcome!='owed'",(binding.operation_id,)).fetchone()[0]
state=self.db.execute("SELECT state FROM operations WHERE operation=?",(binding.operation_id,)).fetchone()[0]
if pending or cleanup or state in {'failed','unknown','cleanup-confirmed'} or count>63:
raise Refused("call sequence is uncertain, closed or exhausted")
return count
def before_call(self, binding: Binding, ordinal: int, call_digest: str):
"""Persist one exact plan-call intent before the mediator issues it.

View file

@ -0,0 +1,180 @@
"""Owner mediator seam for the existing strict Secrets handoff and Approval GET.
Only the disposable NativeFixtureAdapter is callable here. No production backend,
caller-supplied authorizer/transport, approval boolean or portable receipt exists.
The strict Secrets module is an explicit external dependency: absence refuses
before credential-bearing requests or native effects, never a permissive fallback.
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime,timezone
import importlib
import json
from pathlib import Path
from urllib.parse import urlsplit
from task_execution_cleanup import run_cleanup
from task_execution_journal import Binding,Cleanup,Journal,Refused
from task_execution_plan import Compiler,encoded,content_hash
from task_execution_native_fixture import FixtureAdmission,NativeFixtureAdapter
@dataclass(frozen=True)
class ConfirmationConfig:
"""Owner-installed independent read credential/route, never request fields."""
origin: str
token_file: Path
timeout_seconds: float = 3
_HANDOFF_FIELDS={'execution_contract','approval_id','request_digest','decision_id',
'native_binding','approval_binding_digest','submitted_request_digest',
'decision_not_before','decision_expires_at','approval_expires_at'}
def _strict_dependency():
try:
module=importlib.import_module('secrets_engine.task_execution_handoff')
for name in ['TaskExecutionAuthorization','TaskExecutionConsumption',
'authorize_task_execution','consume_task_execution']:
if not hasattr(module,name):raise ImportError()
return module
except ImportError:
raise Refused('strict Secrets task execution handoff dependency unavailable') from None
def _fresh(cfg,handoff,descriptor):
from secrets_engine.application_time import read_window,validity_bounds
lower,upper=validity_bounds(window=read_window(cfg))
try:
parse=lambda value:datetime.fromisoformat(value.replace('Z','+00:00'))
deadline=parse(descriptor['operation_deadline'])
approval=parse(handoff['approval_expires_at']);decision=parse(handoff['decision_expires_at'])
start=parse(handoff['decision_not_before']) if handoff['decision_not_before'] else None
if any(value.tzinfo is None for value in [deadline,approval,decision]) or (start is not None and start.tzinfo is None):raise ValueError()
if upper>=min(deadline,approval,decision) or deadline>min(approval,decision) or (start is not None and lower<start):raise ValueError()
except (KeyError,TypeError,ValueError,AttributeError):
raise Refused('original task authority deadline refused') from None
def _intent(journal,binding,kind,fields):
digest=content_hash(encoded({'kind':kind,**fields}))
ordinal=journal.next_call_ordinal(binding)
journal.before_call(binding,ordinal,digest)
return ordinal,digest
def _unknown(journal,binding):
state=journal.observe(binding)['state']
if state not in {'unknown','failed','cleanup-confirmed'}:
journal.transition(binding,state,'unknown')
def run_native_fixture_task(*,compiler:Compiler,journal:Journal,plan_request:dict,
owner_descriptor:bytes,secrets_cfg,entry,
confirmation:ConfirmationConfig,
native_admission:FixtureAdmission):
"""Authorize inside owner boundary, reserve, consume once, independently GET.
Strict authorization is executed here through the actual Secrets-owned module;
an inbound TaskExecutionAuthorization or arbitrary callable is never accepted.
This function returns closed metadata, not tokens or raw approval/decision data.
Positive execution requires the module's real signed PDP path; actual unadmitted
Access policy must still deny. Fixture policy/identity admission is independent
synthetic setup and cannot become production acceptance.
"""
strict=_strict_dependency()
from approval_engine.execution_confirmation import ExecutionConfirmationClient
from secrets_engine.execution_contract import ExecutionContract
if type(confirmation) is not ConfirmationConfig or type(native_admission) is not FixtureAdmission:
raise Refused('independent owner provider configuration required')
try:
origin=urlsplit(confirmation.origin)
if origin.scheme not in {'http','https'} or origin.hostname!='127.0.0.1' or not origin.port or origin.username or origin.password or origin.path or origin.query or origin.fragment:
raise ValueError()
if confirmation.origin!=str(getattr(secrets_cfg,'approval_url','')).rstrip('/'):
raise ValueError()
descriptor=ExecutionContract.parse(json.loads(owner_descriptor)).as_dict()
if encoded(descriptor)!=owner_descriptor or native_admission.descriptor!=owner_descriptor:
raise ValueError()
except Exception:
raise Refused('exact owner descriptor or provider route refused') from None
# An independently pinned owner catalogue must match every engine field. Its
# approval IDs are source references, never runtime authority.
proposal=compiler.proposal()
target={key:getattr(entry,key) for key in proposal['catalog_target']}
if encoded(target)!=encoded(proposal['catalog_target']) or entry.id!=proposal['catalog_id'] or entry.stage!='prod':
raise Refused('owner catalogue does not match strict task request')
snapshot={path:compiler.read(Path(path)) for path in compiler.pins}
owner_entry=compiler._catalogue_entry(snapshot)
# Only the served approval pointer is added after issue. Purpose or other
# source approval semantics cannot be substituted through an inbound entry.
without_reference=lambda value:{key:item for key,item in value.items() if key!='authorization_id'}
if encoded(without_reference(entry.approval))!=encoded(without_reference(owner_entry.approval)):
raise Refused('owner approval metadata differs from source')
client=ExecutionConfirmationClient(confirmation.origin,confirmation.token_file,
timeout_seconds=confirmation.timeout_seconds)
with journal.locked():
authorization=strict.authorize_task_execution(secrets_cfg,entry,
execution_contract=ExecutionContract.parse(descriptor))
if type(authorization) is not strict.TaskExecutionAuthorization:
raise Refused('strict task authorization missing')
handoff=authorization.as_owner_handoff()
if type(handoff) is not dict or set(handoff)!=_HANDOFF_FIELDS or encoded(handoff['execution_contract'])!=owner_descriptor:
raise Refused('strict task handoff does not match owner descriptor')
_fresh(secrets_cfg,handoff,descriptor)
request=dict(plan_request,request_digest=handoff['request_digest'])
plan=compiler.bind_execution(compiler.compile(request),descriptor,owner_descriptor)
binding=Binding(handoff['approval_id'],handoff['request_digest'],descriptor['operation_id'],plan.content_digest)
# Constructor validates fixed native origin/fixture process/grant sources
# but performs no native HTTP request or credential acquisition.
native=NativeFixtureAdapter(compiler,plan,journal,binding,native_admission)
journal.reserve(binding,native.cleanup)
fields={key:handoff[key] for key in ['approval_id','request_digest','decision_id']}
try:
ordinal,digest=_intent(journal,binding,'strict-secrets-task-consume',fields)
consumed=strict.consume_task_execution(secrets_cfg,authorization)
if type(consumed) is not strict.TaskExecutionConsumption:
raise Refused('strict task consumption missing')
receipt={key:getattr(consumed,key) for key in ['approval_id','request_digest','decision_id','consumed_at','idempotent']}
if any(receipt[key]!=value for key,value in fields.items()) or receipt['idempotent'] is not False:
raise Refused('historical or mismatched task consumption refused')
stamp=datetime.fromisoformat(receipt['consumed_at'].replace('Z','+00:00'))
if stamp.tzinfo is None:raise Refused('consumption timestamp missing')
journal.after_call(binding,ordinal,digest,content_hash(encoded(receipt)))
_fresh(secrets_cfg,handoff,descriptor)
ordinal,digest=_intent(journal,binding,'independent-approval-consumption-read',fields)
confirmed=client.confirm_consumption(binding.approval_id,binding.request_digest,
handoff['decision_id'],expected_binding=handoff['native_binding'],
expected_pdp_digest=handoff['approval_binding_digest'])
if confirmed!={key:receipt[key] for key in ['approval_id','request_digest','decision_id','consumed_at']}:
raise Refused('independent consumption correspondence refused')
journal.after_call(binding,ordinal,digest,content_hash(encoded(confirmed)))
_fresh(secrets_cfg,handoff,descriptor)
journal.transition(binding,'reserved','consume-confirmed',content_hash(encoded(confirmed)))
except Exception:
_unknown(journal,binding)
raise Refused('task consumption or independent confirmation unconfirmed; no native execution') from None
result={'operation_id':binding.operation_id,'request_digest':binding.request_digest,
'decision_id':handoff['decision_id'],'native_apply':'unverified',
'native_calls_completed':0,'cleanup_confirmed':False}
try:
journal.transition(binding,'consume-confirmed','authenticating')
# Fixture identity is independently seeded synthetic setup, not CCR38
# provenance proof or a production service login.
journal.transition(binding,'authenticating','grant-issuing')
native.materialize_grant()
journal.transition(binding,'grant-issued','applying')
for ordinal in range(6):
_fresh(secrets_cfg,handoff,descriptor)
native.metadata_call(ordinal)
result['native_calls_completed']+=1
except Exception:
_unknown(journal,binding)
result['native_apply']='unknown'
finally:
result['cleanup_confirmed']=run_cleanup(journal,binding,native)['confirmed']
# Native total expected-state normalization/acceptance remains explicitly
# absent. Six successful calls cannot be relabelled a verified owner trial.
result['business_state']=journal.observe(binding)['state']
return result

View file

@ -122,8 +122,8 @@ class NativeFixtureAdapter:
self.used+=1
evidence_payload = encoded({'token':'owner-retained-task-token'}) if path=='auth/token/lookup' else payload
digest=content_hash(encoded({'method':method,'path':path,'payload_sha256':'sha256:'+content_hash(evidence_payload),'credential_slot':'task' if task else 'owner'}))
ordinal=self._ordinal
self.journal.before_call(self.binding,ordinal,digest);self._ordinal+=1
ordinal=self.journal.next_call_ordinal(self.binding)
self.journal.before_call(self.binding,ordinal,digest);self._ordinal=ordinal+1
try: status,data=self._http(method,path,token,payload)
except Exception:
state=self.journal.observe(self.binding)['state']

View file

@ -0,0 +1,206 @@
"""Real Approval/Access servers; every admission/key/identity is synthetic local.
The positive fixture policy is separately named and exact-descriptor scoped. It
never edits either existing unadmitted production task policy or their false gate.
"""
import base64
from contextlib import contextmanager
from dataclasses import replace
from datetime import datetime,timedelta,timezone
import hashlib
from http.client import HTTPConnection
from http.server import BaseHTTPRequestHandler,ThreadingHTTPServer
import json
import os
from pathlib import Path
import shutil
import socket
import subprocess
import threading
import time
from types import SimpleNamespace
from wsgiref.simple_server import make_server,WSGIRequestHandler
from cryptography import x509
from cryptography.hazmat.primitives import serialization,hashes
from cryptography.hazmat.primitives.asymmetric import ed25519,rsa
from cryptography.x509.oid import NameOID
ACCESS=Path(os.environ.get('ACCESS_ENGINE_SOURCE_ROOT','/home/worsch/access-engine'))
APPROVAL=Path(os.environ.get('APPROVAL_ENGINE_SOURCE_ROOT','/home/worsch/approval-engine'))
SECRETS=Path(os.environ.get('SECRETS_ENGINE_SOURCE_ROOT','/home/worsch/secrets-engine'))
FIXTURE_PACKAGE='platform.disposable-task-seam.fixture'
FIXTURE_VERSION='v1'
PRINCIPAL='system:serviceaccount:secrets-engine:secrets-engine'
def private(path,text):path.write_text(text);path.chmod(0o600);return path
def free_port():
with socket.socket() as sock:sock.bind(('127.0.0.1',0));return sock.getsockname()[1]
def http(origin,method,path,body=None,token=None):
from urllib.parse import urlsplit
parsed=urlsplit(origin);conn=HTTPConnection(parsed.hostname,parsed.port,timeout=4)
try:
headers={'Content-Type':'application/json'}
if token is not None:headers['Authorization']='Bearer '+token
conn.request(method,path,body=json.dumps(body) if body is not None else None,headers=headers)
response=conn.getresponse();raw=response.read(1024*1024)
return response.status,json.loads(raw) if raw else {}
finally:conn.close()
class QuietWSGI(WSGIRequestHandler):
def log_message(self,*args):pass
@contextmanager
def approval_server(directory):
from approval_engine.api import App
from approval_engine.auth import Identity,StaticTokenAuthenticator
from approval_engine.store import Engine
service='synthetic-source-service';human='synthetic-source-human';no_read='synthetic-source-no-read'
def identity(subject,kind,scopes):
return Identity(subject,'https://synthetic.invalid',('approval-engine',),kind,'tenant:platform',
frozenset(),frozenset(scopes),{'level':'aal2','methods':['synthetic']},
'fixture:synthetic-identity',tenant_source='directory' if kind=='human' else 'registration')
identities={service:identity('secrets-engine','service',['approval:create','approval:read','approval:consume']),
human:identity('synthetic-founder','human',['approval:approve','approval:read']),
no_read:identity('platform-fixture-confirmation','service',['approval:consume'])}
engine=Engine(str(directory/'approval.sqlite'));app=App(engine,StaticTokenAuthenticator(identities))
calls=[]
def logged(environ,start_response):
calls.append((environ['REQUEST_METHOD'],environ['PATH_INFO']))
return app(environ,start_response)
server=make_server('127.0.0.1',0,logged,handler_class=QuietWSGI)
thread=threading.Thread(target=server.serve_forever,daemon=True);thread.start()
try:
yield SimpleNamespace(origin='http://127.0.0.1:'+str(server.server_port),engine=engine,
service_token=service,human_token=human,no_read_token=no_read,calls=calls)
finally:server.shutdown();server.server_close();thread.join(5);engine.close()
@contextmanager
def reviewer_server(directory):
# Actual Access TokenReview client consumes this independently admitted
# synthetic reviewer. This is not a Kubernetes authentication proof.
exp=int(time.time())+900
payload=base64.urlsafe_b64encode(json.dumps({'exp':exp}).encode()).decode().rstrip('=')
token='synthetic.'+payload+'.synthetic';reviewer='synthetic-reviewer';calls=[]
class Handler(BaseHTTPRequestHandler):
def log_message(self,*args):pass
def do_POST(self):
size=int(self.headers.get('Content-Length','0'));data=json.loads(self.rfile.read(size))
valid=(self.path=='/apis/authentication.k8s.io/v1/tokenreviews'
and self.headers.get('Authorization')=='Bearer '+reviewer
and data.get('spec',{}).get('token')==token
and 'flex-auth' in data.get('spec',{}).get('audiences',[]))
calls.append(valid)
result={'apiVersion':'authentication.k8s.io/v1','kind':'TokenReview',
'status':{'authenticated':valid,'audiences':['flex-auth'],
'user':{'username':PRINCIPAL}}}
raw=json.dumps(result).encode();self.send_response(201)
self.send_header('Content-Type','application/json');self.send_header('Content-Length',str(len(raw)));self.end_headers();self.wfile.write(raw)
server=ThreadingHTTPServer(('127.0.0.1',0),Handler);thread=threading.Thread(target=server.serve_forever,daemon=True);thread.start()
# The actual reviewer constructor requires a valid CA even for its explicitly
# synthetic HTTP endpoint; this CA never trusts an estate endpoint.
key=rsa.generate_private_key(public_exponent=65537,key_size=2048)
name=x509.Name([x509.NameAttribute(NameOID.COMMON_NAME,'synthetic-local-reviewer')])
now=datetime.now(timezone.utc)
cert=x509.CertificateBuilder().subject_name(name).issuer_name(name).public_key(key.public_key()).serial_number(x509.random_serial_number()).not_valid_before(now-timedelta(minutes=1)).not_valid_after(now+timedelta(days=1)).sign(key,hashes.SHA256())
ca=directory/'fixture-ca.pem';ca.write_bytes(cert.public_bytes(serialization.Encoding.PEM))
reviewer_file=private(directory/'reviewer.token',reviewer)
try:yield SimpleNamespace(origin='http://127.0.0.1:'+str(server.server_port),caller_token=token,reviewer_file=reviewer_file,ca=ca,calls=calls)
finally:server.shutdown();server.server_close();thread.join(5)
def fixture_policy(directory,descriptor,request):
policy=directory/'fixture-policy.md'
fixture=directory/'fixture-cases.json'
fixture.write_text(json.dumps([{'id':'synthetic-claim-free-deny','request':request,
'expect':{'effect':'deny','reason':'fixture_unapproved'}}]))
document='''---
id: platform.disposable-task-seam.fixture
name: Disposable exact task seam fixture
namespace: secrets-engine:secret-catalog-lane
version: v1
status: proposed
package: fixture.platform.task_seam
allow_ttl: 5m
actions: [execute-ccr]
owner: team:synthetic-fixture
fixtures: [fixture-cases.json]
caring: {profile: caring-0.4.0-rc2, enforce: false}
activation: {mode: local}
---
Synthetic local policy only. No production task policy is edited or enabled.
```rego
default decision := {"effect":"deny","reason":"fixture_unapproved"}
decision := {"effect":"allow","reason":"synthetic_exact_task_approved"} {
input.action == "execute-ccr"
input.tenant == "tenant:platform"
input.subject.id == "secrets-engine"
input.subject.type == "service"
input.resource.system == "secrets-engine"
input.context.human_control == true
input.context.approval.valid_now == true
input.context.approval.consumed == false
input.context.approval.binding.human_control == true
input.context.execution_contract == DESCRIPTOR
}
```
''' + '''
```rego test
import data.fixture.platform.task_seam
test_missing_approval_denies { task_seam.decision.effect == "deny" with input as {} }
```
'''
document=document.replace('DESCRIPTOR',json.dumps(descriptor,separators=(',',':')))
policy.write_text(document)
return policy
@contextmanager
def access_server(directory,descriptor,request,reviewer,*,actual_policy=False):
binary=Path(os.environ.get('PLATFORM_ACCESS_FIXTURE_BINARY','/tmp/netkingdom-platform-wave4-access'))
verifier=Path(os.environ.get('PLATFORM_PDP_FIXTURE_VERIFIER','/tmp/netkingdom-platform-wave4-verify'))
if not binary.is_file() or not verifier.is_file():raise RuntimeError('build source fixture binaries first')
registry=directory/'registry.json';registry.write_bytes((ACCESS/'examples/secrets-engine/registry_snapshot.json').read_bytes())
policy=ACCESS/'examples/secrets-engine-service-task-execution/policy_package.md' if actual_policy else fixture_policy(directory,descriptor,request)
requestfile=directory/'claim-free-request.json';requestfile.write_text(json.dumps(request))
# Trusted owner-local source CLI derives the real package pin independently
# from the network responder. Its DENY is used only as digest provenance.
offline=subprocess.run([str(binary),'check','--registry',str(registry),'--policy',str(policy),'--request',str(requestfile)],capture_output=True,text=True,timeout=15)
if offline.returncode!=0:raise RuntimeError('source policy fixture invalid: '+offline.stderr[:300])
produced=json.loads(offline.stdout);provenance=produced['provenance']
key=ed25519.Ed25519PrivateKey.generate()
seed=key.private_bytes(serialization.Encoding.Raw,serialization.PrivateFormat.Raw,serialization.NoEncryption())
public=key.public_key().public_bytes(serialization.Encoding.Raw,serialization.PublicFormat.Raw)
b64=lambda value:base64.urlsafe_b64encode(value).decode().rstrip('=')
seedfile=private(directory/'signing.seed',b64(seed))
trust={name:provenance[name] for name in ['evaluator','mode','policy_package','policy_version','policy_package_digest']}
trust.update(schema='secrets-engine.pdp-trust.v1',keys={'synthetic-owner-key':b64(public)})
trustfile=directory/'pdp-trust.json';trustfile.write_text(json.dumps(trust))
port=free_port();origin='http://127.0.0.1:'+str(port)
args=[str(binary),'serve','--addr','127.0.0.1:'+str(port),'--registry',str(registry),'--policy',str(policy),
'--envelope-signing-key-file',str(seedfile),'--envelope-signing-kid','synthetic-owner-key',
'--caller-auth-mode','enforce','--caller-audience','flex-auth','--caller-kubernetes-url',reviewer.origin,
'--caller-reviewer-token-file',str(reviewer.reviewer_file),'--caller-ca-file',str(reviewer.ca),
'--caller-binding','secrets-engine='+PRINCIPAL]
process=subprocess.Popen(args,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
for _ in range(100):
if process.poll() is not None:raise RuntimeError('source Access server exited')
try:
with socket.create_connection(('127.0.0.1',port),timeout=.1):break
except OSError:time.sleep(.05)
else:process.kill();process.wait();raise RuntimeError('source Access server failed to start')
try:yield SimpleNamespace(origin=origin,trustfile=trustfile,verifier=verifier,
package=provenance['policy_package'],version=provenance['policy_version'],
process=process,offline_envelope=produced)
finally:
process.terminate()
try:process.wait(timeout=5)
except subprocess.TimeoutExpired:process.kill();process.wait()

View file

@ -0,0 +1,32 @@
"""Durable CAS/confirmation call prefix cannot overlap native call ordinals."""
import os
from pathlib import Path
import sys
import uuid
import pytest
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'scripts'))
from task_execution_journal import Binding,Cleanup,Journal,Refused
def test_next_call_continues_auth_prefix_without_replay_or_resume(tmp_path):
os.chmod(tmp_path,0o700);journal=Journal(tmp_path)
binding=Binding('fixture-approval','sha256:'+'a'*64,str(uuid.uuid4()),'b'*64)
try:
with pytest.raises(Refused):journal.next_call_ordinal(binding)
with journal.locked():
journal.reserve(binding,(Cleanup('task-token-revoke','c'*64),))
assert journal.next_call_ordinal(binding)==0
for ordinal in [0,1]:
journal.before_call(binding,ordinal,'d'*64)
with pytest.raises(Refused):journal.next_call_ordinal(binding)
journal.after_call(binding,ordinal,'d'*64,'e'*64)
assert journal.next_call_ordinal(binding)==2
journal.transition(binding,'reserved','consume-confirmed')
journal.before_call(binding,2,'f'*64)
with pytest.raises(Refused):journal.before_call(binding,0,'f'*64)
journal.after_call(binding,2,'f'*64,'e'*64)
journal.before_cleanup(binding,0,Cleanup('task-token-revoke','c'*64))
with pytest.raises(Refused):journal.next_call_ordinal(binding)
with journal.locked():
with pytest.raises(Refused):journal.next_call_ordinal(binding)
finally:journal.close()

View file

@ -0,0 +1,160 @@
"""Whole source-server/native fixture proof, never production owner acceptance."""
from contextlib import contextmanager
from dataclasses import replace
import importlib
import json
from pathlib import Path
import sys
from types import SimpleNamespace
import uuid
import pytest
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'scripts'))
from test_task_execution_native_fixture import owner,bao_dev,compiler
from task_execution_mediator import ConfirmationConfig,run_native_fixture_task
from task_execution_journal import Refused
from task_execution_source_servers import approval_server,reviewer_server,access_server,http,private
from secrets_engine.approval_consume import _request_purpose
from secrets_engine.approval_claim import binding_from_check_request
from secrets_engine.authorization import build_action_request
from secrets_engine.decision_check import check_decision
from secrets_engine.execution_contract import ExecutionContract
@contextmanager
def whole_fixture(owner,tmp_path,*,actual_policy=False,confirmation_read=True):
native,journal,binding,call,compiler,descriptor=owner
snapshot={path:compiler.read(Path(path)) for path in compiler.pins}
entry=compiler._catalogue_entry(snapshot)
approval_id=str(uuid.uuid4())
entry=replace(entry,approval={**entry.approval,'authorization_id':approval_id})
request=build_action_request(entry,'execute-ccr',subject_id='secrets-engine',subject_type='service',
purpose=_request_purpose(entry),execution_contract=ExecutionContract.parse(descriptor))
with reviewer_server(tmp_path) as reviewer, access_server(tmp_path,descriptor,request,reviewer,actual_policy=actual_policy) as access, approval_server(tmp_path) as approval:
issue=access.offline_envelope
body={'id':approval_id,'binding':binding_from_check_request(issue['binding']),
'pdp_digest':issue['binding']['request_digest'],'pdp_path':True,'human_control':True,
'validity':{'not_before':'2026-01-01T00:00:00+00:00',
'expires_at':reviewer_expiry()}}
status,obj=http(approval.origin,'POST','/v1/approvals',body,approval.service_token)
assert status==201
assert http(approval.origin,'POST','/v1/approvals/'+approval_id+'/entries',{},approval.human_token)[0]==200
approval_token=private(tmp_path/'approval.token',approval.service_token)
pdp_token=private(tmp_path/'pdp.token',reviewer.caller_token)
confirmation_token=private(tmp_path/'confirmation.token',approval.service_token if confirmation_read else approval.no_read_token)
cfg=SimpleNamespace(approval_url=approval.origin,approval_token_file=approval_token,
approval_client_secret_file=None,pdp_url=access.origin,pdp_token_file=pdp_token,
pdp_trust_file=access.trustfile,pdp_verifier=access.verifier,
authorization_subject_id='secrets-engine',authorization_subject_type='service',
authorization_policy_package=access.package,authorization_policy_version=access.version,
clock_trust_file=None)
yield SimpleNamespace(native=native,journal=journal,call=call,compiler=compiler,
descriptor=descriptor,entry=entry,cfg=cfg,approval=approval,
confirmation=ConfirmationConfig(approval.origin,confirmation_token),
approval_id=approval_id,request=request,reviewer=reviewer)
def reviewer_expiry():
from datetime import datetime,timedelta,timezone
return (datetime.now(timezone.utc)+timedelta(minutes=10)).isoformat()
def invoke(fixture):
return run_native_fixture_task(compiler=fixture.compiler,journal=fixture.journal,
plan_request=fixture.native.meta['request'],owner_descriptor=fixture.native.admission.descriptor,
secrets_cfg=fixture.cfg,entry=fixture.entry,confirmation=fixture.confirmation,
native_admission=fixture.native.admission)
def test_real_source_servers_signed_fixture_allow_and_actual_task_policy_deny(owner,tmp_path):
# These two Checks test real source servers and independently installed keys;
# they are not a fabricated DecisionEnvelope or activation of a real policy.
for actual_policy in [False,True]:
directory=tmp_path/('actual-policy' if actual_policy else 'fixture-policy');directory.mkdir()
with whole_fixture(owner,directory,actual_policy=actual_policy) as fixture:
status,claim=http(fixture.approval.origin,'GET','/v1/approvals/'+fixture.approval_id+'/claim',token=fixture.approval.service_token)
assert status==200
request=json.loads(json.dumps(fixture.request));request['context']['approval']=claim
envelope=check_decision(base_url=fixture.cfg.pdp_url,token_file=fixture.cfg.pdp_token_file,request=request,
trust_file=fixture.cfg.pdp_trust_file,verifier=fixture.cfg.pdp_verifier)
assert envelope['effect']==('deny' if actual_policy else 'allow')
assert envelope['provenance']['caller']['mode']=='enforce'
assert all(fixture.reviewer.calls)
assert fixture.approval.engine.get(fixture.approval_id).status=='approved'
assert fixture.call('GET','sys/policies/acl/'+fixture.native.policy_name)[0]==404
def test_missing_strict_dependency_never_reads_credentials_or_reserves(monkeypatch):
original=importlib.import_module
def missing(name,*args,**kwargs):
if name=='secrets_engine.task_execution_handoff':raise ImportError()
return original(name,*args,**kwargs)
monkeypatch.setattr(importlib,'import_module',missing)
with pytest.raises(Refused,match='dependency unavailable'):
run_native_fixture_task(compiler=None,journal=None,plan_request={},owner_descriptor=b'',
secrets_cfg=None,entry=None,confirmation=None,native_admission=None)
def test_whole_strict_consume_confirmation_precedes_real_native_effect(owner,tmp_path):
with whole_fixture(owner,tmp_path) as fixture:
result=invoke(fixture)
assert result['native_calls_completed']==6 and result['cleanup_confirmed']
assert result['native_apply']=='unverified' # total owner baseline/readback acceptance remains separate
obj=fixture.approval.engine.get(fixture.approval_id)
assert obj.status=='consumed'
assert obj.consumed_digest==result['request_digest']
calls=fixture.journal.db.execute('SELECT ordinal,outcome FROM calls ORDER BY ordinal').fetchall()
assert calls[:2]==[(0,'complete'),(1,'complete')]
assert len(calls)==13 # CAS + GET + five native grant calls + six metadata calls
assert fixture.approval.calls.count(('POST','/v1/approvals/'+fixture.approval_id+'/consume'))==1
assert fixture.approval.calls.count(('GET','/v1/approvals/'+fixture.approval_id))==1
assert fixture.call('GET','sys/policies/acl/'+fixture.native.policy_name)[0]==404
raw=(fixture.journal.directory/'journal.sqlite').read_bytes()
for token in [fixture.native.admission.owner_token,fixture.native.admission.identity_session.token,
fixture.approval.service_token,fixture.reviewer.caller_token]:
assert token.encode() not in raw
with pytest.raises(Exception):invoke(fixture)
assert fixture.approval.calls.count(('POST','/v1/approvals/'+fixture.approval_id+'/consume'))==1
def test_actual_confirmation_read_scope_denial_keeps_native_untouched(owner,tmp_path):
with whole_fixture(owner,tmp_path,confirmation_read=False) as fixture:
with pytest.raises(Refused,match='confirmation unconfirmed'):invoke(fixture)
assert fixture.approval.engine.get(fixture.approval_id).status=='consumed'
state=fixture.journal.db.execute('SELECT state FROM operations').fetchone()[0]
assert state=='unknown'
assert fixture.journal.db.execute("SELECT COUNT(*) FROM calls WHERE outcome='pending'").fetchone()[0]==1
assert fixture.call('GET','sys/policies/acl/'+fixture.native.policy_name)[0]==404
policy_path=fixture.compiler.before_call(fixture.native.plan,1).path
assert fixture.call('GET',policy_path)[0]==404
with pytest.raises(Exception):invoke(fixture)
assert fixture.approval.calls.count(('POST','/v1/approvals/'+fixture.approval_id+'/consume'))==1
def test_actual_unadmitted_policy_refuses_before_cas_and_native(owner,tmp_path):
with whole_fixture(owner,tmp_path,actual_policy=True) as fixture:
with pytest.raises(Exception):invoke(fixture)
assert fixture.approval.engine.get(fixture.approval_id).status=='approved'
assert not any(method=='POST' and path.endswith('/consume') for method,path in fixture.approval.calls)
assert fixture.journal.db.execute('SELECT COUNT(*) FROM operations').fetchone()[0]==0
assert fixture.call('GET','sys/policies/acl/'+fixture.native.policy_name)[0]==404
def test_entry_purpose_substitution_refuses_before_authorizer_or_cas(owner,tmp_path):
with whole_fixture(owner,tmp_path) as fixture:
fixture.entry=replace(fixture.entry,approval={**fixture.entry.approval,'purpose':'caller-substituted-purpose'})
before=list(fixture.approval.calls)
with pytest.raises(Refused,match='approval metadata differs'):invoke(fixture)
assert fixture.approval.calls==before
assert fixture.journal.db.execute('SELECT COUNT(*) FROM operations').fetchone()[0]==0
assert fixture.call('GET','sys/policies/acl/'+fixture.native.policy_name)[0]==404
def test_catalogue_bool_integer_alias_refuses_before_authorizer(owner,tmp_path):
with whole_fixture(owner,tmp_path) as fixture:
assert fixture.entry.delivery_auth['secret_id_num_uses']==1
fixture.entry=replace(fixture.entry,delivery_auth={**fixture.entry.delivery_auth,'secret_id_num_uses':True})
before=list(fixture.approval.calls)
with pytest.raises(Refused,match='catalogue does not match'):invoke(fixture)
assert fixture.approval.calls==before
assert fixture.journal.db.execute('SELECT COUNT(*) FROM operations').fetchone()[0]==0

View file

@ -1262,3 +1262,18 @@ bodies before a native fixture can materialize. Proposed source records gain no
execution authority; no real grant, policy or legacy applier registration added.
Details and remaining production gates: docs/task-execution-grant-projection.md.
T12 remains progress; no owner sync or production effect performed by this package.
2026-10-16 T12 fourth source package: connected the Secrets-owned strict task
handoff to actual Approval ExecutionConfirmationClient independent GET before
consume-confirmed/native fixture work. Platform accepts no supplied authorization
boolean/object/callback and preserves its exact owner descriptor/grant/Plan join.
Durable CAS/GET intents precede native ordinals through the repaired journal
prefix API. Actual source-server fixture uses signed Access/enforced synthetic
TokenReview, real Approval WSGI/SQLite with distinct synthetic human/service
identities, actual strict Secrets signature/CAS validation and disposable native
OpenBao. Untouched actual task policy remains signed DENY; separately named
synthetic fixture policy is never production admission. Read-scope denial after
CAS records consumed/unknown with zero native effects. Exact dependency/source
hashes, tests and remaining gates are retained with the source package and in
docs/task-execution-mediator-seam.md. No real grant/custody, policy default, owner
sync or native production acceptance is performed; T12 stays progress.