feat(execution): prove fixed grant and cleanup against disposable OpenBao
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
parent
69a792c070
commit
99fd21ee37
9 changed files with 720 additions and 9 deletions
|
|
@ -77,6 +77,26 @@ class Call:
|
|||
return content_hash(encoded({'ordinal':self.ordinal,'kind':self.kind,'method':self.method,
|
||||
'path':self.path,'payload_sha256':self.payload_sha256}))
|
||||
|
||||
|
||||
def cleanup_specs(operation_id):
|
||||
"""Deterministic owner cleanup plan; native handles stay in owner memory."""
|
||||
try: need(str(UUID(operation_id)) == operation_id, 'operation_id_invalid')
|
||||
except (ValueError, AttributeError, TypeError): raise Refused('operation_id_invalid') from None
|
||||
policy_name = 'task-exec-' + operation_id
|
||||
specs = []
|
||||
for kind, slot, calls in [
|
||||
('task-token-revoke', 'task', [('POST','auth/token/revoke-self'), ('POST','auth/token/lookup-accessor')]),
|
||||
('identity-token-revoke', 'identity', [('POST','auth/token/revoke-self'), ('POST','auth/token/lookup-accessor')]),
|
||||
('grant-policy-delete', 'owner', [('DELETE','sys/policies/acl/'+policy_name), ('GET','sys/policies/acl/'+policy_name)]),
|
||||
]:
|
||||
value = {'kind':kind, 'credential_slot':slot, 'operation_id':operation_id,
|
||||
'calls':[{'method':method,'path':path} for method,path in calls]}
|
||||
if kind == 'task-token-revoke': value['confirm_not_created_if_no_issue_attempt'] = True
|
||||
if kind == 'grant-policy-delete': value['skip_delete_if_no_create_attempt'] = True
|
||||
value['call_digest'] = content_hash(encoded(value))
|
||||
specs.append(value)
|
||||
return specs
|
||||
|
||||
class Compiler:
|
||||
def __init__(self, config: OwnerConfig):
|
||||
need(type(config) is OwnerConfig,'owner_configuration_required')
|
||||
|
|
@ -232,14 +252,47 @@ class Compiler:
|
|||
return Plan(encoded({'schema':'platform-owner-typed-plan/v1','action':'execute-ccr','operation':'metadata-apply-ccr',
|
||||
'request':request,'catalog_target':expected['catalog_target'],
|
||||
'source_pins':dict(self.pins),'task_token_max_ttl':120,'task_token_max_uses':12,
|
||||
'cleanup_uses_reserved':1}))
|
||||
'cleanup_uses_reserved':1,'cleanup':cleanup_specs(request['operation_id'])}))
|
||||
|
||||
def bind_execution(self, plan, descriptor, owner_descriptor):
|
||||
"""Bind exact engine descriptor to owner plan; no authorization is created.
|
||||
|
||||
owner_descriptor must be installed independently by the owner, never copied
|
||||
from the request. The engine must separately validate its closed schema and
|
||||
full canonical request digest/claim/PDP/consume correspondence.
|
||||
"""
|
||||
need(type(plan) is Plan and type(descriptor) is dict and type(owner_descriptor) is bytes,
|
||||
'independent_owner_descriptor_required')
|
||||
meta=plan.metadata()
|
||||
need(self.compile(meta['request']).serialized == plan.serialized, 'immutable_plan_changed')
|
||||
need(encoded(descriptor) == owner_descriptor, 'owner_descriptor_mismatch')
|
||||
ccr,_,_=self._derive()
|
||||
expected = {'contract_version':'SECRETS-EXEC-20261011-v1',
|
||||
'operation_id':meta['request']['operation_id'],
|
||||
'operation':'metadata-apply-ccr','execution_actor':'service:secrets-engine',
|
||||
'ccr_id':ccr['id'],'catalog_sha256':meta['request']['catalog_sha256'],
|
||||
'operations':meta['request']['operations']}
|
||||
need(all(descriptor.get(k)==v for k,v in expected.items()),'execution_descriptor_plan_mismatch')
|
||||
bound = dict(meta, execution_descriptor=descriptor,
|
||||
execution_descriptor_sha256=tagged(owner_descriptor))
|
||||
# The full descriptor's independently admitted grant immutable digest must
|
||||
# cover these cleanup commitments. No grant schema exists here yet, so this
|
||||
# source binding cannot itself admit a grant/native production execution.
|
||||
return Plan(encoded(bound))
|
||||
|
||||
def before_call(self,plan,ordinal):
|
||||
need(type(plan) is Plan and type(ordinal) is int and 0<=ordinal<6,'fixed_plan_ordinal_required')
|
||||
try: meta=plan.metadata();fresh=self.compile(meta['request'])
|
||||
try:
|
||||
meta=plan.metadata();fresh=self.compile(meta['request'])
|
||||
if 'execution_descriptor' in meta:
|
||||
fresh=self.bind_execution(fresh,meta['execution_descriptor'],encoded(meta['execution_descriptor']))
|
||||
except Refused: raise
|
||||
except BaseException: raise Refused('invalid_plan') from None
|
||||
need(fresh.serialized==plan.serialized,'immutable_plan_changed')
|
||||
# Immediately re-derive owner payload bytes, and reconfirm immutable snapshot after derivation.
|
||||
_,_,calls=self._derive();need(self.compile(meta['request']).serialized==plan.serialized,'immutable_plan_changed')
|
||||
_,_,calls=self._derive()
|
||||
final=self.compile(meta['request'])
|
||||
if 'execution_descriptor' in meta:
|
||||
final=self.bind_execution(final,meta['execution_descriptor'],encoded(meta['execution_descriptor']))
|
||||
need(final.serialized==plan.serialized,'immutable_plan_changed')
|
||||
return calls[ordinal]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue