from pathlib import Path
import subprocess,sys,json,os,re,importlib.util
R=Path(__file__).resolve().parents[1]; cp=subprocess.run([sys.executable,str(R/'src/static_preflight_q1.py')],cwd=R,text=True,capture_output=True,env={**os.environ,'PYTHONDONTWRITEBYTECODE':'1'}); print(cp.stdout,end=''); m=re.findall(r'(\d+)/(\d+) PASS',cp.stdout); bp,bt=(map(int,m[-1]) if m else (0,1)); checks=[]
def ck(n,v): checks.append((n,bool(v)))
sp=importlib.util.spec_from_file_location('wf',R/'src/webauthn_fixture.py'); wf=importlib.util.module_from_spec(sp); sp.loader.exec_module(wf); b=json.loads((R/'fixture/baseline-webauthn.json').read_text()); g=json.loads((R/'fixture/golden-policy.json').read_text()); req=json.loads((R/'requirements.json').read_text())
ck('model invariants hardened',wf.validate_model_invariants()['pass']); ck('record exact unique',b['record_fields']==wf.EXPECTED_RECORD_FIELDS and len(set(b['record_fields']))==11); ck('positive exact',g['required_positive_paths']==wf.EXPECTED_POSITIVE_PATHS); ck('negative exact',g['required_negative_paths']==wf.EXPECTED_NEGATIVE_PATHS); ck('forbidden exact',g['forbidden_conclusions']==wf.EXPECTED_FORBIDDEN_CONCLUSIONS); ck('transfer exact',g['transfer_context']==wf.EXPECTED_TRANSFER_CONTEXT); ck('approved recovery exact',b['recovery_policy']['approved_paths']==wf.EXPECTED_APPROVED_RECOVERY_PATHS); ck('ttl binding',all(b['challenges'][k]['expires_at']-b['challenges'][k]['issued_at']==120 for k in ['registration','authentication'])); ck('baseline unused',all(b['challenges'][k]['used'] is False for k in ['registration','authentication'])); blank={k:'observed' for k in wf.EXPECTED_RECORD_FIELDS}; blank['Evidence']=' '; ck('blank evidence rejected',wf.validate_evidence_record(blank)['pass'] is False); ck('registration single use',wf.verify_single_use_sequence('registration')['pass']); ck('authentication single use',wf.verify_single_use_sequence('authentication')['pass']); alt=wf.load_baseline(); alt['synthetic_account']['credential_registered']=False; ck('unregistered rejected',wf._verify_ceremony('authentication',model=alt)['classification']=='UNREGISTERED_CREDENTIAL_REJECTED'); ck('unknown credential rejected',wf._verify_ceremony('authentication',credential_id='not-registered')['classification']=='UNKNOWN_CREDENTIAL_REJECTED'); ck('positive recovery accepted',wf.evaluate_recovery('backup_authenticator')['classification']=='RECOVERY_PATH_BOUNDED_ACCEPTABLE'); ck('risk decision required',wf.evaluate_recovery('backup_authenticator',risk_decision_recorded=False)['classification']=='RECOVERY_RISK_DECISION_REQUIRED'); ck('local only',all(req[k] is False for k in ['external_network_required','real_credentials_required','physical_authenticator_required','external_target_required','real_account_required']))
for n,v in checks: print(('PASS' if v else 'FAIL'),n)
p=bp+sum(v for _,v in checks); t=bt+len(checks); print(f'{p}/{t} PASS'); sys.exit(0 if cp.returncode==0 and p==t else 1)
