fix(auth): authenticate producer-signed decisions before authorization
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
tegwick 2026-10-16 07:51:44 +02:00
parent 6bd7129eac
commit c80a944105
30 changed files with 2059 additions and 32 deletions

View file

@ -12,7 +12,7 @@ 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.test_consume_binding_join import _Cfg, _token, _opener, APPROVAL_ID
from tests.authorization_stub import AuthorizationStub
H = 'sha256:' + 'a' * 64
@ -21,7 +21,7 @@ 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'}
raw['approval'] = {'model': 'bootstrap-only', 'authorization_id': APPROVAL_ID, 'purpose': 'metadata-test'}
return validate_entry(raw)
@ -59,7 +59,7 @@ def test_four_builders_preserve_context_and_binding(tmp_path):
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 = 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
@ -76,7 +76,7 @@ def test_four_builders_preserve_context_and_binding(tmp_path):
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,
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,
@ -92,7 +92,7 @@ def test_four_builders_preserve_context_and_binding(tmp_path):
@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=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'
@ -164,7 +164,7 @@ def test_expired_contract_refuses_before_claim(tmp_path):
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 = 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'})
@ -190,8 +190,13 @@ def test_raw_dictionary_and_direct_invalid_type_cannot_bypass_validation():
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=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