#!/usr/bin/env python3 """Freeze a reusable SSH-site plan locally. No network, credentials or ledger writes.""" import argparse import hashlib import json import importlib import sys from pathlib import Path from batch import validate,atomic_json from site_adapter import SiteAdapter def configure(plan,site): allowed={'ops_root','node_root','batch_backup_root','node_backup_root','qa_root','provider_snapshot','exit_registry','ssh_config','preserved_service','formal_socks_port','gateway_containers','client_sha256'} if set(site)-allowed:raise ValueError('Unexpected site configuration fields') library=importlib.import_module('paramiko') if library.__version__!='5.0.0':raise ValueError('Use the reviewed Paramiko 5.0.0 environment') plan=dict(plan,context={**plan['context'],**site}) validate(plan) adapter=SiteAdapter(plan,Path('/private/tmp/dpl-validation-only')) # Creates no directory or connections. adapter.pool.close() base=Path(__file__).resolve().parent plan.pop('command_profile',None) plan['adapter']=[str(Path(sys.executable).resolve()),str(base/'command-adapter.py')] paths=[base/x for x in ('batch.py','site_adapter.py','ssh_pool.py','acceptance.py')]+[Path(site[k]) for k in ('ssh_config','exit_registry')] plan['runtime']={'kind':'ssh-site-v1','python':str(Path(sys.executable).resolve()),'paramiko_version':library.__version__,'files':{str(p):hashlib.sha256(p.read_bytes()).hexdigest() for p in paths}} return plan def main(): p=argparse.ArgumentParser(description=__doc__) for k in ('plan','site','output'):p.add_argument('--'+k,required=True) a=p.parse_args() try: output=Path(a.output) if not output.is_absolute() or output.exists() or output.is_symlink():raise ValueError('New absolute output file required; never mutate a frozen plan') plan=configure(json.loads(Path(a.plan).read_text()),json.loads(Path(a.site).read_text())) atomic_json(output,plan) print(json.dumps({'state':'configured','nodes':len(plan['nodes']),'network':False,'ledger_writes':False})) return 0 except Exception: print(json.dumps({'state':'blocked','reason':'Inspect explicit site paths, registry and plan; no network performed'}));return 2 if __name__=='__main__':raise SystemExit(main())