activity-core/scripts/render_gitops.py
tegwick 68063cc57a
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 20s
Verify domain definition projection against pinned frontend source
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e241-8285-7a63-8c0c-51c9cb824dc3
2026-09-27 15:26:04 +02:00

50 lines
2.7 KiB
Python

"""Render only the reviewed application resource set, excluding jobs and custody."""
import argparse
import hashlib
import json
import re
import urllib.request
from pathlib import Path
import yaml
ROOT=Path(__file__).resolve().parents[1]
MANAGED={
'ConfigMap': ['actcore-runtime-config','actcore-external-activity-definitions','actcore-report-schemas','actcore-ops-service-inventory'],
'Service': ['actcore-api','actcore-worker-metrics'],
'Deployment': ['actcore-api','actcore-worker','actcore-event-router'],
}
class Dumper(yaml.SafeDumper): pass
def strings(d,v): return d.represent_scalar('tag:yaml.org,2002:str',v,style='|' if '\n' in v else None)
Dumper.add_representer(str,strings)
def render():
docs=list(yaml.safe_load_all((ROOT/'k8s/railiance/20-runtime.yaml').read_text()))
selected=[]
for kind,names in MANAGED.items():
for name in names:
matches=[d for d in docs if d and d['kind']==kind and d['metadata']['name']==name]
if len(matches)!=1: raise ValueError(f'expected exactly one {kind}/{name}')
d=matches[0]
if d['metadata'].get('namespace')!='activity-core': raise ValueError('namespace outside grant')
selected.append(d)
return '# Generated by scripts/render_gitops.py; do not edit directly.\n'+'---\n'.join(yaml.dump(d,Dumper=Dumper,sort_keys=False) for d in selected)
def verify_frontend(source_dir=None):
pin=json.loads((ROOT/'k8s/gitops/frontend-source.json').read_text())
names={f'frontend-patterns-{mode}.md' for mode in ('daily','weekly','monthly')}
if pin.get('schema_version')!=1 or pin.get('repository')!='coulomb/frontend-patterns' or set(pin['files'])!=names or not re.fullmatch('[0-9a-f]{40}',pin['revision']):
raise ValueError('invalid frontend source pin')
cm=next(d for d in yaml.safe_load_all(render()) if d['metadata']['name']=='actcore-external-activity-definitions')
for name,digest in pin['files'].items():
if source_dir is None:
url=f"https://forgejo.coulomb.social/coulomb/frontend-patterns/raw/commit/{pin['revision']}/activity-definitions/{name}"
with urllib.request.urlopen(url,timeout=10) as response: body=response.read(32769)
else: body=(Path(source_dir)/name).read_bytes()
if len(body)>32768 or hashlib.sha256(body).hexdigest()!=digest or cm['data'][name].encode()!=body:
raise ValueError('frontend definition projection mismatch: '+name)
if __name__=='__main__':
parser=argparse.ArgumentParser(); parser.add_argument('--check',action='store_true'); parser.add_argument('--verify-frontend',action='store_true'); args=parser.parse_args()
path=ROOT/'k8s/gitops/runtime.yaml'; text=render()
if args.check:
if path.read_text()!=text: raise SystemExit('GitOps projection stale; run scripts/render_gitops.py')
else: path.write_text(text)
if args.verify_frontend: verify_frontend()