Assistant: codex Assistant-Model: gpt-5.6-luna Assistant-Session: 01a087b0-7b1e-7531-8ef3-6525ebaf7ee7
35 lines
2.6 KiB
Python
Executable file
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()
|