40-validation/validate-validation-contract.py
#!/usr/bin/env python3
from __future__ import annotations
import argparse, json, os, sys
from pathlib import Path
from evidence_lifecycle import seal_evidence
VALIDATOR_REF="engineering-tools:40-validation/validate-validation-contract.py"
REPOS=["enterprise-architecture","solution-architecture","engineering-platform","engineering-tools","runtime"]
REQUIRED_ARTIFACTS=[
"enterprise-architecture:85-reference-artifacts/reference-model/validation-contract-model.md",
"solution-architecture:98-tests/MVP-001-validation-contract.md",
"engineering-platform:00-overview/VALIDATION_CONTRACT.md",
"engineering-platform:96-documentation/VALIDATION_CONTRACT_EVIDENCE.md",
"engineering-tools:40-validation/VALIDATION_EXECUTION_CONTRACT.md",
"engineering-tools:40-validation/VALIDATION_CONTRACT_VALIDATION.md",
]
REQUIRED_EVIDENCE=[
"runtime:test/reports/validation/artifact-manifests.json",
"runtime:test/reports/validation/build-contract.json",
"runtime:test/reports/validation/deployment-contract.json",
"runtime:test/reports/validation/workspace-contract.json",
]
def atomic_json(path:Path,data:dict)->None:
path.parent.mkdir(parents=True,exist_ok=True); tmp=path.with_suffix(path.suffix+'.tmp')
tmp.write_text(json.dumps(data,indent=2,ensure_ascii=False)+'\n',encoding='utf-8'); os.replace(tmp,path)
def roots(container:Path)->dict[str,Path]:
out={}
for rid in REPOS:
p=container/rid
m=p/'manifest.json'
if not m.is_file(): raise RuntimeError(f'missing repository manifest: {rid}')
d=json.loads(m.read_text()); ident=d.get('artifactName') or d.get('repository',{}).get('id')
if ident!=rid: raise RuntimeError(f'repository identity mismatch: {rid}')
out[rid]=p
return out
def resolve(rs:dict[str,Path],ref:str)->Path:
rid,rel=ref.split(':',1); p=rs[rid]/rel
if not p.is_file(): raise RuntimeError(f'missing required artifact: {ref}')
return p
def evidence_passed(data:dict)->bool:
for key in ('status','result','overallStatus'):
v=data.get(key)
if isinstance(v,str) and v.upper() in {'PASSED','PASS','SUCCESS','SUCCEEDED'}: return True
return data.get('freshness')=='fresh' and data.get('result') not in {'failed','FAILED'}
def main()->None:
ap=argparse.ArgumentParser(); ap.add_argument('repository_roots',type=Path); ap.add_argument('runtime_root',type=Path); ap.add_argument('--work-item',default='KT-0016'); a=ap.parse_args()
container=a.repository_roots.resolve(); rt=a.runtime_root.resolve(); rs=roots(container)
for ref in REQUIRED_ARTIFACTS: resolve(rs,ref)
checks=[]
for ref in REQUIRED_EVIDENCE:
p=resolve(rs,ref); d=json.loads(p.read_text())
ok=evidence_passed(d)
checks.append({'reference':ref,'required':True,'status':'PASSED' if ok else 'FAILED'})
if not ok: raise RuntimeError(f'required validation evidence not successful: {ref}')
manifest={'schemaVersion':'1.0','validationId':a.work_item,'workItem':a.work_item,'chain':'RC-0006','status':'PASSED','subject':'MVP-001 contract realization coverage','repositories':REPOS,'checks':checks,'findings':[],'sourcesModified':False,'deploymentPerformed':False,'promotionPerformed':False}
mp=rt/'test/validations'/a.work_item/'validation-manifest.json'; atomic_json(mp,manifest)
refs=REQUIRED_ARTIFACTS+REQUIRED_EVIDENCE+[f'runtime:test/validations/{a.work_item}/validation-manifest.json']
ev=seal_evidence(manifest,container,VALIDATOR_REF,refs,work_item=a.work_item,chain='RC-0006')
atomic_json(rt/'test/reports/validation/validation-contract.json',ev)
print(json.dumps({'status':'PASSED','chain':'RC-0006','checks':len(checks),'findings':0},indent=2))
if __name__=='__main__':
try: main()
except Exception as exc: print('ERROR: '+str(exc),file=sys.stderr); raise SystemExit(1)