secrets-engine/tests/test_execution_context.py
tegwick 4dd004a225
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Verify normalized task approval facts and preserve signed source types
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 17:28:03 +02:00

221 lines
14 KiB
Python

"""Source-only builder tests; mocks confer no real grant or principal admission."""
import copy
from dataclasses import replace
import json
from datetime import datetime, timedelta, timezone
import pytest
from secrets_engine.approval_consume import consume_approval, _expected_request, authorize_action, resolve_approval_observation
from secrets_engine.authorization import approval_binding_digest, build_action_request, request_digest
from secrets_engine.catalog import validate_entry
from secrets_engine.errors import DecisionError
from secrets_engine.execution_contract import ExecutionContract, catalog_target_digest
from tests.test_catalog import VALID
from tests.test_consume_binding_join import _Cfg, _token, _opener, APPROVAL_ID
from tests.authorization_stub import AuthorizationStub
H = 'sha256:' + 'a' * 64
def entry():
raw = copy.deepcopy(VALID)
raw['stage'] = 'prod'
raw['approval'] = {'model': 'bootstrap-only', 'authorization_id': APPROVAL_ID, 'purpose': 'metadata-test'}
return validate_entry(raw)
def descriptor(e):
baseline = build_action_request(e, 'apply', subject_id='secrets-engine', subject_type='service', purpose='metadata-test')
return {
'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', 'ccr_immutable_sha256': H, 'execution_grant_ccr_id': 'CCR-2099-0002',
'grant_immutable_sha256': H, 'catalog_sha256': catalog_target_digest(baseline['context']['catalog_target']),
'source_bundle': {name: {'path': '/owner/'+name+'.py', 'sha256': H}
for name in ['engine_dispatcher', 'platform_mediator', 'typed_ccr', 'policy_auth']},
'backend_origin': 'http://127.0.0.1:18200', 'cluster_uid': 'test-estate-not-live',
'operations': [{'method': 'GET', 'path': 'sys/policies/acl/test-policy', 'payload_sha256': H},
{'method': 'PUT', 'path': 'auth/netkingdom/role/test-role', 'payload_sha256': H}],
'operation_deadline': (datetime.now(timezone.utc)+timedelta(seconds=60)).isoformat(),
'backend_budget': {'ttl_seconds': 120, 'uses': 12}, 'expected_before': H, 'expected_after': H,
}
def request(e, contract):
return build_action_request(e, 'execute-ccr', subject_id='secrets-engine', subject_type='service',
purpose='metadata-test', execution_contract=contract)
def served(pdp):
claim = pdp.claim()
claim['binding']['human_control'] = True
return claim
def test_four_builders_preserve_context_and_binding(tmp_path):
e = entry(); raw = descriptor(e); contract = ExecutionContract.parse(raw)
cfg = _Cfg(_token(tmp_path), authorization_subject_id='secrets-engine', authorization_subject_type='service')
expected = request(e, contract)
assert expected['context']['human_control'] is True
assert _expected_request(cfg,e,'execute-ccr',execution_contract=contract) == expected
pdp = AuthorizationStub(approval_id=APPROVAL_ID, package=cfg.authorization_policy_package, version=cfg.authorization_policy_version)
pdp.bind_request(expected); claim = served(pdp)
observed = resolve_approval_observation(cfg,e,'execute-ccr',None,execution_contract=contract,opener=_opener(claim))
assert observed.request['context']['execution_contract'] == raw
assert approval_binding_digest(observed.request) == request_digest(expected)
assert request_digest(observed.request) != request_digest(expected)
submitted=[]
def check(req, timeout=None):
value=json.loads(req.data); submitted.append(value)
return _opener(pdp.decision(value))(req)
authorized = authorize_action(cfg,e,'execute-ccr',execution_contract=contract,opener=_opener(claim),pdp_opener=check)
assert authorized.binding.request_digest == request_digest(submitted[0])
assert submitted[0] == observed.request
from tests.test_approval_consume import _Response
consume_bodies = []
def consume(req, timeout=None):
value = json.loads(req.data); consume_bodies.append(value)
return _Response(200, {'status':'consumed', 'approval_id':APPROVAL_ID,
'request_digest':value['request_digest'], 'decision_id':value['decision_id'],
'consumed_at':datetime.now(timezone.utc).isoformat(), 'idempotent':False})
confirmed = consume_approval(base_url=cfg.approval_url, token_file=cfg.approval_token_file,
binding=authorized.binding, opener=consume)
assert consume_bodies == [{'request_digest':request_digest(submitted[0]), 'decision_id':authorized.decision_id}]
assert confirmed.request_digest != request_digest(expected)
raw['operations'][0]['path']='sys/policies/acl/changed'
observed.request['context']['execution_contract']['source_bundle']['typed_ccr']['path']='/changed.py'
assert contract.as_dict()['operations'][0]['path']=='sys/policies/acl/test-policy'
assert contract.as_dict()['source_bundle']['typed_ccr']['path']=='/owner/typed_ccr.py'
@pytest.mark.parametrize('change', ['operation_id','ccr','grant','source','body','method','path','budget','deadline','state','cluster'])
def test_changed_binding_cannot_use_original_claim(tmp_path,change):
e=entry(); original=descriptor(e); cfg=_Cfg(_token(tmp_path),authorization_subject_id='secrets-engine',authorization_subject_type='service')
pdp=AuthorizationStub(approval_id=APPROVAL_ID,package=cfg.authorization_policy_package,version=cfg.authorization_policy_version)
pdp.bind_request(request(e,ExecutionContract.parse(original))); claim=served(pdp)
changed=copy.deepcopy(original)
if change=='operation_id': changed[change]='775ab8f4-4731-47c8-bd98-342af22885dd'
elif change=='ccr': changed['ccr_immutable_sha256']='sha256:'+'b'*64
elif change=='grant': changed['grant_immutable_sha256']='sha256:'+'b'*64
elif change=='source': changed['source_bundle']['typed_ccr']['sha256']='sha256:'+'b'*64
elif change=='body': changed['operations'][1]['payload_sha256']='sha256:'+'b'*64
elif change=='method': changed['operations'][0]['method']='PUT'
elif change=='path': changed['operations'][0]['path']='sys/policies/acl/changed'
elif change=='budget': changed['backend_budget']['uses']=11
elif change=='deadline': changed['operation_deadline']=(datetime.now(timezone.utc)+timedelta(seconds=50)).isoformat()
elif change=='state': changed['expected_before']='sha256:'+'b'*64
elif change=='cluster': changed['cluster_uid']='different-estate'
typed=ExecutionContract.parse(changed)
assert approval_binding_digest(request(e,typed)) != pdp._pdp_digest
def check(req,timeout=None): return _opener(pdp.decision(json.loads(req.data)))(req)
with pytest.raises(DecisionError,match='digest'):
authorize_action(cfg,e,'execute-ccr',execution_contract=typed,opener=_opener(claim),pdp_opener=check)
@pytest.mark.parametrize('mutation', ['unknown','extra_nested','missing','wrong_actor','boolean_budget','oversize_budget','sibling_endpoint','path_traversal','source_relative','wrong_hash','bad_deadline','method_object'])
def test_closed_schema_refuses(mutation):
raw=descriptor(entry())
if mutation=='unknown': raw['approved']=True
elif mutation=='extra_nested': raw['backend_budget']['renewable']=True
elif mutation=='missing': del raw['source_bundle']['typed_ccr']
elif mutation=='wrong_actor': raw['execution_actor']='user:admin'
elif mutation=='boolean_budget': raw['backend_budget']['uses']=True
elif mutation=='oversize_budget': raw['backend_budget']['ttl_seconds']=121
elif mutation=='sibling_endpoint': raw['operations'][0]['path']='secret/data/x'
elif mutation=='path_traversal': raw['operations'][0]['path']='auth/a/role/../x'
elif mutation=='source_relative': raw['source_bundle']['typed_ccr']['path']='foo.py'
elif mutation=='wrong_hash': raw['expected_after']='unsafe'
elif mutation=='bad_deadline': raw['operation_deadline']='2026-10-11T10:00:00'
elif mutation=='method_object': raw['operations'][0]['method']={}
with pytest.raises(DecisionError): ExecutionContract.parse(raw)
@pytest.mark.parametrize('action', ['apply','rotate','exec','execute-ccr'])
def test_invalid_action_or_absent_contract_refuses_before_claim(tmp_path,action):
e=entry(); cfg=_Cfg(_token(tmp_path),authorization_subject_id='secrets-engine',authorization_subject_type='service'); calls=[]
def fetch(*args,**kwargs): calls.append('claim'); raise AssertionError
contract=None if action=='execute-ccr' else ExecutionContract.parse(descriptor(e))
with pytest.raises(DecisionError):
authorize_action(cfg,e,action,execution_contract=contract,opener=fetch,pdp_opener=fetch)
assert calls==[]
def test_catalog_mismatch_and_unserved_execution_refuse(tmp_path):
e=entry(); typed=ExecutionContract.parse(descriptor(e)); e=replace(e,path='changed/path')
cfg=_Cfg(_token(tmp_path),authorization_subject_id='secrets-engine',authorization_subject_type='service'); calls=[]
with pytest.raises(DecisionError,match='catalog'):
resolve_approval_observation(cfg,e,'execute-ccr',None,execution_contract=typed,opener=lambda *a,**k:calls.append('claim'))
assert not calls
e=entry(); cfg.approval_url=''
with pytest.raises(DecisionError,match='human_control'):
resolve_approval_observation(cfg,e,'execute-ccr',None,execution_contract=ExecutionContract.parse(descriptor(e)))
def test_expired_contract_refuses_before_claim(tmp_path):
e=entry(); raw=descriptor(e); raw['operation_deadline']=(datetime.now(timezone.utc)-timedelta(seconds=1)).isoformat()
cfg=_Cfg(_token(tmp_path),authorization_subject_id='secrets-engine',authorization_subject_type='service'); calls=[]
with pytest.raises(DecisionError,match='expired'):
authorize_action(cfg,e,'execute-ccr',execution_contract=ExecutionContract.parse(raw),opener=lambda *a,**k:calls.append('claim'))
assert not calls
@pytest.mark.parametrize('changed', ['subject', 'purpose', 'catalog', 'tenant', 'stage'])
def test_request_correspondence_changes_refuse_before_authorization(tmp_path, changed):
e = entry(); contract = ExecutionContract.parse(descriptor(e))
cfg = _Cfg(_token(tmp_path),authorization_subject_id='secrets-engine',authorization_subject_type='service')
pdp = AuthorizationStub(approval_id=APPROVAL_ID,package=cfg.authorization_policy_package,version=cfg.authorization_policy_version)
pdp.bind_request(request(e,contract)); claim = served(pdp)
if changed == 'subject': cfg.authorization_subject_id = 'foreign-service'
elif changed == 'purpose': e = replace(e,approval={**e.approval, 'purpose':'different-purpose'})
elif changed == 'catalog': e = replace(e,path='changed/path')
elif changed == 'stage': e = replace(e,stage='test')
calls = []
def check(req,timeout=None):
calls.append('check'); return _opener(pdp.decision(json.loads(req.data)))(req)
with pytest.raises(DecisionError):
if changed == 'tenant':
build_action_request(e,'execute-ccr',subject_id='secrets-engine',subject_type='service',purpose='metadata-test',tenant='tenant:foreign',execution_contract=contract)
else:
authorize_action(cfg,e,'execute-ccr',execution_contract=contract,opener=_opener(claim),pdp_opener=check)
if changed in {'catalog','stage','tenant'}: assert not calls
def test_raw_dictionary_and_direct_invalid_type_cannot_bypass_validation():
e = entry()
with pytest.raises(DecisionError): request(e,descriptor(e))
with pytest.raises(DecisionError): request(e,ExecutionContract('{}'))
def test_deadline_beyond_claim_refuses_before_pdp(tmp_path):
e=entry(); raw=descriptor(e); raw['operation_deadline']=(datetime.now(timezone.utc)+timedelta(hours=2)).isoformat()
contract=ExecutionContract.parse(raw); cfg=_Cfg(_token(tmp_path),authorization_subject_id='secrets-engine',authorization_subject_type='service')
pdp=AuthorizationStub(approval_id=APPROVAL_ID,package=cfg.authorization_policy_package,version=cfg.authorization_policy_version)
pdp.bind_request(request(e,contract)); calls=[]
with pytest.raises(DecisionError,match='exceeds served authority'):
authorize_action(cfg,e,'execute-ccr',execution_contract=contract,opener=_opener(served(pdp)),pdp_opener=lambda *a,**k:calls.append('check'))
assert not calls
# Reuse admitted native producer signing, never bypass responder verification.
from tests.test_consume_binding_join import admitted_native_signer
from tests.signature_support import signature_tools
def test_execution_service_declaration_is_fixed_before_issue():
e=entry();contract=ExecutionContract.parse(descriptor(e))
built=request(e,contract)
assert built['context']['service_actor_binding']=={
'version':'proposed-service-task-caller/v1',
'transport_principal':'system:serviceaccount:secrets-engine:secrets-engine',
'subject_id':'secrets-engine','subject_type':'service','tenant':'tenant:platform'}
assert built['subject']=={'id':'secrets-engine','type':'service','tenant':'tenant:platform'}
assert built['resource']['tenant']=='tenant:platform'
assert 'service_actor_binding' not in build_action_request(e,'apply',subject_id='secrets-engine',subject_type='service',purpose='metadata-test')['context']
@pytest.mark.parametrize('subject_id,subject_type',[('other','service'),('secrets-engine','Human'),('user:alice','Human')])
def test_execution_declaration_cannot_assert_foreign_service(subject_id,subject_type):
e=entry();contract=ExecutionContract.parse(descriptor(e))
with pytest.raises(DecisionError,match='service subject'):
build_action_request(e,'execute-ccr',subject_id=subject_id,subject_type=subject_type,purpose='metadata-test',execution_contract=contract)