Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
218 lines
13 KiB
Python
218 lines
13 KiB
Python
"""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
|
|
import os
|
|
import stat
|
|
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,_absolute_budget
|
|
|
|
|
|
@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 _trusted_v2(cfg):
|
|
return (getattr(cfg,'authorization_policy_package',None)=='secrets-engine.task-execution.service-pilot'
|
|
and getattr(cfg,'authorization_policy_version',None)=='v2')
|
|
|
|
|
|
def _read_source_bundle(descriptor):
|
|
# Paths/hash expectations come from independently installed owner_descriptor,
|
|
# never a requester-selected file lookup. No bytes or raw OS errors escape.
|
|
for item in descriptor['source_bundle'].values():
|
|
path=Path(item['path']);fd=None
|
|
try:
|
|
if not path.is_absolute() or path.resolve()!=path:raise ValueError()
|
|
fd=os.open(path,os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK)
|
|
before=os.fstat(fd)
|
|
if not stat.S_ISREG(before.st_mode) or before.st_nlink!=1 or before.st_mode&0o022 or not 0<before.st_size<=1048576:raise ValueError()
|
|
with os.fdopen(fd,'rb',closefd=False) as stream:raw=stream.read(1048577)
|
|
after=os.fstat(fd)
|
|
identity=lambda value:(value.st_dev,value.st_ino,value.st_size,value.st_mtime_ns,value.st_ctime_ns,value.st_mode,value.st_nlink)
|
|
if identity(before)!=identity(after) or len(raw)!=before.st_size or 'sha256:'+content_hash(raw)!=item['sha256']:raise ValueError()
|
|
except Exception:raise Refused('exact owner execution source bundle refused') from None
|
|
finally:
|
|
if fd is not None:os.close(fd)
|
|
|
|
|
|
def _source_bundle(descriptor):
|
|
with _absolute_budget(2):_read_source_bundle(descriptor)
|
|
|
|
|
|
def _fresh(cfg,handoff,descriptor):
|
|
if _trusted_v2(cfg):_source_bundle(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; the retained v1
|
|
Access policy stays DENY-only; actual v2 successor source is separately tested
|
|
through its authenticated caller/fresh-source path without runtime admission. 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
|
|
if _trusted_v2(secrets_cfg):_source_bundle(descriptor)
|
|
# 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')
|
|
_fresh(secrets_cfg,handoff,descriptor)
|
|
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
|
|
result['readback_evidence_digest']=native.verify_metadata()
|
|
result['native_apply']='verified'
|
|
except Exception:
|
|
_unknown(journal,binding)
|
|
result['native_apply']='unknown'
|
|
finally:
|
|
result['cleanup_confirmed']=run_cleanup(journal,binding,native)['confirmed']
|
|
if result['native_apply']=='verified' and result['cleanup_confirmed']:
|
|
journal.transition(binding,'verified','cleanup-confirmed',result['readback_evidence_digest'])
|
|
# Readback and cleanup are independent outcomes; no recovery authority
|
|
# or native compare-and-swap is implied by either fixture result.
|
|
result['business_state']=journal.observe(binding)['state']
|
|
return result
|