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)))
b=json.loads((R/'fixture/baseline-policy.json').read_text()); g=json.loads((R/'fixture/golden-policy.json').read_text()); tmpl=json.loads((R/'evidence/Authorization_Decision_Matrix_v1.template.json').read_text()); src=(R/'src/authz_fixture.py').read_text(); fields=['Subject/Role','Resource Scope','Action','Explicit Allow Rule','Default Decision','Enforcement Point','Positive Probe','Negative Probe','Evidence','Residual Policy Question']
ck('subject bindings exact',b['subjects']=={'alice':{'role':'Viewer','workspace_id':'w1'},'bob':{'role':'Editor','workspace_id':'w1'},'carol':{'role':'WorkspaceAdmin','workspace_id':'w1'},'dave':{'role':'Viewer','workspace_id':'w2'}})
ck('resource types exact',{k:v['type'] for k,v in b['resources'].items()}=={'project:p1':'project','file:f1':'file','members:w1':'member_collection','project:p2':'project','file:f2':'file','members:w2':'member_collection'})
ck('record fields exact unique',b['record_fields']==fields and len(set(b['record_fields']))==10)
ck('template fields exact',list(tmpl.keys())[:10]==fields)
ck('bounded objective exact',g['bounded_objective']=='Same-workspace subjects receive only task-required actions; all unmatched or cross-workspace requests are denied at the server policy evaluator.')
ck('negative paths exact',g['required_negative_paths']==['unknown action denied','cross-workspace read denied','Editor member.manage denied'])
ck('forbidden exact',len(g['forbidden_conclusions'])==4 and g['forbidden_conclusions'][2].startswith('RBAC is always') and g['forbidden_conclusions'][3].startswith('A single admin role'))
ck('unknown subject guard',"subject_id not in m['subjects']" in src and 'UNKNOWN_SUBJECT_DENIED' in src)
ck('unknown resource guard',"resource_id not in m['resources']" in src and 'UNKNOWN_RESOURCE_DENIED' in src)
ck('resource action guard',"r.get('type')!=ACTION_RESOURCE_TYPES[action]" in src and 'RESOURCE_ACTION_MISMATCH_DENIED' in src)
ck('scope guard generic',"s['workspace_id']!=r['workspace_id']" in src and "subject_id=='alice'" not in src)
ck('vertical generic',"if action not in perms:" in src and "subject_id!='bob'" not in src)
ck('evidence blank guard',"blank=[x for x in EXPECTED_RECORD_FIELDS" in src)
ck('evidence schema guard','schema_ok=req==EXPECTED_RECORD_FIELDS' in src)
ck('action map complete',all(x in src for x in ["'project.read':'project'","'file.read':'file'","'file.write':'file'","'member.list':'member_collection'","'member.manage':'member_collection'"]))
ck('runtime fixture exists',(R/'src/run_local_lab.py').exists())
ck('no external target',json.loads((R/'requirements.json').read_text())['external_target_required'] is False)
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)
