feat(execution): bind immutable task grants before native effects
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
parent
4021ca5e79
commit
d042d468df
7 changed files with 460 additions and 7 deletions
|
|
@ -3,6 +3,8 @@
|
|||
These tests do not contact estate OpenBao or claim production owner acceptance.
|
||||
"""
|
||||
import hashlib
|
||||
from dataclasses import replace
|
||||
import yaml
|
||||
import http.client
|
||||
import json
|
||||
import shutil
|
||||
|
|
@ -20,6 +22,7 @@ from test_task_execution_plan import compiler,request,m
|
|||
from task_execution_journal import Binding,Cleanup,Journal,Refused
|
||||
from task_execution_cleanup import run_cleanup
|
||||
from task_execution_native_fixture import FixtureAdmission,NativeFixtureAdapter,PrivateSession
|
||||
import task_execution_grant as grant
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
@ -79,8 +82,29 @@ def owner(compiler,bao_dev,tmp_path):
|
|||
# grant/expected-state digests remain deliberately synthetic owner fixtures.
|
||||
from secrets_engine.execution_contract import ExecutionContract
|
||||
descriptor=ExecutionContract.parse(descriptor).as_dict()
|
||||
# Install an independently pinned synthetic grant source and its pure
|
||||
# validator. No real CCR is written or approved in the owner checkout.
|
||||
grantfile=compiler.config.platform_repo/'credential-change-requests/CCR-FIXTURE-GRANT.yaml'
|
||||
grantfile.write_text('placeholder: true\n')
|
||||
grantcode=Path(grant.__file__).resolve()
|
||||
pins=dict(compiler.config.source_pins)
|
||||
pins.update({str(grantfile):m.tagged(grantfile.read_bytes()),str(grantcode):m.tagged(grantcode.read_bytes())})
|
||||
compiler=m.Compiler(replace(compiler.config,source_pins=tuple(pins.items()),grant_filename=grantfile.name))
|
||||
plan=compiler.compile(req)
|
||||
expected_execution,expected_openbao=compiler.grant_effects(plan,descriptor)
|
||||
record={'id':descriptor['execution_grant_ccr_id'],'kind':'credential-change-request',
|
||||
'schema_version':1,'request_type':'task-execution-grant','title':'Synthetic disposable fixture grant',
|
||||
'status':'approved','created':'2026-10-16','updated':'2026-10-16',
|
||||
'requester':{'agent':'fixture','reason':'Synthetic disposable proof; no founder approval'},
|
||||
'review':{'required':True,'required_approvers':['railiance-platform-owner','secrets-engine-owner','access-engine-owner','approval-engine-owner'],'comments':[]},
|
||||
'target':{'domain':'infotech','tenant':'platform','workload':'secrets-engine','environment':'production','purpose':'Synthetic metadata primitive proof'},
|
||||
'execution':expected_execution,'openbao':expected_openbao,'evidence':{'events':[]}}
|
||||
grantfile.write_text(yaml.safe_dump(record,sort_keys=False))
|
||||
pins[str(grantfile)]=m.tagged(grantfile.read_bytes())
|
||||
compiler=m.Compiler(replace(compiler.config,source_pins=tuple(pins.items())))
|
||||
descriptor['grant_immutable_sha256']=grant.immutable_digest(record)
|
||||
installed=m.encoded(descriptor)
|
||||
plan=compiler.bind_execution(plan,descriptor,installed)
|
||||
plan=compiler.bind_execution(compiler.compile(req),descriptor,installed)
|
||||
binding=Binding('SYNTHETIC-APPROVAL-NOT-PRODUCTION',req['request_digest'],req['operation_id'],plan.content_digest)
|
||||
state=tmp_path/'private-journal';state.mkdir(mode=0o700);journal=Journal(state)
|
||||
admission=FixtureAdmission(installed,root,identity,process)
|
||||
|
|
@ -225,8 +249,62 @@ def test_actual_native_policy_retirement_does_not_prove_failed_token_revoke(owne
|
|||
def test_nonloopback_estate_origin_is_refused_before_native_transport(owner):
|
||||
native,journal,binding,call,compiler,descriptor=owner
|
||||
changed=dict(descriptor,backend_origin='https://estate.invalid:8200')
|
||||
# The owner grant now also binds origin. Build a matching synthetic grant so
|
||||
# this case reaches the adapter's independent nonloopback refusal; ordinary
|
||||
# origin substitution is already refused earlier by the grant join.
|
||||
record=yaml.safe_load(compiler.grant_record.read_text())
|
||||
record['execution'],record['openbao']=compiler.grant_effects(compiler.compile(native.meta['request']),changed)
|
||||
compiler.grant_record.write_text(yaml.safe_dump(record))
|
||||
pins=dict(compiler.config.source_pins);pins[str(compiler.grant_record)]=m.tagged(compiler.grant_record.read_bytes())
|
||||
changed_compiler=m.Compiler(replace(compiler.config,source_pins=tuple(pins.items())))
|
||||
changed['grant_immutable_sha256']=grant.immutable_digest(record)
|
||||
installed=m.encoded(changed)
|
||||
plan=compiler.bind_execution(compiler.compile(native.meta['request']),changed,installed)
|
||||
plan=changed_compiler.bind_execution(changed_compiler.compile(native.meta['request']),changed,installed)
|
||||
changed_binding=Binding(binding.approval_id,binding.request_digest,binding.operation_id,plan.content_digest)
|
||||
admission=FixtureAdmission(installed,native.admission.owner_token,native.admission.identity_session,native.admission.server_process)
|
||||
with pytest.raises(Refused):NativeFixtureAdapter(compiler,plan,journal,changed_binding,admission)
|
||||
with pytest.raises(Refused):NativeFixtureAdapter(changed_compiler,plan,journal,changed_binding,admission)
|
||||
|
||||
|
||||
def test_changed_grant_immutable_join_refuses_before_any_native_grant(owner):
|
||||
native,journal,binding,call,compiler,descriptor=owner
|
||||
changed=dict(descriptor,grant_immutable_sha256='sha256:'+'0'*64)
|
||||
with pytest.raises(m.Refused):compiler.bind_execution(compiler.compile(native.meta['request']),changed,m.encoded(changed))
|
||||
assert call('GET','sys/policies/acl/'+native.policy_name)[0]==404
|
||||
|
||||
|
||||
def test_grant_body_repin_cannot_replace_independently_derived_effects(owner):
|
||||
native,journal,binding,call,compiler,descriptor=owner
|
||||
record=yaml.safe_load(compiler.grant_record.read_text())
|
||||
record['openbao']['policy']['hcl']='path "*" { capabilities = ["sudo"] }'
|
||||
compiler.grant_record.write_text(yaml.safe_dump(record))
|
||||
pins=dict(compiler.config.source_pins);pins[str(compiler.grant_record)]=m.tagged(compiler.grant_record.read_bytes())
|
||||
changed_compiler=m.Compiler(replace(compiler.config,source_pins=tuple(pins.items())))
|
||||
changed_descriptor=dict(descriptor,grant_immutable_sha256=grant.immutable_digest(record))
|
||||
with pytest.raises(m.Refused):changed_compiler.bind_execution(changed_compiler.compile(native.meta['request']),changed_descriptor,m.encoded(changed_descriptor))
|
||||
assert call('GET','sys/policies/acl/'+native.policy_name)[0]==404
|
||||
|
||||
|
||||
def test_proposed_source_grant_never_materializes_even_with_matching_digest(owner):
|
||||
native,journal,binding,call,compiler,descriptor=owner
|
||||
record=yaml.safe_load(compiler.grant_record.read_text());record['status']='proposed'
|
||||
compiler.grant_record.write_text(yaml.safe_dump(record))
|
||||
pins=dict(compiler.config.source_pins);pins[str(compiler.grant_record)]=m.tagged(compiler.grant_record.read_bytes())
|
||||
changed_compiler=m.Compiler(replace(compiler.config,source_pins=tuple(pins.items())))
|
||||
changed_descriptor=dict(descriptor,grant_immutable_sha256=grant.immutable_digest(record))
|
||||
installed=m.encoded(changed_descriptor)
|
||||
plan=changed_compiler.bind_execution(changed_compiler.compile(native.meta['request']),changed_descriptor,installed)
|
||||
changed_binding=Binding(binding.approval_id,binding.request_digest,binding.operation_id,plan.content_digest)
|
||||
admission=FixtureAdmission(installed,native.admission.owner_token,native.admission.identity_session,native.admission.server_process)
|
||||
with pytest.raises(Refused):NativeFixtureAdapter(changed_compiler,plan,journal,changed_binding,admission)
|
||||
assert call('GET','sys/policies/acl/'+native.policy_name)[0]==404
|
||||
|
||||
|
||||
def test_grant_source_drift_after_admission_prevents_protected_effect(owner):
|
||||
native,journal,binding,call,compiler,*_=owner
|
||||
with journal.locked():
|
||||
admit(native,journal,binding)
|
||||
record=yaml.safe_load(compiler.grant_record.read_text());record['execution']['cleanup'][0]['call_digest']='f'*64
|
||||
compiler.grant_record.write_text(yaml.safe_dump(record))
|
||||
with pytest.raises(m.Refused):native.materialize_grant()
|
||||
assert call('GET','sys/policies/acl/'+native.policy_name)[0]==404
|
||||
assert run_cleanup(journal,binding,native)['confirmed']
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue