"""Founder admission of the responder trust file (SECRETS-WP-0014-T02).""" import json import os import subprocess import pytest from secrets_engine import founder_admission from secrets_engine.decision_signature import load_trust from secrets_engine.errors import DecisionError from tests.signature_support import PUBLIC, FOUNDER, admit TRUST = {'schema':'secrets-engine.pdp-trust.v1','evaluator':'stub/local','mode':'standalone', 'policy_package':'p','policy_version':'v','policy_package_digest':'sha256:'+'1'*64, 'keys':{'testdata-ed25519':PUBLIC}} @pytest.fixture def trust(tmp_path): path=tmp_path/'pdp-trust.json';path.write_text(json.dumps(TRUST));return path def test_admitted_trust_carries_founder_identity_only(trust): loaded=load_trust(admit(trust)) assert dict(loaded)==TRUST assert loaded.admission['principal']==FOUNDER assert loaded.admission['key_fingerprint'].startswith('SHA256:') assert loaded.admission['namespace']=='secrets-engine-pdp-trust' @pytest.mark.parametrize('change',['unsigned','edited','other-namespace','gexec-namespace','garbage-signature']) def test_unadmitted_trust_refuses(trust,change): if change=='unsigned':pass elif change=='edited': admit(trust);trust.write_text(json.dumps({**TRUST,'keys':{'attacker':PUBLIC}})) elif change=='other-namespace':admit(trust,namespace='secrets-engine-recovery-attempt') elif change=='gexec-namespace':admit(trust,namespace='gexec-approval') else:(trust.parent/(trust.name+'.sig')).write_text('-----BEGIN SSH SIGNATURE-----\nAAAA\n') with pytest.raises(DecisionError):load_trust(trust) def test_key_outside_anchor_refuses(trust,tmp_path): key=tmp_path/'intruder' subprocess.run(['ssh-keygen','-q','-t','ed25519','-N','','-f',str(key)],check=True,timeout=30) with pytest.raises(DecisionError):load_trust(admit(trust,key=key)) def test_runtime_writable_anchor_refuses(trust,monkeypatch,founder_anchor): admit(trust) # The anchor is owned by the test's own uid, so the production rule must refuse. monkeypatch.setattr(founder_admission,'_writable_by_runtime',founder_anchor['real_rule']) assert os.stat(founder_anchor['anchor']).st_uid==os.geteuid()!=0 with pytest.raises(DecisionError):load_trust(trust) def test_group_writable_anchor_refuses(trust,founder_anchor): admit(trust);signers=founder_anchor['anchor']/'allowed_signers' signers.chmod(0o664) try: with pytest.raises(DecisionError):load_trust(trust) finally:signers.chmod(0o644) def test_relocated_anchor_without_signers_refuses(trust,tmp_path,monkeypatch): admit(trust);empty=tmp_path/'empty';empty.mkdir() monkeypatch.setenv('SECRETS_ENGINE_ADMISSION_ANCHOR',str(empty)) with pytest.raises(DecisionError):load_trust(trust)