prj-forgejo-org-refactor/tools/verify_inventory.py
tegwick 660c429838 Prepare org reference inventory and stewardship assignment review
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e782-9f45-7382-afff-77ad665b88ec
2026-09-28 12:42:22 +02:00

37 lines
1.8 KiB
Python

#!/usr/bin/env python3
"""Fail-closed G6 check of literal old paths against an accepted assignment matrix."""
import argparse
import json
def check(inventory, matrix):
blockers=[]
if not inventory.get('g1_complete'):blockers.append('Inventory coverage has not been accepted as complete')
if not matrix.get('approved'):blockers.append('Assignment matrix is not approved')
assignments={r['repository']:r for r in matrix['assignments']}
stale=[]
sources=inventory['local_repositories']+inventory.get('remote_archives',[])
for repo in sources:
for ref in repo['references']:
name=ref['reference'].split('/',1)[1].removesuffix('.git')
row=assignments.get(name)
# Historical matches need explicit disposition, never automatic exemption.
if not row or row.get('proposed_org')!='coulomb':
stale.append({'repo':repo['name'],**ref})
for remote in repo.get('remotes',[]):
path=remote.get('owner_path')
if path and assignments.get(path.split('/',1)[1],{}).get('proposed_org')!='coulomb':
stale.append({'repo':repo['name'],'remote':remote['remote'],'reference':path})
if any(not r.get('proposed_org') for r in matrix['assignments']):blockers.append('Unresolved organization assignments')
return {'clean':not blockers and not stale,'blockers':blockers,'old_path_findings':len(stale)}
def main():
p=argparse.ArgumentParser(description=__doc__)
p.add_argument('--inventory',required=True);p.add_argument('--assignments',required=True)
a=p.parse_args()
result=check(json.load(open(a.inventory)),json.load(open(a.assignments)))
print(json.dumps(result,indent=2))
return 0 if result['clean'] else 1
if __name__=='__main__':raise SystemExit(main())