#!/usr/bin/env python3 """Plan bounded essentials retention; never delete provider objects.""" import argparse from datetime import datetime, timezone import json from pathlib import Path import re NAME=re.compile(r'^forgejo-essentials-(\d{8}T\d{6}Z)\.zip\.age$') DIGEST=re.compile(r'^[0-9a-f]{64}$') RESERVE=2*1024**3 MAX_INCOMING=600*1024**2 def plan(inventory, protected, incoming_bytes, available_bytes, now=None): now=now or datetime.now(timezone.utc) if not protected or not 0now or not DIGEST.fullmatch(item.get('sha256','')) or not etag.startswith('"') or not etag.endswith('"') or any(c in etag for c in '\r\n') or not 0=incoming_bytes+RESERVE else 'insufficient_upload_headroom', 'keep':sorted(keep),'protected':sorted(protected),'delete_candidates':candidates,'ignored':sorted(ignored), 'incoming_bytes':incoming_bytes,'available_bytes':available_bytes,'reserved_bytes':RESERVE, 'upload_before_expiration':True,'provider_mutations':False, 'execution_gate':'Separate owner executor must revalidate ETags, protected recovery receipts and completed replacement before expiration.'} def main(): p=argparse.ArgumentParser(description=__doc__);p.add_argument('--inventory',required=True,type=Path) p.add_argument('--protected',required=True,action='append');p.add_argument('--incoming-bytes',required=True,type=int) p.add_argument('--available-bytes',required=True,type=int);a=p.parse_args() result=plan(json.loads(a.inventory.read_text()),a.protected,a.incoming_bytes,a.available_bytes) print(json.dumps(result,indent=2));return int(result['status']!='ready') if __name__=='__main__': raise SystemExit(main())