facetted-interfaces/history/FIAM_v0.2_Draft6/tools/security_coverage_lens.py
tegwick 1353267569 Establish FIAM repository governance baseline
Assistant: codex
Assistant-Model: gpt-5.6-luna
Assistant-Session: 01a087b0-7b1e-7531-8ef3-6525ebaf7ee7
2026-09-09 21:53:43 +02:00

35 lines
2.6 KiB
Python
Executable file

#!/usr/bin/env python3
"""Project declared OpenAPI security requirements into practical operation coverage."""
from __future__ import annotations
import argparse
from pathlib import Path
import yaml
def execute(doc):
op_contract={};ops={}
for c in doc.get('contracts',[]) or []:
for o in c.get('operations',[]) or []:ops[o['id']]=o;op_contract[o['id']]=c['id']
profiles=doc.get('security',[]) or [];by_target={}
for p in profiles:by_target.setdefault(p.get('applies_to'),[]).append(p)
override={}
for a in doc.get('assertions',[]) or []:
if a.get('assertion_kind')=='property' and a.get('predicate')=='fiam.property.security-override' and a.get('polarity')=='asserted':override[a.get('subject')]=a.get('value')
rows=[]
for oid in sorted(ops):
own=by_target.get(oid,[]);globalp=by_target.get(op_contract.get(oid),[]);ov=override.get(oid)
if ov=='none':status='explicitly-unprotected';effective=[]
elif ov=='anonymous-alternative':status='anonymous-access-allowed';effective=own if own else globalp
elif own:status='operation-specific';effective=own
elif globalp:status='inherited-contract-security';effective=globalp
else:status='no-declared-security';effective=[]
alternatives={}
for p in effective:
alt=(p.get('facets') or {}).get('requirement_alternative',1);alternatives.setdefault(alt,[]).append({'profile':p['id'],'authentication':p.get('authentication'),'scheme':(p.get('facets') or {}).get('openapi_security_scheme'),'scopes':(p.get('facets') or {}).get('required_scopes',[])})
rows.append({'operation_ref':oid,'contract_ref':op_contract.get(oid),'classification':status,'alternatives':[{'alternative':k,'all_of':v} for k,v in sorted(alternatives.items())],'runtime_observability':'not-inferred-from-generic-OTLP'})
summary={}
for r in rows:summary[r['classification']]=summary.get(r['classification'],0)+1
return {'lens':'fiam.lens.security-coverage','model':doc.get('instance',{}).get('id'),'summary':dict(sorted(summary.items())),'operations':rows,'note':'Generic OTLP does not prove authentication presence/absence; this lens reports declared coverage only unless an explicit security telemetry source is added.'}
def main():
ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('model',type=Path);ap.add_argument('-o','--output',type=Path,required=True);args=ap.parse_args();r=execute(yaml.safe_load(args.model.read_text()));args.output.write_text(yaml.safe_dump(r,sort_keys=False,allow_unicode=True,width=120));print(yaml.safe_dump(r['summary'],sort_keys=False).strip())
if __name__=='__main__':main()