Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
197 lines
12 KiB
Python
197 lines
12 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, AUTH_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': AUTH_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=AUTH_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':AUTH_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=AUTH_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)); 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)); 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)); 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=AUTH_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=AUTH_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
|