39 lines
80 KiB
JSON
39 lines
80 KiB
JSON
{
|
|
"schema_version": 1,
|
|
"channel": "homelab-runtime",
|
|
"command_id": "NEWFI-260920-NEWFDOM-MESSENGERS214-BASE213",
|
|
"status": "OK",
|
|
"rc": 0,
|
|
"host": "pve01",
|
|
"mode": "read-only",
|
|
"component": "newfi-newfdom-messengers214-backupv2-base-release-authority-aware-readonly",
|
|
"started_at_utc": "2026-09-20T02:30:57Z",
|
|
"finished_at_utc": "2026-09-20T02:30:57Z",
|
|
"reference_register_checked": true,
|
|
"reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66",
|
|
"error_register_checked": true,
|
|
"error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0",
|
|
"command_sha256": "65d18e767349b7319c7197b07d4122dae093e606f12244bfd676798e5606e937",
|
|
"duplicate_failed_command_blocked": false,
|
|
"block_reason": null,
|
|
"execution_started": true,
|
|
"change_declared": false,
|
|
"result_contract_valid": true,
|
|
"result_contract_status": null,
|
|
"result_contract_error": null,
|
|
"command_rc": 0,
|
|
"changes_made": false,
|
|
"rollback_started": false,
|
|
"rollback_restored": null,
|
|
"mutation_outcome": "NO_MUTATION",
|
|
"sanitized": true,
|
|
"secrets_included": false,
|
|
"private_addresses_included": false,
|
|
"raw_evidence_retained_locally": true,
|
|
"raw_evidence_sha256": "417d54bc3ee03b085ea2894f80cd2f3c4e8df0652fe89b0f35fa9f5df73e61c3",
|
|
"sanitized_output_sha256": "c2da47960582cda8715a7fd595b714f908f504dd277254ed2b277fdb5c900bf3",
|
|
"output_truncated_in_json": false,
|
|
"full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt",
|
|
"output": "NEWFI213_BEGIN=true\nMODE=read-only\nIMMUTABLE_PLAN_CHECK=PASS\nCHANGES_MADE=false\nMUTATION_OUTCOME=NO_MUTATION\nRUNNER_SHA256=b248a4c32c9cc64e5747e7dce6c7fc0a23f5124a77c71ce72e27a81aceae9d2d\nRUNNER_PIN_MATCH=true\nERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0\nERROR_REGISTER_PIN_MATCH=true\nREFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66\nREFERENCE_PIN_MATCH=true\nWRAPPER_SHA256=5077444065c732451cb84898680f62361b21a24ef9eb4f191253e82ead524ea2\nWRAPPER_PIN_MATCH=true\nOVERLAY_SHA256=ca6876fa9c3b1465b045344a8ad46962de16972c7dadc4ac6257c7d225047793\nOVERLAY_PIN_MATCH=true\nPRODUCTION_ACCEPTANCE_SHA256=708a481f6719ff1ed8d0afec1902650ed36ac631e980611b015419f504f16df0\nPRODUCTION_ACCEPTANCE_PIN_MATCH=true\nAUTHORITY_PIN_MATCH=true\nBACKUP_SOURCE_PIN_MATCH=true\nACCEPTED_RELEASE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1\nBASE_RELEASE=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1\nMATCHING_FILE_COUNT=26\nFILE_1_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/ACCEPTANCE.json\nFILE_1_BYTES=517\nFILE_1_SHA256=904dfccad43b55ad0b53cfbd29fb45fee36fd0fbfa5afa58da5c3cca0ee7153b\nFILE_1_CONTEXT_LINE_COUNT=1\nFILE_1_L1={\"command_id\":\"SUPPORT-260916-INFRA-DR-BACKUPV2-FINAL-REPLACEMENT-PLAN-STABILITY-SCHEMA-RCA-FIX-VALIDATE-PROMOTE-CUTOVER-SEAL-486R1\",\"ct112_manifest_sha256\":\"1ac4f16a54bcdd8b896c9a131abef966d315256aa56da3f83ed0b30845c4fcb0\",\"ct112_payload_bytes\":223875308,\"ct112_payload_sha256\":\"d443b85e76e806830fd9c372d0a09fc5b91ca9c9d35c44fb0ad7968cc996d01d\",\"legacy_ids\":[\"node-pve01\",\"md-relay\",\"spb-ingress\",\"us-netbird\",\"router-netcraze\",\"xf-codevipe\",\"xf-zakrutim\",\"control-bootstrap-v2\"],\"representative_pass\":9,\"schema\":1}\nFILE_2_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/RELEASE_MANIFEST.json\nFILE_2_BYTES=3301\nFILE_2_SHA256=a36dd0db88592ec3d355ef43e6b218da6c9ad649e9ccf8c8f680b96eb23a156e\nFILE_2_CONTEXT_LINE_COUNT=1\nFILE_2_L1={\"files\":{\"ACCEPTANCE.json\":{\"bytes\":517,\"mode\":256,\"sha256\":\"904dfccad43b55ad0b53cfbd29fb45fee36fd0fbfa5afa58da5c3cca0ee7153b\"},\"candidate411/CONTRACT.json\":{\"bytes\":2077,\"mode\":256,\"sha256\":\"a414715f1b91b3701c52073709a80c38218f76e3961618e8af61489211e50c01\"},\"candidate411/PLAN265_REFERENCE.json\":{\"bytes\":7210,\"mode\":256,\"sha256\":\"8d36e82080be93a8c929a9211191fa868166b9e7b6152c4c7689fa52b6720757\"},\"candidate411/PROVENANCE.json\":{\"bytes\":4310,\"mode\":256,\"sha256\":\"303f44dc8e91c8e6a675f9ea406ce4b7532ed98440a9b6807fa593ede9d33254\"},\"candidate411/adapter.py\":{\"bytes\":2989,\"mode\":320,\"sha256\":\"18eb29cef165371b48bcb78e1a456e1939e6eff253787218133162cc89ab9fa3\"},\"candidate411/guest266.py\":{\"bytes\":7385,\"mode\":256,\"sha256\":\"86433bc424d5fa5017c20f7a237c82874b02357a3283660d8a6b0039ef2bc868\"},\"candidate411/large264.py\":{\"bytes\":16514,\"mode\":256,\"sha256\":\"5cc4641fc35e4dd554495a36146da7dbbb7f142d1450e04cc5d3c89678b8497a\"},\"candidate411/nodeplan263.py\":{\"bytes\":4603,\"mode\":256,\"sha256\":\"db5c16ee24d25aa\nFILE_3_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/ct112_handler.py\nFILE_3_BYTES=10955\nFILE_3_SHA256=8cac6e627d5e7abe5d3163cdd24911995a1e3f45c776f9373c2aa68784f5ec6c\nFILE_3_CONTEXT_LINE_COUNT=98\nFILE_3_L1=#!/usr/bin/env python3\nFILE_3_L2=from __future__ import annotations\nFILE_3_L3=import hashlib,json,os,secrets,shutil,stat,subprocess,sys,time\nFILE_3_L4=from pathlib import Path\nFILE_3_L5=ROOT=Path(__file__).resolve().parent\nFILE_3_L6=CAND=ROOT/'candidate411'\nFILE_3_L7=if str(CAND) not in sys.path:sys.path.insert(0,str(CAND))\nFILE_3_L8=import guest266,large264 as large,pve265,pve282,transport261 as t,v2core as core\nFILE_3_L9=CT_ID='guest-pve01-lxc-112'\nFILE_3_L10=PLAN=CAND/'PLAN265_REFERENCE.json'\nFILE_3_L11=PLAN_SHA='8d36e82080be93a8c929a9211191fa868166b9e7b6152c4c7689fa52b6720757'\nFILE_3_L12=RCLONE=Path('/usr/bin/rclone'); RCLONE_SHA='20df3d5eac5d4e187ce638e4216354e7fa6778c3c51f0caf48c48acca9686354'\nFILE_3_L13=RCLONE_CFG=Path('/root/.config/rclone/[SENSITIVE_FILE]')\nFILE_3_L14=BINDING_FP='ed48c1345771c3e0f50db9516f13f26bb66047283e2f883d5df272f15e2282b8'\nFILE_3_L15=VZDUMP=Path('/usr/bin/vzdump'); VZDUMP_SHA='21339d009afd55cb7ec613b64c1f493b2a7dbd18b85b4d712909ef6d6710f4ea'\nFILE_3_L16=ZSTD=Path('/usr/bin/zstd'); ZSTD_SHA='3eb7744cf8fd1ecd46d617098ee870b3e7911fe570ffaba662c1c5b7d6456020'\nFILE_3_L26= p=subprocess.run(argv,stdout=subprocess.PIPE,stderr=subprocess.PIPE,timeout=45,check=False,env=ENV)\nFILE_3_L27= if p.returncode!=0 or len(p.stdout)>4*1024*1024:raise RuntimeError('PVESH_READ_FAILED')\nFILE_3_L28= try:return json.loads(p.stdout.decode('utf-8','strict'))\nFILE_3_L29= except (ValueError,UnicodeError):raise RuntimeError('PVESH_JSON') from None\nFILE_3_L30=\nFILE_3_L31=def _baseline():\nFILE_3_L32= b=t.read_secure(PLAN,1024*1024,private=True)[0]\nFILE_3_L33= if t.sha(b)!=PLAN_SHA:raise RuntimeError('PLAN_REFERENCE_IDENTITY')\nFILE_3_L34= try:return json.loads(b.decode('utf-8','strict'))\nFILE_3_L35= except (ValueError,UnicodeError):raise RuntimeError('PLAN_REFERENCE_JSON') from None\nFILE_3_L36=\nFILE_3_L37=def _defaults():\nFILE_3_L38= p=Path('/etc/vzdump.conf');st=os.stat(p,follow_symlinks=False)\nFILE_3_L100= return {'path':str(path),'sha256':want}\nFILE_3_L101=\nFILE_3_L102=def _private_config():\nFILE_3_L103= b,identity=t.read_secure(RCLONE_CFG,t.MAX_CONFIG_BYTES,private=True)\nFILE_3_L104= text=b.decode('utf-8-sig','strict');entries=core.inventory_from_config(text);binding=t.binding(text)\nFILE_3_L105= if len(entries)!=13 or len({x['account_id'] for x in entries})!=13:raise RuntimeError('RCLONE_INVENTORY')\nFILE_3_L106= if hashlib.sha256(binding.encode()).hexdigest()!=BINDING_FP:raise RuntimeError('RCLONE_BINDING')\nFILE_3_L107= return b,entries,binding\nFILE_3_L108=\nFILE_3_L109=def _write_private(path,data):\nFILE_3_L118=class LazyReader:\nFILE_3_L119= def __init__(self,work,entries,binding,guard,deadline,logical_id):\nFILE_3_L120= self.work=Path(work);self.entries=entries;self.binding=binding;self.guard=guard;self.deadline=deadline;self.logical_id=logical_id\nFILE_3_L121= self.snapshot=self.work/'rclone.snapshot';self.inner=None\nFILE_3_L122= def _ensure(self):\nFILE_3_L123= if self.inner is not None:return self.inner\nFILE_3_L124= b,e,bind=_private_config()\nFILE_3_L125= if e!=self.entries or bind!=self.binding:raise RuntimeError('RCLONE_SEMANTIC_DRIFT')\nFILE_3_L126= _write_private(self.snapshot,b)\nFILE_3_L127= self.inner=large.ReadOnlyLarge(str(RCLONE),self.snapshot,e,bind,self.guard,self.work,self.deadline,self.logical_id)\nFILE_3_L128= return self.inner\nFILE_3_L129= def list_generations(self,*a,**k):return self._ensure().list_generations(*a,**k)\nFILE_3_L130= def get(self,*a,**k):return self._ensure().get(*a,**k)\nFILE_3_L131= def read_stream(self,*a,**k):return self._ensure().read_stream(*a,**k)\nFILE_3_L132= def close(self):\nFILE_3_L135=\nFILE_3_L136=def selftest():\nFILE_3_L137= if _sha(PLAN,1024*1024)!=PLAN_SHA:return False\nFILE_3_L138= for p,h in ((RCLONE,RCLONE_SHA),(VZDUMP,VZDUMP_SHA),(ZSTD,ZSTD_SHA)):\nFILE_3_L139= if _sha(p)!=h:return False\nFILE_3_L140= return True\nFILE_3_L141=\nFILE_3_L142=def run_target(target,state_writer=None):\nFILE_3_L143= if not isinstance(target,dict) or target.get('logical_id')!=CT_ID or target.get('vmid')!=112:return (_ for _ in ()).throw(RuntimeError('CT112_DESCRIPTOR'))\nFILE_3_L144= if _sha(PLAN,1024*1024)!=PLAN_SHA:raise RuntimeError('PLAN_REFERENCE_IDENTITY')\nFILE_3_L145= tools={'vzdump':_tool(VZDUMP,VZDUMP_SHA),'zstd':_tool(ZSTD,ZSTD_SHA)};_tool(RCLONE,RCLONE_SHA)\nFILE_3_L146= pvesh_sha=_sha(PVESH);now=int(time.time());current=_fresh_plan(now);job=_select_live_ct112(current,now)\nFILE_3_L147= expected=job['config_sha256'];mapping=_canonical_host_mapping()\nFILE_3_L148= def producer_guard():\nFILE_3_L153= pve282.live_gate(fresh,str(PVESH),pvesh_sha,expected)\nFILE_3_L154= producer_guard()\nFILE_3_L155= cfg,entries,binding=_private_config()\nFILE_3_L156= generation='V2-'+time.strftime('%Y%m%dT%H%M%SZ',time.gmtime())+'-'+secrets.token_hex(6)\nFILE_3_L157= work=STAGING/('backup-v2-'+generation);work.mkdir(mode=0o700,parents=False,exist_ok=False)\nFILE_3_L158= deadline=time.monotonic()+21600\nFILE_3_L159= def cloud_guard():\nFILE_3_L160= _,e,b=_private_config()\nFILE_3_L161= if e!=entries or b!=binding:raise RuntimeError('RCLONE_SEMANTIC_DRIFT')\nFILE_3_L162= writer=large.CloudLarge(str(RCLONE),RCLONE_CFG,entries,binding,cloud_guard,work/'upload',deadline)\nFILE_3_L163= reader=LazyReader(work/'restore',entries,binding,cloud_guard,deadline,CT_ID)\nFILE_3_L164= def produce(j,w):return pve282.produce(j,w,tools,producer_guard,mapping=mapping,expected_config=expected,seconds=14400,emit=lambda k,v:None)\nFILE_3_L165= def compression(path):\nFILE_3_L166= p=subprocess.run([str(ZSTD),'--test','--quiet','--',str(path)],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=3600,check=False,env=ENV)\nFILE_3_L167= return p.returncode==0\nFILE_3_L168= try:\nFILE_3_L169= r=guest266.run_flow(job,work,entries,writer,reader,produce,producer_guard,cloud_guard,compression,generation,lambda k,v:None)\nFILE_3_L170= reps=r.get('replicas')\nFILE_3_L171= if not isinstance(reps,list) or len(reps)!=2 or len({x.get('account_id') for x in reps})!=2:raise RuntimeError('REPLICA_PHYSICAL_INDEPENDENCE')\nFILE_3_L172= if r.get('archive_cloud_restore_verified') is not True or r.get('local_payload_files_remaining')!=0:raise RuntimeError('CT112_RESTORE_CONTRACT')\nFILE_3_L173= out={**r,'status':'OK','cloud_only_independent_restore_verified':True,'local_payload_files_remaining':0}\nFILE_3_L174= reader.close();shutil.rmtree(work)\nFILE_3_L175= if work.exists():raise RuntimeError('CT112_WORKSPACE_CLEANUP')\nFILE_3_L176= if state_writer is not None:\nFILE_3_L177= state_writer(CT_ID,'SUCCESS',generation=r['generation'],payload_sha256=r['payload_sha256'],manifest_sha256=r['manifest_sha256'],replicas=r['replicas'],green_verified=True)\nFILE_3_L178= return out\nFILE_3_L179= except BaseException:\nFILE_3_L180= try:reader.close()\nFILE_3_L181= except BaseException:pass\nFILE_3_L182= raise\nFILE_4_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/legacy_engine.py\nFILE_4_BYTES=59719\nFILE_4_SHA256=b6e79f087b9f1d21dac4f77a7b46b743299bbb85bc716e80d2ea67c2e038bcd7\nFILE_4_CONTEXT_LINE_COUNT=180\nFILE_4_L1=#!/usr/bin/python3\nFILE_4_L2=import ast, base64, datetime as dt, hashlib, io, json, os, pathlib, random, re, select, shlex, shutil, stat, subprocess, sys, tarfile, tempfile, time\nFILE_4_L3=\nFILE_4_L4=PART_SIZE=536870912\nFILE_4_L5=RESERVE_BYTES=536870912\nFILE_4_L6=STATE_ROOT=pathlib.Path('/var/lib/homelab-backup-v2')\nFILE_4_L7=CONFIG_ROOT=pathlib.Path('/etc/homelab-backup-v2')\nFILE_4_L8=TARGETS_PATH=CONFIG_ROOT/'targets.json'\nFILE_4_L9=WORK_ROOT=pathlib.Path('/mnt/staging/homelab-backup-v2')\nFILE_4_L10=ENGINE_PATH=pathlib.Path('/usr/local/sbin/homelab-backup-v2')\nFILE_4_L11=RCLONE=shutil.which('rclone') or '/usr/bin/rclone'\nFILE_4_L12=SSH=shutil.which('ssh') or '/usr/bin/ssh'\nFILE_4_L13=SCP=shutil.which('scp') or '/usr/bin/scp'\nFILE_4_L14=SSH_KEYSCAN=shutil.which('ssh-keyscan') or '/usr/bin/ssh-keyscan'\nFILE_4_L30=P282_SHA='73c6cb7773eb8e82d1e7ed5ab4733b4afb88f74ae69c09125d0378d6e480e012'\nFILE_4_L31=P265=pathlib.Path('/opt/homelab-backup-v2/releases/pve-producer-265r1/pve265.py')\nFILE_4_L32=P265_SHA='cd2f634414a8e38a3789015aeca5a9b47821f77d7d1fa61dcdbdc866172963be'\nFILE_4_L33=RESULT_CLASSES=('SUCCESS','DEFER','PARTIAL_VALID','FAIL')\nFILE_4_L34=HISTORICAL_RELEASE_GRAPH=[\nFILE_4_L35= (pathlib.Path('/opt/homelab-backup-v2/releases/core-260r1/v2core.py'),'e285bf9a5678d07dcbb90261f9f93e7826ff524e04cfec780bf5a3c4b0dc29f2'),\nFILE_4_L36= (pathlib.Path('/opt/homelab-backup-v2/releases/transport-261r1/transport261.py'),'b9b92f957bf441cb5d1702f4881897328e6c0338f8c3f6d41d27d9a349b37688'),\nFILE_4_L51= pathlib.Path('/opt/homelab-backup-v2/releases/large-cloud-264r1'),\nFILE_4_L52= pathlib.Path('/opt/homelab-backup-v2/releases/stream-263r1'),\nFILE_4_L53= pathlib.Path('/opt/homelab-backup-v2/releases/transport-261r1'),\nFILE_4_L54= pathlib.Path('/opt/homelab-backup-v2/releases/restore-262r1'),\nFILE_4_L55= pathlib.Path('/opt/homelab-backup-v2/releases/core-260r1'),\nFILE_4_L56= pathlib.Path('/opt/homelab-backup-v2/releases/vm-backup-283r1'),\nFILE_4_L57=]\nFILE_4_L58=_HISTORICAL_HELPER = r'''import importlib,importlib.util,json,pathlib,sys\nFILE_4_L59=mode=sys.argv[1]\nFILE_4_L60=if mode=='import_all':\nFILE_4_L61= out={}\nFILE_4_L74='''\nFILE_4_L75=os.umask(0o077)\nFILE_4_L76=\nFILE_4_L77=REMOTES=[\nFILE_4_L78= ('pve01-mail-01-crypt','pve01-mail-01'),('pve01-mail-02-crypt','pve01-mail-02'),('pve01-mail-03-crypt','pve01-mail-03'),('pve01-mail-04-crypt','pve01-mail-04'),('pve01-mail-05-crypt','pve01-mail-05'),\nFILE_4_L79= ('pve02-mail-01-crypt','pve02-mail-01'),('pve02-mail-02-crypt','pve02-mail-02'),('pve02-mail-03-crypt','pve02-mail-03'),('pve02-mail-04-crypt','pve02-mail-04'),\nFILE_4_L80= ('pve03-mail-01-crypt','pve03-mail-01'),('pve03-mail-02-crypt','pve03-mail-02'),('pve03-mail-03-crypt','pve03-mail-03'),('pve03-mail-04-crypt','pve03-mail-04')]\nFILE_4_L81=\nFILE_4_L82=class BackupError(RuntimeError):\nFILE_4_L83= def __init__(self, code, detail=''):\nFILE_4_L102= if not b: break\nFILE_4_L103= h.update(b); n+=len(b)\nFILE_4_L104= if remain is not None: remain-=len(b)\nFILE_4_L105= if length is not None and n!=length: raise BackupError('LOCAL_PART_SHORT_READ')\nFILE_4_L106= return h.hexdigest()\nFILE_4_L107=\nFILE_4_L108=def part_plan(n):\nFILE_4_L109= if not isinstance(n,int) or n<=0: raise BackupError('PAYLOAD_SIZE_INVALID')\nFILE_4_L110= out=[]; off=0; idx=1\nFILE_4_L111= while off<n:\nFILE_4_L112= size=min(PART_SIZE,n-off)\nFILE_4_L113= out.append({'name':f'part-{idx:06d}','offset':off,'bytes':size})\nFILE_4_L114= off+=size; idx+=1\nFILE_4_L115= return out\nFILE_4_L116=\nFILE_4_L117=def select_replicas(rows,payload_bytes,reserve_bytes=RESERVE_BYTES):\nFILE_4_L118= eligible=[]\nFILE_4_L119= for r in rows:\nFILE_4_L120= if not isinstance(r.get('free'),int): continue\nFILE_4_L121= if r['free'] < payload_bytes + reserve_bytes: continue\nFILE_4_L122= eligible.append(dict(r))\nFILE_4_L123= eligible.sort(key=lambda r:(-r['free'],r['physical'],r['crypt']))\nFILE_4_L124= out=[]; phys=set()\nFILE_4_L125= for r in eligible:\nFILE_4_L126= if r['physical'] in phys: continue\nFILE_4_L127= out.append(r); phys.add(r['physical'])\nFILE_4_L128= if len(out)==2: break\nFILE_4_L129= if len(out)!=2: raise BackupError('ALLOCATOR_TWO_DISTINCT_ACCOUNTS_UNAVAILABLE')\nFILE_4_L130= return out\nFILE_4_L131=\nFILE_4_L132=def remote_generation_path(scope,logical_id,generation):\nFILE_4_L133= safe=re.compile(r'^[A-Za-z0-9._-]+$')\nFILE_4_L134= for x in (scope,logical_id,generation):\nFILE_4_L135= if not safe.fullmatch(x): raise BackupError('UNSAFE_CLOUD_COMPONENT')\nFILE_4_L136= return f'homelab-backups/v2/{scope}/{logical_id}/generations/{generation}'\nFILE_4_L137=\nFILE_4_L138=def make_manifest(scope,logical_id,generation,payload_bytes,payload_sha256,parts,replicas,source_meta):\nFILE_4_L139= if len(replicas)!=2 or len({r['physical'] for r in replicas})!=2: raise BackupError('MANIFEST_REPLICA_PHYSICAL_DUPLICATE')\nFILE_4_L140= if not re.fullmatch(r'[0-9a-f]{64}',payload_sha256): raise BackupError('MANIFEST_PAYLOAD_SHA_INVALID')\nFILE_4_L141= if sum(int(p['bytes']) for p in parts)!=payload_bytes: raise BackupError('MANIFEST_PART_TOTAL_MISMATCH')\nFILE_4_L142= return {'schema':2,'scope':scope,'logical_id':logical_id,'generation':generation,'created_at_utc':utcnow(),\nFILE_4_L143= 'payload_bytes':payload_bytes,'payload_sha256':payload_sha256,'part_size':PART_SIZE,'parts':parts,\nFILE_4_L144= 'replicas':[{'crypt':r['crypt'],'physical':r['physical']} for r in replicas],'source_meta':source_meta}\nFILE_4_L145=\nFILE_4_L146=def utcnow(): return dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace('+00:00','Z')\nFILE_4_L147=def epoch(): return int(time.time())\nFILE_4_L225=\nFILE_4_L226=def atomic_write(path,data,mode=0o600):\nFILE_4_L227= path=pathlib.Path(path); ensure_dir(path.parent,0o700)\nFILE_4_L228= fd,tmp=tempfile.mkstemp(prefix='.'+path.name+'.',dir=str(path.parent))\nFILE_4_L229= try:\nFILE_4_L230= with os.fdopen(fd,'wb') as f: f.write(data); f.flush(); os.fsync(f.fileno())\nFILE_4_L231= os.chmod(tmp,mode); os.replace(tmp,path)\nFILE_4_L235=\nFILE_4_L236=def load_targets():\nFILE_4_L237= j=json.loads(TARGETS_PATH.read_text())\nFILE_4_L238= if j.get('schema')!=1 or not isinstance(j.get('targets'),list): raise BackupError('TARGET_MANIFEST_SCHEMA')\nFILE_4_L239= ids=[x.get('logical_id') for x in j['targets']]\nFILE_4_L240= if len(ids)!=len(set(ids)): raise BackupError('TARGET_MANIFEST_DUPLICATE')\nFILE_4_L241= return j['targets']\nFILE_4_L242=\nFILE_4_L243=def load_state_all():\nFILE_4_L257= atomic_write(STATE_ROOT/'state'/(logical_id+'.json'),canonical_json(j)+b'\\n',0o600)\nFILE_4_L258= return j\nFILE_4_L259=\nFILE_4_L260=def rclone_base_args():\nFILE_4_L261= return [RCLONE]\nFILE_4_L262=\nFILE_4_L263=def rclone_about(remote):\nFILE_4_L264= p=run(rclone_base_args()+['about',remote+':','--json','--contimeout','15s','--timeout','45s'],timeout=60)\nFILE_4_L265= try:j=json.loads(p.stdout)\nFILE_4_L266= except Exception: raise BackupError('RCLONE_ABOUT_JSON')\nFILE_4_L267= free=j.get('free')\nFILE_4_L268= if not isinstance(free,int): raise BackupError('RCLONE_FREE_UNKNOWN')\nFILE_4_L269= return free\nFILE_4_L270=\nFILE_4_L271=def allocator(payload_bytes):\nFILE_4_L272= rows=[]; bad=0\nFILE_4_L273= for crypt,physical in REMOTES:\nFILE_4_L274= try: free=rclone_about(crypt)\nFILE_4_L275= except BackupError: bad+=1; continue\nFILE_4_L276= rows.append({'crypt':crypt,'physical':physical,'free':free})\nFILE_4_L277= reps=select_replicas(rows,payload_bytes,RESERVE_BYTES)\nFILE_4_L278= return reps,bad,len(rows)\nFILE_4_L279=\nFILE_4_L280=def remote_exists_any(scope,logical_id,generation):\nFILE_4_L281= rel=remote_generation_path(scope,logical_id,generation)\nFILE_4_L282= for crypt,_physical in REMOTES:\nFILE_4_L283= p=run(rclone_base_args()+['lsf',crypt+':'+rel,'--max-depth','1'],timeout=45,check=False)\nFILE_4_L284= if p.returncode==0 and p.stdout.strip(): return True\nFILE_4_L285= return False\nFILE_4_L286=\nFILE_4_L287=def rclone_rcat(remote_path, source_path=None, offset=0, length=None, data=None, timeout=3600):\nFILE_4_L288= argv=rclone_base_args()+['rcat',remote_path,'--retries','3','--low-level-retries','5','--contimeout','20s','--timeout','5m']\nFILE_4_L289= p=subprocess.Popen(argv,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)\nFILE_4_L290= try:\nFILE_4_L291= if data is not None:\nFILE_4_L304= try:p.kill()\nFILE_4_L305= except Exception:pass\nFILE_4_L306= raise\nFILE_4_L307= if p.returncode!=0: raise BackupError('RCLONE_RCAT_FAILED',str(p.returncode))\nFILE_4_L308=\nFILE_4_L309=def rclone_cat_hash(remote_path, expected_bytes=None, timeout=3600):\nFILE_4_L310= h=hashlib.sha256(); n=0; start=time.time()\nFILE_4_L311= with subprocess.Popen(rclone_base_args()+['cat',remote_path,'--contimeout','20s','--timeout','5m'],stdout=subprocess.PIPE,stderr=subprocess.PIPE) as p:\nFILE_4_L312= while True:\nFILE_4_L313= if time.time()-start>timeout:\nFILE_4_L314= p.kill(); p.wait(); raise BackupError('RCLONE_CAT_TIMEOUT')\nFILE_4_L315= b=p.stdout.read(1024*1024)\nFILE_4_L316= if not b: break\nFILE_4_L317= h.update(b); n+=len(b)\nFILE_4_L318= p.stderr.read(); rc=p.wait()\nFILE_4_L319= if rc!=0: raise BackupError('RCLONE_CAT_FAILED',str(rc))\nFILE_4_L320= if expected_bytes is not None and n!=expected_bytes: raise BackupError('RCLONE_CAT_SIZE_MISMATCH')\nFILE_4_L321= return h.hexdigest(),n\nFILE_4_L322=\nFILE_4_L323=def rclone_cat_bytes(remote_path,max_bytes=4*1024*1024):\nFILE_4_L324= p=run(rclone_base_args()+['cat',remote_path,'--contimeout','20s','--timeout','60s'],timeout=90)\nFILE_4_L325= if len(p.stdout)>max_bytes: raise BackupError('RCLONE_SMALL_OBJECT_TOO_LARGE')\nFILE_4_L326= return p.stdout\nFILE_4_L327=\nFILE_4_L328=def generation_id(logical_id):\nFILE_4_L329= ts=dt.datetime.now(dt.timezone.utc).strftime('%Y%m%dT%H%M%SZ')\nFILE_4_L330= return f'v2-{logical_id}-{ts}-{os.urandom(6).hex()}'\nFILE_4_L331=\nFILE_4_L332=def upload_and_seal(t,payload_path,source_meta):\nFILE_4_L333= payload_path=pathlib.Path(payload_path); n=payload_path.stat().st_size\nFILE_4_L334= psha=sha256_file(payload_path); reps,bad,healthy=allocator(n)\nFILE_4_L335= gen=source_meta['generation']; rel=remote_generation_path(t['scope'],t['logical_id'],gen)\nFILE_4_L336= if remote_exists_any(t['scope'],t['logical_id'],gen): raise BackupError('GENERATION_COLLISION')\nFILE_4_L337= parts=part_plan(n)\nFILE_4_L338= for p in parts: p['sha256']=sha256_file(payload_path,p['offset'],p['bytes'])\nFILE_4_L339= manifest=make_manifest(t['scope'],t['logical_id'],gen,n,psha,parts,reps,source_meta)\nFILE_4_L340= mb=canonical_json(manifest)+b'\\n'; msha=sha256_bytes(mb)\nFILE_4_L341= for rep in reps:\nFILE_4_L342= base=rep['crypt']+':'+rel\nFILE_4_L343= for part in parts:\nFILE_4_L344= rp=base+'/parts/'+part['name']\nFILE_5_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/representative_driver.py\nFILE_5_BYTES=4214\nFILE_5_SHA256=b3050a8f95e6d9826a4f0786cd3ca32012b6ab10486d10e4981b50b8a0affff2\nFILE_5_CONTEXT_LINE_COUNT=60\nFILE_5_L3=\nFILE_5_L4=This module does not discover credentials, modify scheduler state, or implement the\nFILE_5_L5=CT112 producer/cloud path. It routes CT112 to an explicitly supplied callback and\nFILE_5_L6=isolates legacy engine state writes into a candidate-owned state directory.\nFILE_5_L7=\"\"\"\nFILE_5_L8=from __future__ import annotations\nFILE_5_L9=\nFILE_5_L10=import json\nFILE_5_L11=import os\nFILE_5_L12=from pathlib import Path\nFILE_5_L13=from typing import Callable, Iterable, Mapping, Any\nFILE_5_L14=\nFILE_5_L15=LEGACY_IDS=(\nFILE_5_L16= 'node-pve01',\nFILE_5_L24=)\nFILE_5_L25=CT112_ID='guest-pve01-lxc-112'\nFILE_5_L26=REPRESENTATIVE_IDS=(CT112_ID,)+LEGACY_IDS\nFILE_5_L27=CANDIDATE_ROOT=Path(__file__).resolve().parent\nFILE_5_L28=STATE_ROOT=CANDIDATE_ROOT/'state'\nFILE_5_L29=\nFILE_5_L30=class ContractError(RuntimeError):\nFILE_5_L31= pass\nFILE_5_L36= raise ContractError('TARGET_LOGICAL_ID')\nFILE_5_L37= return value\nFILE_5_L38=\nFILE_5_L39=def partition_targets(targets: Iterable[Mapping[str, Any]]):\nFILE_5_L40= selected={}\nFILE_5_L41= wanted=set(REPRESENTATIVE_IDS)\nFILE_5_L42= for target in targets:\nFILE_5_L62= with os.fdopen(fd,'wb',closefd=True) as f:\nFILE_5_L63= f.write(data);f.flush();os.fsync(f.fileno())\nFILE_5_L64= os.replace(tmp,path)\nFILE_5_L65= except BaseException:\nFILE_5_L66= try: os.unlink(tmp)\nFILE_5_L67= except FileNotFoundError: pass\nFILE_5_L68= raise\nFILE_5_L72= def write_state(logical_id,result,**kw):\nFILE_5_L73= if logical_id not in LEGACY_IDS:\nFILE_5_L74= raise ContractError('STATE_TARGET_FORBIDDEN')\nFILE_5_L75= payload={'logical_id':logical_id,'result':result,'meta':kw,'schema_version':1}\nFILE_5_L76= _atomic_json(root/(logical_id+'.json'),payload)\nFILE_5_L77= return write_state\nFILE_5_L78=\nFILE_5_L79=def run_legacy_lane(engine, target: Mapping[str, Any]):\nFILE_5_L97= raise ContractError('CT112_RESULT_SCHEMA')\nFILE_5_L98= if result.get('logical_id')!=CT112_ID or result.get('status')!='OK':\nFILE_5_L99= raise ContractError('CT112_RESULT_STATUS')\nFILE_5_L100= if result.get('cloud_only_independent_restore_verified') is not True:\nFILE_5_L101= raise ContractError('CT112_RESTORE_NOT_VERIFIED')\nFILE_5_L102= if result.get('local_payload_files_remaining')!=0:\nFILE_5_L103= raise ContractError('CT112_LOCAL_PAYLOAD_REMAINS')\nFILE_5_L104= return result\nFILE_5_L105=\nFILE_5_L106=def run_representative(engine, targets, ct112_callback: Callable[[Mapping[str, Any]], Any]):\nFILE_5_L107= if not callable(ct112_callback):\nFILE_5_L108= raise ContractError('CT112_CALLBACK_REQUIRED')\nFILE_5_L109= legacy,ct112=partition_targets(targets)\nFILE_5_L110= results=[_validate_ct112_result(ct112_callback(ct112))]\nFILE_5_L111= for target in legacy:\nFILE_5_L112= results.append(run_legacy_lane(engine,target))\nFILE_6_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/wrapper.py\nFILE_6_BYTES=5055\nFILE_6_SHA256=2b5eb4fc0f6f466a0d3e5a007af987092b6c17baa3ff9241a6afc2c2e97df1d5\nFILE_6_CONTEXT_LINE_COUNT=43\nFILE_6_L1=#!/usr/bin/env python3\nFILE_6_L2=from __future__ import annotations\nFILE_6_L3=import errno,fcntl,importlib.util,os,sys\nFILE_6_L4=from pathlib import Path\nFILE_6_L5=ROOT=Path(__file__).resolve().parent\nFILE_6_L6=CT_ID='guest-pve01-lxc-112'\nFILE_6_L7=LEGACY_IDS=('node-pve01','md-relay','spb-ingress','us-netbird','router-netcraze','xf-codevipe','xf-zakrutim','control-bootstrap-v2')\nFILE_6_L35= 'guest_type':'lxc','due_seconds':due,'enabled':True,'green1':True}\nFILE_6_L36=\nFILE_6_L37=def load_targets():\nFILE_6_L38= base=canonical_targets();return base+[_ct_descriptor(base)]\nFILE_6_L39=\nFILE_6_L40=def backup_target(t,green_verify=False):\nFILE_6_L41= if not isinstance(t,dict) or t.get('logical_id')!=CT_ID:\nFILE_6_L42= return _legacy_backup_target(t,green_verify)\nFILE_6_L43= try:\nFILE_6_L44= r=ct112.run_target(t,state_writer=legacy.write_state)\nFILE_6_L45= return {'logical_id':CT_ID,'generation':r['generation'],'result':'SUCCESS','payload_bytes':r['payload_bytes'],\nFILE_6_L46= 'replicas':2,'manifest_sha256':r['manifest_sha256'],'payload_sha256':r['payload_sha256']}\nFILE_6_L47= except BaseException:\nFILE_6_L48= try: legacy.write_state(CT_ID,'FAIL',reason='CT112_PIPELINE_FAILED')\nFILE_6_L49= except BaseException: pass\nFILE_6_L50= raise legacy.BackupError('CT112_PIPELINE_FAILED') from None\nFILE_6_L51=\nFILE_6_L52=legacy.load_targets=load_targets\nFILE_6_L53=legacy.backup_target=backup_target\nFILE_6_L54=\nFILE_6_L55=def _legacy_reused_boundary_selftest():\nFILE_6_L56= if legacy.PART_SIZE!=536870912: raise RuntimeError('LEGACY_PART_SIZE')\nFILE_6_L57= if len(legacy.REMOTES)!=13 or len({p for _,p in legacy.REMOTES})!=13: raise RuntimeError('LEGACY_REMOTES')\nFILE_6_L58= d=legacy.default_targets()\nFILE_6_L59= if not isinstance(d,list) or len(d)<28: raise RuntimeError('LEGACY_DEFAULT_TARGET_COUNT')\nFILE_6_L60= want={'ct112',*LEGACY_IDS}\nFILE_6_L67=\nFILE_6_L68=def selftest():\nFILE_6_L69= _legacy_reused_boundary_selftest()\nFILE_6_L70= base=canonical_targets(); eff=load_targets()\nFILE_6_L71= if len(eff)!=29 or sum(1 for x in eff if x.get('logical_id')==CT_ID)!=1: raise RuntimeError('EFFECTIVE_TARGETS')\nFILE_6_L72= legacy_rows,ct=driver.partition_targets(eff)\nFILE_6_L73= if [x['logical_id'] for x in legacy_rows]!=list(LEGACY_IDS) or ct.get('vmid')!=112: raise RuntimeError('REPRESENTATIVE_PARTITION')\nFILE_6_L74= if ct112.selftest() is not True: raise RuntimeError('CT112_HANDLER_SELFTEST')\nFILE_6_L75= print('SELFTEST_REPLACEMENT486=PASS',flush=True);return 0\nFILE_6_L76=\nFILE_7_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/CONTRACT.json\nFILE_7_BYTES=2077\nFILE_7_SHA256=a414715f1b91b3701c52073709a80c38218f76e3961618e8af61489211e50c01\nFILE_7_CONTEXT_LINE_COUNT=1\nFILE_7_L1={\"candidate\":\"pve-lxc-adapter-411r1\",\"next_gate\":\"PVE_LXC_REAL_ENVIRONMENT_DRY_RUN\",\"owner\":{\"MappedScratch\":\"pve270\",\"capture_archive\":\"pve270\",\"dump_argv\":\"pve265\",\"pve282.old\":\"pve265\",\"pve282.proven\":\"pve270\",\"validate_mapping\":\"pve270\"},\"schema\":1,\"signatures\":{\"pve265\":{\"dump_argv\":{\"args\":[\"job\",\"executable\",\"tmpdir\",\"now\"],\"defaults\":0,\"kw_defaults\":[],\"kwarg\":null,\"kwonly\":[],\"posonly\":[],\"vararg\":null},\"make_plan\":{\"args\":[\"rows\",\"configs\",\"storage_rows\",\"defaults\",\"staging_free\",\"now\",\"node\"],\"defaults\":1,\"kw_defaults\":[],\"kwarg\":null,\"kwonly\":[],\"posonly\":[],\"vararg\":null},\"produce\":{\"args\":[\"job\",\"work\",\"tools\",\"guard\",\"seconds\"],\"defaults\":1,\"kw_defaults\":[],\"kwarg\":null,\"kwonly\":[],\"posonly\":[],\"vararg\":null},\"validate_job\":{\"args\":[\"job\",\"now\"],\"defaults\":0,\"kw_defaults\":[],\"kwarg\":null,\"kwonly\":[],\"posonly\":[],\"vararg\":null}},\"pve270\":{\"capture_archive\":{\"args\":[\"argv\",\"destination\",\"cap\",\"seconds\",\"check\"],\"defaults\":0,\"kw_defaults\":[],\"kwarg\":null,\"kwonly\":[],\"posonl\nFILE_8_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/PLAN265_REFERENCE.json\nFILE_8_BYTES=7210\nFILE_8_SHA256=8d36e82080be93a8c929a9211191fa868166b9e7b6152c4c7689fa52b6720757\nFILE_8_CONTEXT_LINE_COUNT=1\nFILE_8_L1={\"all_guest_coverage_eligible\":true,\"backup_executed\":false,\"capacity_policy\":\"four archive copies plus 4GiB; capped producer; actual compressed size still unknown\",\"collected_at_utc\":\"2026-09-12T06:57:40.611329+00:00\",\"full_host_coverage\":false,\"global_blockers\":[],\"global_defaults\":{\"blockers\":[],\"keys\":[],\"present\":true,\"sha256\":\"cf34c8e3812547954bb1d08b50212b6e148ee9cf2b629e895a843ed49d623b38\"},\"guest_membership_and_configs_stable\":true,\"jobs\":[{\"application_consistency_verified\":false,\"archive_cap_bytes\":9516036916,\"blockers\":[],\"cdrom_count\":0,\"cdrom_media_included\":false,\"compression_dependent\":false,\"config_sha256\":\"09957aacd41ba9eeaf5fd4eda13936d580c9082a46895433379aa9dd0bad5969\",\"configured_archive_bound_bytes\":9516036916,\"configured_disk_bytes\":8589934592,\"configured_full_cycle_fits\":true,\"coverage_eligible\":true,\"disks\":[{\"backup_setting\":\"included_default_rootfs\",\"class\":\"managed-volume\",\"configured_size_bytes\":8589934592,\"slot\":\"rootfs\",\"storage\":\"local-lvm\"}],\"global_def\nFILE_9_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/PROVENANCE.json\nFILE_9_BYTES=4310\nFILE_9_SHA256=303f44dc8e91c8e6a675f9ea406ce4b7532ed98440a9b6807fa593ede9d33254\nFILE_9_CONTEXT_LINE_COUNT=1\nFILE_9_L1={\"anchors\":{\"SUPPORT-260915-INFRA-DR-BACKUPV2-PVE-LXC-EXACT-CALL-GRAPH-PROOF-401R1\":\"840b3f1e8b023899c0554305a97af2d55dc71cf9\",\"SUPPORT-260915-INFRA-DR-BACKUPV2-PVE-LXC-IMMUTABLE-ADAPTER-CANDIDATE-STAGE-FIXTURE-RCA-FIX-407R1\":\"0261475cdd35d3b762de0a29e46f3acd0b9af229\",\"SUPPORT-260915-INFRA-DR-BACKUPV2-PVE-LXC-IMMUTABLE-ADAPTER-CANDIDATE-STAGE-RCA-FIX-403R1\":\"e3f753ce9cf95e21750e9ad7f9574cafc199b3ce\",\"SUPPORT-260915-INFRA-DR-BACKUPV2-PVE-LXC-PERL270-HISTORICAL-TEST-RCA-404R1\":\"58f61ce62c3b6a57d8c5fc2465d2537d6728f9d5\",\"SUPPORT-260915-INFRA-DR-BACKUPV2-PVE-LXC-PERLPIN-EXEC-FS-RCA-409R1\":\"0db666a5a1f4796b567663adfc5568817e87efa5\",\"SUPPORT-260915-INFRA-DR-BACKUPV2-PVE-LXC-PERLPIN-NEED-TRACE-RCA-408R1\":\"44cdff7dab9e60aff1d69c12d2c32a4b26d04de8\",\"SUPPORT-260915-INFRA-DR-BACKUPV2-PVE-LXC-PERLPIN-PRODUCTION-VS-FIXTURE-RCA-406R1\":\"4c5836ff0ef73cb2ef306857be713383ba5e85f4\",\"SUPPORT-260915-INFRA-DR-BACKUPV2-PVE-LXC-PERLPIN-ROOT-SUITE-STRUCTURED-RCA-410R1\":\"4673bfaf04877370bc4ac02fef37885eb82cb1eb\nFILE_10_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/adapter.py\nFILE_10_BYTES=2989\nFILE_10_SHA256=18eb29cef165371b48bcb78e1a456e1939e6eff253787218133162cc89ab9fa3\nFILE_10_CONTEXT_LINE_COUNT=30\nFILE_10_L1=#!/usr/bin/python3\nFILE_10_L2=import hashlib,inspect,json,pathlib,sys\nFILE_10_L3=BASE=pathlib.Path(__file__).resolve().parent\nFILE_10_L4=EXPECTED={\nFILE_10_L5='v2core.py':'e285bf9a5678d07dcbb90261f9f93e7826ff524e04cfec780bf5a3c4b0dc29f2',\nFILE_10_L6='transport261.py':'b9b92f957bf441cb5d1702f4881897328e6c0338f8c3f6d41d27d9a349b37688',\nFILE_10_L7='restore262.py':'56d1b961c8d5654d5e2ee2755268db46bd2202bca11e69788febf991cfaa79f1',\nFILE_10_L8='stream263.py':'a83d03a86b93a855716658652dd073fcb281cd387fc6200fe4bc2a922f39ea16',\nFILE_10_L9='nodeplan263.py':'db5c16ee24d25aa1694530332d3190ab7cc5d4f8eb69067d025e27ad5c995060',\nFILE_10_L10='large264.py':'5cc4641fc35e4dd554495a36146da7dbbb7f142d1450e04cc5d3c89678b8497a',\nFILE_10_L19= return h.hexdigest()\nFILE_10_L20=def verify_sources():\nFILE_10_L21= for name,want in EXPECTED.items():\nFILE_10_L22= p=BASE/name\nFILE_10_L23= if not p.is_file() or p.is_symlink() or sha(p)!=want:raise RuntimeError('SOURCE_IDENTITY_'+name)\nFILE_10_L24=def load_graph():\nFILE_10_L25= import guest266,pve265,pve270,pve282\nFILE_10_L26= if hasattr(guest266,'dump_argv'):raise RuntimeError('GUEST266_UNEXPECTED_DUMP_ARGV')\nFILE_10_L27= if not hasattr(pve265,'dump_argv'):raise RuntimeError('PVE265_DUMP_ARGV_MISSING')\nFILE_10_L28= if getattr(pve270,'old',None) is not pve265:raise RuntimeError('PVE270_OLD_NOT_PVE265')\nFILE_10_L35=def describe():\nFILE_10_L36= _,p265,p270,p282=load_graph()\nFILE_10_L37= funcs={'pve265.dump_argv':p265.dump_argv,'pve265.validate_job':p265.validate_job,'pve265.make_plan':p265.make_plan,'pve270.validate_mapping':p270.validate_mapping,'pve270.capture_archive':p270.capture_archive,'pve270.produce':p270.produce,'pve282.select112':p282.select112,'pve282.produce':p282.produce}\nFILE_10_L38= return {'schema':1,'bundle':'pve-lxc-adapter-411r1','source_sha256':EXPECTED,'signatures':{k:str(inspect.signature(v)) for k,v in funcs.items()},'owner':{'dump_argv':'pve265','MappedScratch':'pve270','capture_archive':'pve270','validate_mapping':'pve270','pve282.old':'pve265','pve282.proven':'pve270'}}\nFILE_10_L39=def main():\nFILE_10_L40= verify_sources(); mode=sys.argv[1] if len(sys.argv)>1 else 'selftest'; d=describe()\nFILE_10_L41= if mode not in ('selftest','describe'):raise SystemExit(2)\nFILE_10_L42= print(json.dumps(d,sort_keys=True,separators=(',',':')))\nFILE_10_L43= if mode=='selftest':print('ADAPTER_SELFTEST=PASS')\nFILE_10_L44=if __name__=='__main__':main()\nFILE_11_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/guest266.py\nFILE_11_BYTES=7385\nFILE_11_SHA256=86433bc424d5fa5017c20f7a237c82874b02357a3283660d8a6b0039ef2bc868\nFILE_11_CONTEXT_LINE_COUNT=75\nFILE_11_L1=\"\"\"266R1 bounded real-guest orchestration. Import has no side effects.\nFILE_11_L2=\nFILE_11_L3=One small LXC rootfs, no compression-dependent admission. No node-wide approval,\nFILE_11_L4=no guest restore/start/delete, no cloud deletion. Archive CRC/SHA is not boot proof.\nFILE_11_L5=\"\"\"\nFILE_11_L6=import copy,os,time\nFILE_11_L7=from pathlib import Path\nFILE_11_L8=import v2core as core\nFILE_11_L9=import transport261 as t\nFILE_11_L10=import stream263 as stream\nFILE_11_L11=import large264 as large\nFILE_11_L12=import pve265 as producer\nFILE_11_L13=\nFILE_11_L14=MAX_CONFIGURED_BYTES=8*1024**3\nFILE_11_L15=RESERVE_BYTES=536870912\nFILE_11_L25=\nFILE_11_L26=def choose(plan,now):\nFILE_11_L27= rows=plan_rows(plan);t.need(plan.get('global_blockers')==[],'GLOBAL_DEFAULT_BLOCK')\nFILE_11_L28= candidates=[]\nFILE_11_L29= for job in rows:\nFILE_11_L30= if not (job.get('type')=='lxc' and job.get('coverage_eligible') is True and\nFILE_11_L31= job.get('blockers')==[] and job.get('compression_dependent') is False and\nFILE_11_L35= disks[0].get('class')=='managed-volume' and disks[0].get('backup_setting') in ('included','included_default_rootfs')):continue\nFILE_11_L36= n=job.get('configured_disk_bytes')\nFILE_11_L37= if type(n) is not int or not 0<n<=MAX_CONFIGURED_BYTES:continue\nFILE_11_L38= producer.validate_job(job,now);candidates.append(job)\nFILE_11_L39= t.need(bool(candidates),'NO_SMALL_NONCOMPRESSED_DEPENDENT_LXC')\nFILE_11_L40= chosen=min(candidates,key=lambda j:(j['configured_disk_bytes'],j['vmid']))\nFILE_11_L41= stores={s['storage']:s for s in plan.get('storages',[])}\nFILE_11_L42= disk=chosen['disks'][0];st=stores.get(disk['storage'],{})\nFILE_11_L43= t.need(st.get('active') is True and st.get('enabled') is True and st.get('type') in ('lvmthin','zfspool'),'SNAPSHOT_STORAGE_UNAVAILABLE')\nFILE_11_L44= t.need(type(st.get('free_bytes')) is int and st['free_bytes']>=max(1024**3,chosen['configured_disk_bytes']),'SNAPSHOT_HEADROOM_UNPROVEN')\nFILE_11_L45= return copy.deepcopy(chosen)\nFILE_11_L46=\nFILE_11_L47=def same_state(before,after,vmid):\nFILE_11_L48= old=plan_rows(before);new=plan_rows(after)\nFILE_11_L64= if type(task.get('endtime')) is int and task.get('status') not in (None,'RUNNING'):continue\nFILE_11_L65= kind=task['type'];target=str(task.get('id',''))\nFILE_11_L66= if kind in ('vncshell','vncterm','vncproxy','spiceproxy'):continue\nFILE_11_L67= t.need(target!=str(vmid) and not any(x in kind.lower() for x in ('dump','restore','migrat','snapshot','clone','move_disk','resize')),'COMPETING_PVE_TASK')\nFILE_11_L68=\nFILE_11_L69=def check_result(result,job,work):\nFILE_11_L70= t.need(type(result) is dict,'PRODUCER_RESULT_SCHEMA')\nFILE_11_L80= finally:os.close(fd)\nFILE_11_L81= return expected\nFILE_11_L82=\nFILE_11_L83=def run_flow(job,work,entries,cloud,reader,produce,state_guard,guard,compression_check,generation,say,clock=lambda:int(time.time())):\nFILE_11_L84= \"\"\"Caller provides real fresh PVE guards; simulation callbacks live in tests only.\"\"\"\nFILE_11_L85= producer.validate_job(job,clock());core.validate_inventory(entries)\nFILE_11_L86= t.need(job['type']=='lxc' and job.get('compression_dependent') is False,'FIRST_GUEST_POLICY')\nFILE_11_L87= t.need(core.valid_name(generation),'GENERATION_ID')\nFILE_11_L88= t.need(all(callable(f) for f in (produce,state_guard,guard,compression_check,say,clock)),'CALLBACKS_REQUIRED')\nFILE_11_L89= work=Path(work);state_guard();guard()\nFILE_11_L90= for sub in ('producer','upload','restore'):t.make_dir(work/sub,exclusive=True)\nFILE_11_L91= say('PHASE','REAL_SINGLE_GUEST_SNAPSHOT')\nFILE_11_L92= produced=produce(job,work/'producer')\nFILE_11_L93= source=check_result(produced,job,work/'producer');state_guard();guard()\nFILE_11_L94= t.create(work/'PRODUCER.json',core.canonical_bytes(produced))\nFILE_11_L95= say('PRODUCER_RC',0);say('PAYLOAD_BYTES',produced['size']);say('ARCHIVE_SHA256',produced['sha256'])\nFILE_11_L96= logical='guest-%s-%s-%d'%(job['node'],job['type'],job['vmid'])\nFILE_11_L97= say('PHASE','TWO_REPLICA_UPLOAD_AND_READBACK')\nFILE_11_L98= up=large.upload(source,work/'upload',entries,cloud,generation,logical,RESERVE_BYTES,guard,clock=clock)\nFILE_11_L99= t.need(up['manifest']['payload_bytes']==produced['size'] and up['manifest']['payload_sha256']==produced['sha256'],'MANIFEST_PRODUCER_MISMATCH')\nFILE_11_L100= say('SEALED_QUORUM_VERIFIED','YES');mh=core.manifest_hash(up['manifest']);say('MANIFEST_SHA256',mh)\nFILE_11_L101= say('PHASE','CLOUD_DISCOVERY_AND_ARCHIVE_RECONSTRUCTION')\nFILE_11_L102= found=large.discover(reader,entries,logical,mh)\nFILE_11_L103= restored=large.restore(work/'restore',reader,found)\nFILE_11_L104= t.need(compression_check(work/'restore/restored.bin') is True,'RECONSTRUCTED_COMPRESSION_FAILED')\nFILE_11_L105= state_guard();guard();say('PHASE','GUARDED_LOCAL_PAYLOAD_CLEANUP')\nFILE_11_L106= count=large.cleanup(up,restored,reader,guard)\nFILE_11_L107= return {'state':'SINGLE_GUEST_ARCHIVE_SEALED_AND_CLOUD_RECONSTRUCTED','vmid':job['vmid'],'type':job['type'],'node':job['node'],\nFILE_11_L108= 'generation':generation,'logical_id':logical,'manifest_sha256':mh,'payload_bytes':produced['size'],'payload_sha256':produced['sha256'],\nFILE_11_L109= 'replicas':up['manifest']['replicas'],'parts_count':len(up['manifest']['parts']),'archive_cloud_restore_verified':True,\nFILE_11_L110= 'guest_restore_verified':False,'application_consistency_verified':False,'whole_node_backup':False,'local_payload_files_remaining':0,\nFILE_11_L111= 'files_deleted':count,'accounts_scanned':found['accounts_scanned'],'config_sha256':job['config_sha256']}\nFILE_12_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/large264.py\nFILE_12_BYTES=16514\nFILE_12_SHA256=5cc4641fc35e4dd554495a36146da7dbbb7f142d1450e04cc5d3c89678b8497a\nFILE_12_CONTEXT_LINE_COUNT=180\nFILE_12_L1=\"\"\"264R1 streaming cloud adapter and synthetic boundary proof.\nFILE_12_L2=\nFILE_12_L3=No work on import. No guest/backup producer and no cloud deletion. Existing\nFILE_12_L4=small-canary adapters are not modified. Only caller-owned local payload is removed,\nFILE_12_L5=after two cloud seals and a separately cloud-discovered restore have been checked.\nFILE_12_L6=\"\"\"\nFILE_12_L7=import hashlib\nFILE_12_L8=import os\nFILE_12_L9=from pathlib import Path\nFILE_12_L10=import selectors\nFILE_12_L11=import signal\nFILE_12_L12=import subprocess\nFILE_12_L13=import time\nFILE_12_L14=import v2core as core\nFILE_12_L15=import transport261 as t\nFILE_12_L16=import restore262 as r\nFILE_12_L17=import stream263 as s\nFILE_12_L18=\nFILE_12_L19=BOUNDARY_BYTES=536870929\nFILE_12_L20=LOGICAL_ID='stream-canary-pve01'\nFILE_12_L21=\nFILE_12_L22=\nFILE_12_L23=def process_stream(argv,env,size,digest,consume,seconds):\nFILE_12_L24= \"\"\"Drain both pipes, hashing stdout incrementally; never retain the whole part.\"\"\"\nFILE_12_L25= t.need(type(argv) is list and argv and seconds>0,'STREAM_PROCESS_ARGUMENTS')\nFILE_12_L26= sink=s.DigestSink(size,digest)\nFILE_12_L27= p=subprocess.Popen(argv,stdin=subprocess.DEVNULL,stdout=subprocess.PIPE,stderr=subprocess.PIPE,\nFILE_12_L38= remaining=deadline-time.monotonic();t.need(remaining>0,'STREAM_TIMEOUT')\nFILE_12_L39= rc=p.wait(timeout=remaining);t.need(rc==0,'STREAM_PROCESS_RC_FAILED')\nFILE_12_L40= result=sink.finish();complete=True;return result\nFILE_12_L41= except subprocess.TimeoutExpired:raise t.Stop('STREAM_TIMEOUT') from None\nFILE_12_L42= finally:\nFILE_12_L43= if not complete or p.poll() is None:\nFILE_12_L44= try:os.killpg(p.pid,signal.SIGKILL)\nFILE_12_L53= '--cache-dir',str(Path(work)/'cache')]+args\nFILE_12_L54=\nFILE_12_L55=\nFILE_12_L56=class CloudLarge(t.RcloneIO):\nFILE_12_L57= \"\"\"Reuse the existing crypt inventory/namespace guards, not its in-memory payload I/O.\"\"\"\nFILE_12_L58= def call(self,args,limit):\nFILE_12_L59= t.need(type(args) is list and args and args[0] in ('about','lsjson','copyto','cat'),'RCLONE_VERB_FORBIDDEN')\nFILE_12_L60= t.need(type(limit) is int and 0<=limit<=core.MANIFEST_MAX_BYTES+1,'METADATA_BOUND')\nFILE_12_L61= self.check();seconds=min(3600 if args[0]=='copyto' else 90,self.deadline-time.monotonic())\nFILE_12_L62= t.need(seconds>0,'CLOUD_DEADLINE');self.calls+=1\nFILE_12_L63= if args[0]=='copyto':self.writes_attempted+=1\nFILE_12_L64= rc,out=t.bounded_process(flags(self.executable,self.config_path,self.work,args),self.env,limit,seconds)\nFILE_12_L65= self.check();return rc,out\nFILE_12_L66= def put(self,remote,name,path):\nFILE_12_L67= dest=self.address(remote,name)\nFILE_12_L68= if name in ('manifest.json','SEALED.json'):\nFILE_12_L69= return super().put(remote,name,path)\nFILE_12_L70= part=next((p for p in self.manifest['parts'] if p['name']==name),None)\nFILE_12_L71= t.need(part is not None,'PART_NOT_IN_MANIFEST')\nFILE_12_L72= n,h,identity=s.hash_file(path,part['size'])\nFILE_12_L73= t.need(n==part['size'] and h==part['sha256'],'UPLOAD_SOURCE_HASH')\nFILE_12_L74= rc,_=self.call(['lsjson',dest,'--stat'],65536)\nFILE_12_L75= t.need(rc in (3,4),'OBJECT_NOT_PROVEN_ABSENT')\nFILE_12_L76= with s.file_handle(path,part['size']) as (_,size,seen):\nFILE_12_L77= t.need(seen==identity,'UPLOAD_SOURCE_CHANGED')\nFILE_12_L78= rc,_=self.call(['copyto',str(path),dest,'--immutable','--no-update-modtime'],65536)\nFILE_12_L79= t.need(rc==0,'CLOUD_COPY_FAILED')\nFILE_12_L80= def read_stream(self,remote,name,size,digest,consume):\nFILE_12_L81= address=self.address(remote,name)\nFILE_12_L82= part=next((p for p in self.manifest['parts'] if p['name']==name),None)\nFILE_12_L83= t.need(part is not None and part['size']==size and part['sha256']==digest,'READBACK_EXPECTATION')\nFILE_12_L84= self.check();seconds=min(3600,self.deadline-time.monotonic());t.need(seconds>0,'CLOUD_DEADLINE')\nFILE_12_L85= self.calls+=1\nFILE_12_L86= out=process_stream(flags(self.executable,self.config_path,self.work,['cat',address,'--count',str(size+1)]),\nFILE_12_L90=\nFILE_12_L91=class ReadOnlyLarge(r.ReadOnlyCloud):\nFILE_12_L92= \"\"\"Metadata uses inherited bounded reads; this class has no upload API.\"\"\"\nFILE_12_L93= def read_stream(self,remote,generation,name,size,digest,consume):\nFILE_12_L94= t.need(type(size) is int and 0<size<=core.PART_BYTES and core.valid_hash(digest),'READBACK_EXPECTATION')\nFILE_12_L95= t.need(type(name) is str and name.startswith('part-'),'PART_REQUIRED')\nFILE_12_L96= address=self.address(remote,generation,name)\nFILE_12_L97= self.check();seconds=min(3600,self.deadline-time.monotonic());t.need(seconds>0,'RESTORE_DEADLINE')\nFILE_12_L98= self.calls+=1\nFILE_12_L99= out=process_stream(flags(self.executable,self.snapshot,self.work,['cat',address,'--count',str(size+1)]),\nFILE_12_L100= self.env,size,digest,consume,seconds)\nFILE_12_L116=\nFILE_12_L117=\nFILE_12_L118=def receipt(rep,m,whole,count):\nFILE_12_L119= t.need(count==m['payload_bytes'] and whole.hexdigest()==m['payload_sha256'],'PAYLOAD_READBACK_MISMATCH')\nFILE_12_L120= return {**rep,'generation':m['generation'],'manifest_sha256':core.manifest_hash(m),\nFILE_12_L121= 'payload_sha256':whole.hexdigest(),'payload_bytes':count,'parts':m['parts'],\nFILE_12_L122= 'method':'download-sha256','ok':True}\nFILE_12_L123=\nFILE_12_L124=\nFILE_12_L125=def upload(source,work,entries,cloud,generation,logical_id,reserve,guard,clock=lambda:int(time.time())):\nFILE_12_L126= \"\"\"Upload and seal; retain all source bytes here. Cleanup is a later gated operation.\"\"\"\nFILE_12_L127= work=Path(work);source=Path(source);guard();core.validate_inventory(entries)\nFILE_12_L128= t.need(core.valid_name(generation) and core.valid_name(logical_id),'GENERATION_ID')\nFILE_12_L129= partdir=work/'parts';t.make_dir(partdir,exclusive=True)\nFILE_12_L130= record=s.split_file(source,partdir)\nFILE_12_L131= t.create(work/'parts-record.json',core.canonical_bytes(record))\nFILE_12_L132= quotas={e['account_id']:cloud.quota(e['crypt_remote']) for e in entries}\nFILE_12_L133= allocation=core.allocate(entries,quotas,record['payload_bytes'],reserve,clock())\nFILE_12_L134= m=core.make_manifest(generation,logical_id,record['payload_bytes'],record['payload_sha256'],record['parts'],allocation)\nFILE_12_L135= mb=core.canonical_bytes(m);mh=core.manifest_hash(m);cloud.bind(m)\nFILE_12_L136= t.create(work/'allocation.json',core.canonical_bytes(allocation));t.create(work/'manifest.json',mb)\nFILE_12_L137= for rep in m['replicas']:\nFILE_12_L138= guard();cloud.absent(rep['crypt_remote'])\nFILE_12_L139= receipts=[]\nFILE_12_L140= for rep in m['replicas']:\nFILE_12_L141= guard();remote=rep['crypt_remote'];q=cloud.quota(remote)\nFILE_12_L142= t.need(core.quota_reason(q,clock()) is None and q['free']>=allocation['required_free_bytes'],'SELECTED_ACCOUNT_CAPACITY_CHANGED')\nFILE_12_L143= s.verify_parts(partdir,record)\nFILE_12_L144= for part in m['parts']:cloud.put(remote,part['name'],partdir/part['name'])\nFILE_12_L145= cloud.put(remote,'manifest.json',work/'manifest.json')\nFILE_12_L146= t.need(cloud.get(remote,'manifest.json',len(mb)+1)==mb,'MANIFEST_READBACK_MISMATCH')\nFILE_12_L147= whole=hashlib.sha256();count=0\nFILE_12_L148= for part in m['parts']:\nFILE_12_L149= observed=cloud.read_stream(remote,part['name'],part['size'],part['sha256'],whole.update)\nFILE_12_L150= t.need(observed=={'size':part['size'],'sha256':part['sha256']},'PART_READBACK_MISMATCH');count+=observed['size']\nFILE_12_L151= receipts.append(receipt(rep,m,whole,count));t.create(work/('receipt-%d.json'%len(receipts)),core.canonical_bytes(receipts[-1]))\nFILE_12_L152= core.verify_receipts(m,receipts)\nFILE_12_L153= seal={'schema_version':2,'state':'SEALED','generation':generation,'logical_id':logical_id,\nFILE_12_L154= 'manifest_sha256':mh,'replicas':m['replicas'],'receipts':receipts,\nFILE_12_L155= 'acceptance':'IDENTICAL_SEAL_REQUIRED_ON_BOTH_NAMED_ACCOUNTS'}\nFILE_12_L156= sb=core.canonical_bytes(seal);t.need(len(sb)<=core.SEAL_MAX_BYTES,'SEAL_BOUND')\nFILE_12_L157= r.validate_seal(sb,entries,generation,logical_id);t.create(work/'SEALED.json',sb)\nFILE_12_L158= for rep in m['replicas']:\nFILE_12_L159= guard();cloud.put(rep['crypt_remote'],'SEALED.json',work/'SEALED.json')\nFILE_12_L160= for rep in m['replicas']:\nFILE_12_L161= t.need(cloud.get(rep['crypt_remote'],'SEALED.json',len(sb)+1)==sb,'SEALED_QUORUM_REQUIRED')\nFILE_12_L162= guard();s.verify_parts(partdir,record)\nFILE_12_L163= t.create(work/'QUORUM_VERIFIED.json',core.canonical_bytes({'manifest_sha256':mh,'seal_sha256':t.sha(sb)}))\nFILE_12_L164= return {'sealed':True,'manifest':m,'seal_bytes':sb,'parts_record':record,'source':str(source),'work':str(work)}\nFILE_12_L165=\nFILE_12_L166=\nFILE_12_L167=def discover(cloud,entries,logical_id,expected_hash):\nFILE_12_L168= \"\"\"Find placement from all cloud catalogs, using only an external manifest digest.\"\"\"\nFILE_12_L169= core.validate_inventory(entries)\nFILE_12_L170= t.need(core.valid_name(logical_id) and core.valid_hash(expected_hash),'DISCOVERY_INPUT')\nFILE_12_L171= listed={};generations=set()\nFILE_12_L172= for e in entries:\nFILE_12_L173= gs=cloud.list_generations(e['crypt_remote'])\nFILE_12_L174= t.need(type(gs) is list and len(gs)<=r.MAX_GENERATIONS and all(core.valid_name(g) for g in gs),'GENERATION_LIST_INVALID')\nFILE_12_L175= t.need(len(gs)==len(set(gs)),'GENERATION_LIST_DUPLICATE');listed[e['crypt_remote']]=set(gs);generations.update(gs)\nFILE_12_L176= t.need(len(generations)<=r.MAX_GENERATIONS,'TOTAL_GENERATIONS_BOUND')\nFILE_12_L177= candidates=[]\nFILE_12_L178= for gen in sorted(generations):\nFILE_12_L179= seen={}\nFILE_12_L180= for e in entries:\nFILE_12_L181= remote=e['crypt_remote']\nFILE_12_L182= if gen not in listed[remote]:continue\nFILE_12_L183= b=cloud.get(remote,gen,'SEALED.json',core.SEAL_MAX_BYTES+1,missing_ok=True)\nFILE_12_L184= if b is None:continue\nFILE_12_L185= seal=r.validate_seal(b,entries,gen,logical_id)\nFILE_12_L186= t.need(remote in {x['crypt_remote'] for x in seal['replicas']},'UNNAMED_SEAL_LOCATION');seen[remote]=(b,seal)\nFILE_12_L187= if not seen:continue\nFILE_12_L188= sb,seal=next(iter(seen.values()))\nFILE_12_L189= if seal['manifest_sha256']!=expected_hash:continue\nFILE_12_L190= named={x['crypt_remote'] for x in seal['replicas']}\nFILE_12_L191= t.need(set(seen)==named and all(b==sb for b,_ in seen.values()),'IDENTICAL_TWO_SEALS_REQUIRED')\nFILE_12_L192= blobs=[]\nFILE_12_L193= for rep in seal['replicas']:\nFILE_12_L194= b=cloud.get(rep['crypt_remote'],gen,'manifest.json',core.MANIFEST_MAX_BYTES+1)\nFILE_12_L195= t.need(type(b) is bytes and t.sha(b)==expected_hash,'MANIFEST_DIGEST_MISMATCH')\nFILE_12_L196= m=r.strict_json(b,core.MANIFEST_MAX_BYTES);core.validate_manifest(m)\nFILE_12_L197= t.need(m['generation']==gen and m['logical_id']==logical_id and m['replicas']==seal['replicas'],'MANIFEST_PLACEMENT')\nFILE_12_L198= t.need(core.canonical_bytes(m)==b,'MANIFEST_CANONICAL_BYTES');core.verify_receipts(m,seal['receipts']);blobs.append(b)\nFILE_12_L199= t.need(len(blobs)==2 and blobs[0]==blobs[1],'TWO_MANIFEST_COPIES_REQUIRED')\nFILE_12_L200= candidates.append({'manifest':m,'seal_bytes':sb,'accounts_scanned':len(listed)})\nFILE_12_L201= t.need(len(candidates)==1,'EXACTLY_ONE_ACCEPTED_GENERATION_REQUIRED')\nFILE_12_L202= return candidates[0]\nFILE_12_L203=\nFILE_12_L204=\nFILE_12_L205=def fresh_seals(cloud,discovery):\nFILE_12_L206= m=discovery['manifest'];core.validate_manifest(m);sb=discovery['seal_bytes']\nFILE_12_L207= for rep in m['replicas']:\nFILE_12_L208= t.need(cloud.get(rep['crypt_remote'],m['generation'],'SEALED.json',len(sb)+1)==sb,'SEAL_CHANGED_DURING_RESTORE')\nFILE_12_L209=\nFILE_12_L210=\nFILE_12_L211=def download_part(cloud,rep,m,part,path,whole):\nFILE_12_L212= path=Path(path);parent=t.open_dir(path.parent);fd=None\nFILE_12_L213= try:\nFILE_12_L214= fd=os.open(path.name,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600,dir_fd=parent)\nFILE_12_L215= def consume(block):whole.update(block);s.write_all(fd,block)\nFILE_12_L216= result=cloud.read_stream(rep['crypt_remote'],m['generation'],part['name'],part['size'],part['sha256'],consume)\nFILE_13_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/nodeplan263.py\nFILE_13_BYTES=4603\nFILE_13_SHA256=db5c16ee24d25aa1694530332d3190ab7cc5d4f8eb69067d025e27ad5c995060\nFILE_13_CONTEXT_LINE_COUNT=23\nFILE_13_L1=\"\"\"Pure, allowlisted PVE metadata projection. Does not execute any command.\"\"\"\nFILE_13_L2=from decimal import Decimal,InvalidOperation\nFILE_13_L3=import hashlib\nFILE_13_L4=import re\nFILE_13_L5=import v2core as core\nFILE_13_L6=\nFILE_13_L7=class PlanError(ValueError):pass\nFILE_13_L8=\nFILE_13_L15= if type(value) is not str or not re.fullmatch(r'\\d+(?:\\.\\d+)?[KMGTPE]?',value):return None\nFILE_13_L16= try:\nFILE_13_L17= suffix=value[-1] if value[-1] in 'KMGTPE' else ''\nFILE_13_L18= base=Decimal(value[:-1] if suffix else value)\nFILE_13_L19= b=base*(1024**('KMGTPE'.index(suffix)+1) if suffix else 1)\nFILE_13_L20= return int(b) if b==int(b) and 0<b<=2**63-1 else None\nFILE_13_L21= except (ValueError,InvalidOperation):return None\nFILE_13_L22=\nFILE_13_L47= need(type(value) is str and len(value)<=8192,'DISK_VALUE_BOUND')\nFILE_13_L48= fields=value.split(',');vol=fields[0];opts={}\nFILE_13_L49= for item in fields[1:]:\nFILE_13_L50= k,sep,v=item.partition('=')\nFILE_13_L51= if sep:\nFILE_13_L52= need(k not in opts,'DISK_DUPLICATE_PROPERTY');opts[k]=v\nFILE_13_L53= if opts.get('media')=='cdrom':cdrom+=1;continue\nFILE_14_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/pve265.py\nFILE_14_BYTES=12888\nFILE_14_SHA256=cd2f634414a8e38a3789015aeca5a9b47821f77d7d1fa61dcdbdc866172963be\nFILE_14_CONTEXT_LINE_COUNT=80\nFILE_14_L1=\"\"\"PVE producer 265R1. Import has no effects. No network, cloud or payload deletion.\nFILE_14_L2=\nFILE_14_L3=The installer calls only make_plan; produce is an explicit, guarded future-run API.\nFILE_14_L4=A successful compression test is not a VM/CT restore test or proof of application consistency.\nFILE_14_L5=\"\"\"\nFILE_14_L6=import hashlib\nFILE_14_L7=import os\nFILE_14_L8=from pathlib import Path\nFILE_14_L9=import re\nFILE_14_L10=import selectors\nFILE_14_L11=import signal\nFILE_14_L12=import stat\nFILE_14_L13=import subprocess\nFILE_14_L14=import time\nFILE_14_L15=import v2core as core\nFILE_14_L16=import transport261 as t\nFILE_14_L17=import stream263 as stream\nFILE_14_L18=import nodeplan263 as np\nFILE_14_L19=\nFILE_14_L20=GIB=1024**3\nFILE_14_L21=LOCAL_RESERVE=4*GIB\nFILE_14_L32= if not ok:raise PVEError(reason)\nFILE_14_L33=\nFILE_14_L34=def path_ok(path):\nFILE_14_L35= return isinstance(path,(str,Path)) and Path(path).is_absolute() and '..' not in Path(path).parts and all(32<=ord(c)<127 for c in str(path))\nFILE_14_L36=\nFILE_14_L37=def defaults_summary(raw):\nFILE_14_L38= need(raw is None or type(raw) is bytes and len(raw)<=262144,'DEFAULTS_BOUND')\nFILE_14_L85= for disk in summary['disks']:\nFILE_14_L86= slot=disk['slot'];opts={}\nFILE_14_L87= for field in cfg[slot].split(',')[1:]:\nFILE_14_L88= k,sep,v=field.partition('=')\nFILE_14_L89= if sep:opts[k]=v\nFILE_14_L90= if 'backup' in opts and opts['backup'] not in ('0','1','yes','no','on','off','true','false'):\nFILE_14_L91= block.add('BACKUP_FLAG_UNKNOWN')\nFILE_14_L109= 'archive_cap_bytes':cap,'configured_full_cycle_fits':bool(configured_bound and 4*configured_bound+LOCAL_RESERVE<=staging_free),\nFILE_14_L110= 'compression_dependent':bool(configured_bound and cap<configured_bound),\nFILE_14_L111= 'coverage_eligible':not block,'local_reserve_bytes':LOCAL_RESERVE,'snapshot_history_included':False,\nFILE_14_L112= 'cdrom_media_included':False,'application_consistency_verified':False,'guest_restore_verified':False}\nFILE_14_L113= jobs.append(job)\nFILE_14_L114= return {'schema_version':1,'node':node,'observed_at':now,'local_guest_count':len(jobs),\nFILE_14_L115= 'jobs':jobs,'storages':ss,'global_defaults':global_summary,'global_blockers':global_summary['blockers'],\nFILE_14_L147= p.wait()\nFILE_14_L148=\nFILE_14_L149=def capture_archive(argv,destination,cap,seconds,check):\nFILE_14_L150= \"\"\"Bounded, exclusive file capture from a producer; on failure keep partial bytes at 0600.\"\"\"\nFILE_14_L151= need(type(argv) is list and argv and all(type(x) is str for x in argv),'ARGV')\nFILE_14_L152= need(type(cap) is int and 0<cap<=stream.MAX_BYTES,'ARCHIVE_CAP')\nFILE_14_L153= need(type(seconds) in (int,float) and 0<seconds<=86400,'DEADLINE')\nFILE_14_L169= b=os.read(key.fileobj.fileno(),65536)\nFILE_14_L170= if not b:sel.unregister(key.fileobj);continue\nFILE_14_L171= if key.fileobj is p.stdout:\nFILE_14_L172= need(total+len(b)<=cap,'ARCHIVE_CAP_REACHED_PARTIAL_RETAINED')\nFILE_14_L173= stream.write_all(fd,b);digest.update(b);total+=len(b)\nFILE_14_L174= need(deadline>time.monotonic(),'PRODUCER_TIMEOUT')\nFILE_14_L175= try:rc=p.wait(timeout=deadline-time.monotonic())\nFILE_14_L176= except subprocess.TimeoutExpired:raise PVEError('PRODUCER_TIMEOUT') from None\nFILE_14_L177= need(rc==0,'PRODUCER_RC_FAILED_PARTIAL_RETAINED');need(total>0,'EMPTY_ARCHIVE');check()\nFILE_14_L178= st=os.fstat(fd);named=os.stat(dest.name,dir_fd=parent,follow_symlinks=False)\nFILE_14_L179= need(st.st_dev==initial.st_dev and st.st_ino==initial.st_ino and t.ident(st)==t.ident(named) and\nFILE_14_L180= st.st_nlink==1 and st.st_size==total,'PRODUCER_FILE_IDENTITY_CHANGED')\nFILE_14_L200= \"\"\"Future explicit execution API. Caller must recheck full plan/coverage in guard.\nFILE_14_L201=\nFILE_14_L202= Compression CRC and SHA are verified; guest bootability remains unproved.\nFILE_14_L203= This function has no cloud/seal/delete operations and returns a readonly artifact.\nFILE_14_L204= \"\"\"\nFILE_14_L205= need(callable(guard),'GUARD_REQUIRED');guard();validate_job(job,int(time.time()));validate_tools(tools)\nFILE_14_L206= work=Path(work);parent=stream.private_dir(work)\nFILE_14_L209= tmp=work/'tmp';t.make_dir(tmp,exclusive=True)\nFILE_14_L210= dest=work/('guest-%d.%s.zst'%(job['vmid'],'tar' if job['type']=='lxc' else 'vma'))\nFILE_14_L211= def free_guard():\nFILE_14_L212= v=os.statvfs(work);need(v.f_frsize*v.f_bavail>=LOCAL_RESERVE,'STAGING_RESERVE_REACHED_PARTIAL_RETAINED')\nFILE_14_L213= free_guard()\nFILE_14_L214= result=capture_archive(dump_argv(job,tools['vzdump']['path'],tmp,int(time.time())),dest,job['archive_cap_bytes'],seconds,free_guard)\nFILE_14_L215= guard();validate_tools(tools)\nFILE_14_L219= need(n==result['size'] and h==result['sha256'] and list(identity)==result['identity'],'PRODUCER_READBACK_MISMATCH')\nFILE_14_L220= guard();validate_tools(tools)\nFILE_14_L221= return {**result,'path':str(dest),'vmid':job['vmid'],'type':job['type'],'node':job['node'],\nFILE_14_L222= 'config_sha256':job['config_sha256'],'compression_test_ok':True,'restored':False,\nFILE_14_L223= 'state':'PRODUCED_COMPRESSION_CHECKED_NOT_CLOUD_SEALED','local_payload_retained':True}\nFILE_15_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/pve270.py\nFILE_15_BYTES=19595\nFILE_15_SHA256=97015277a4f3f8129c0fd11eb70c06293026366f1f8232a97feeed513a2dbcef\nFILE_15_CONTEXT_LINE_COUNT=140\nFILE_15_L3=Does not modify installed pve265, old workspaces, staging permissions or guest config.\nFILE_15_L4=Only explicit produce() executes vzdump. Private bounded stderr/exit metadata retained.\nFILE_15_L5=\"\"\"\nFILE_15_L6=import hashlib,json,os,re,secrets,selectors,signal,stat,subprocess,sys,time\nFILE_15_L7=from pathlib import Path\nFILE_15_L8=import v2core as core\nFILE_15_L9=import transport261 as t\nFILE_15_L10=import stream263 as stream\nFILE_15_L11=import pve265 as old\nFILE_15_L12=need=old.need\nFILE_15_L13=MAX_STDERR=2*1024**2\nFILE_15_L14=EXPECTED_CFG='09957aacd41ba9eeaf5fd4eda13936d580c9082a46895433379aa9dd0bad5969'\nFILE_15_L39=def live_gate(job,pvesh_path,pvesh_sha):\nFILE_15_L40= need(job.get('vmid')==110 and job.get('type')=='lxc' and job.get('node')=='pve01' and job.get('config_sha256')==EXPECTED_CFG,'ONLY_ACCEPTED_CT110')\nFILE_15_L41= vals=[]\nFILE_15_L42= for part in ('config','status/current','snapshot'):\nFILE_15_L43= need(t.sha(t.read_secure(Path(pvesh_path),16*1024**2)[0])==pvesh_sha,'PVESH_CHANGED')\nFILE_15_L44= rc,b=t.bounded_process([str(pvesh_path),'get','/nodes/pve01/lxc/110/'+part,'--output-format','json'],dict(old.ENV),262144,30)\nFILE_15_L45= need(rc==0,'CT_GATE_READ_FAILED')\nFILE_15_L46= try:vals.append(json.loads(b))\nFILE_15_L47= except (ValueError,UnicodeError):raise old.PVEError('CT_GATE_JSON') from None\nFILE_15_L48= validate_ct(*vals,job['config_sha256'])\nFILE_15_L49= return True\nFILE_15_L50=\nFILE_15_L59= def __init__(self,path,alias):\nFILE_15_L60= self.path=Path(path);self.alias=Path(alias);self.parent=None;self.fd=None\nFILE_15_L61= need(self.path.name=='perl' and self.alias.name=='perl5.40.1' and self.path.parent==self.alias.parent,'PERL_PATH_POLICY')\nFILE_15_L62= need(self.path.is_absolute() and '..' not in self.path.parts,'PERL_PATH_POLICY')\nFILE_15_L63= try:\nFILE_15_L64= self.parent=os.open('/',os.O_RDONLY|os.O_DIRECTORY)\nFILE_15_L65= for part in self.path.parts[1:-1]:\nFILE_15_L66= nxt=os.open(part,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW,dir_fd=self.parent)\nFILE_15_L67= os.close(self.parent);self.parent=nxt\nFILE_15_L68= s=os.fstat(nxt)\nFILE_15_L69= need(s.st_uid==0 and not s.st_mode&0o022,'PERL_PARENT_UNTRUSTED')\nFILE_15_L75= need(os.pread(self.fd,4,0)==b'\\x7fELF','PERL_ELF_REQUIRED')\nFILE_15_L76= self.identity=t.ident(s)+(s.st_nlink,)\nFILE_15_L77= self.sha256=self._digest();self.check()\nFILE_15_L78= except BaseException:\nFILE_15_L79= self.close();raise\nFILE_15_L80= def _digest(self):\nFILE_15_L81= s=os.fstat(self.fd);need(0<s.st_size<=32*1024**2,'PERL_SIZE_BOUND')\nFILE_15_L94= # Verify that the trusted parent path still resolves to the open dir.\nFILE_15_L95= fd=os.open('/',os.O_RDONLY|os.O_DIRECTORY)\nFILE_15_L96= try:\nFILE_15_L97= for part in self.path.parts[1:-1]:\nFILE_15_L98= nxt=os.open(part,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW,dir_fd=fd)\nFILE_15_L99= os.close(fd);fd=nxt;s=os.fstat(fd)\nFILE_15_L100= need(s.st_uid==0 and not s.st_mode&0o022,'PERL_PARENT_UNTRUSTED')\nFILE_15_L101= a=os.fstat(fd);b=os.fstat(self.parent)\nFILE_15_L102= need((a.st_dev,a.st_ino)==(b.st_dev,b.st_ino),'PERL_PARENT_CHANGED')\nFILE_15_L103= finally:os.close(fd)\nFILE_15_L104= except OSError:raise old.PVEError('PERL_PATH_CHANGED') from None\nFILE_15_L105= def run(self,args,seconds=30):\nFILE_15_L106= need(type(args) is list and all(type(x) is str and '\\x00' not in x for x in args),'PERL_ARGV')\nFILE_15_L107= need(type(seconds) in (int,float) and 0<seconds<=30,'PERL_DEADLINE')\nFILE_15_L121= need(len(out)+len(b)<=16384,'PERL_STDOUT_BOUND');out.extend(b)\nFILE_15_L122= left=deadline-time.monotonic();need(left>0,'PERL_TIMEOUT')\nFILE_15_L123= rc=p.wait(timeout=left);self.check();return rc,bytes(out)\nFILE_15_L124= except subprocess.TimeoutExpired:raise old.PVEError('PERL_TIMEOUT') from None\nFILE_15_L125= finally:\nFILE_15_L126= if p is not None:\nFILE_15_L127= if p.poll() is None:\nFILE_15_L150= for p,h in pins.items():need(t.sha(t.read_secure(Path(p),2*1024**2)[0])==h,'PVE_MAPPING_SOURCE_CHANGED')\nFILE_15_L151= pin.check()\nFILE_15_L152= try:d=json.loads(b)\nFILE_15_L153= except (ValueError,UnicodeError):raise old.PVEError('PVE_IDMAP_JSON') from None\nFILE_15_L154= return validate_mapping(d)\nFILE_15_L155=\nFILE_15_L156=def _parent(path):\nFILE_15_L157= path=Path(path)\nFILE_15_L158= need(path.is_absolute() and '..' not in path.parts,'TEMP_PARENT_PATH')\nFILE_15_L159= fd=os.open('/',os.O_RDONLY|os.O_DIRECTORY)\nFILE_15_L160= try:\nFILE_15_L161= for i,part in enumerate(path.parts[1:]):\nFILE_15_L162= nxt=os.open(part,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW,dir_fd=fd);os.close(fd);fd=nxt\nFILE_15_L163= s=os.fstat(fd);last=i==len(path.parts)-2\nFILE_15_L164= need(s.st_uid==0,'TEMP_PARENT_OWNER')\nFILE_15_L165= need(not s.st_mode&0o022 or last and s.st_mode&stat.S_ISVTX,'TEMP_PARENT_WRITABLE')\nFILE_15_L166= result=fd;fd=None;return result\nFILE_15_L170=\nFILE_15_L171=class MappedScratch:\nFILE_15_L172= \"\"\"Root-owned, mapped-GID traverse-only, no access for others. No recursive cleanup.\"\"\"\nFILE_15_L173= def __init__(self,gid,base='/var/tmp'):\nFILE_15_L174= need(type(gid) is int and gid==100000,'TEMP_GID_POLICY')\nFILE_15_L175= self.parent=_parent(base);self.fd=None;self.gid=gid\nFILE_15_L176= self.name='homelab-vzdump-268-'+secrets.token_hex(16);self.path=Path(base)/self.name\nFILE_15_L177= try:\nFILE_15_L178= os.mkdir(self.name,0o700,dir_fd=self.parent)\nFILE_15_L179= self.fd=os.open(self.name,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW,dir_fd=self.parent)\nFILE_15_L181= os.fchown(self.fd,0,gid);os.fchmod(self.fd,0o710)\nFILE_15_L182= s=os.fstat(self.fd);self.identity=(s.st_dev,s.st_ino)\nFILE_15_L183= os.fsync(self.parent);self.check()\nFILE_15_L184= except BaseException:\nFILE_15_L185= if self.fd is not None:os.close(self.fd);self.fd=None\nFILE_15_L186= os.close(self.parent);self.parent=None\nFILE_15_L187= raise\nFILE_15_L199= name='access-probe';fd=os.open(name,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o644,dir_fd=self.fd)\nFILE_15_L200= try:os.fchmod(fd,0o644);stream.write_all(fd,b'HOMELAB_ACCESS_PROBE\\n');os.fsync(fd);identity=t.ident(os.fstat(fd))\nFILE_15_L201= finally:os.close(fd)\nFILE_15_L202= positive='''import os,sys\nFILE_15_L203=p,private=sys.argv[1:]\nFILE_15_L204=assert open(p+'/access-probe','rb').read()==b'HOMELAB_ACCESS_PROBE\\\\n'\nFILE_15_L205=for action in (lambda:os.listdir(p),lambda:os.open(p+'/forbidden',os.O_WRONLY|os.O_CREAT,0o600),lambda:os.open(private,os.O_RDONLY|os.O_DIRECTORY)):\nFILE_15_L207= except PermissionError:continue\nFILE_15_L208= raise SystemExit(31)\nFILE_15_L209='''\nFILE_15_L210= negative='''import sys\nFILE_15_L211=try:open(sys.argv[1]+'/access-probe','rb').read()\nFILE_15_L212=except PermissionError:raise SystemExit(0)\nFILE_15_L213=raise SystemExit(32)\nFILE_15_L256= b=os.read(key.fileobj.fileno(),65536)\nFILE_15_L257= if not b:sel.unregister(key.fileobj);continue\nFILE_15_L258= if key.fileobj is p.stdout:\nFILE_15_L259= need(total+len(b)<=cap,'ARCHIVE_CAP_REACHED_PARTIAL_RETAINED')\nFILE_15_L260= stream.write_all(fd,b);digest.update(b);total+=len(b)\nFILE_15_L261= else:\nFILE_15_L262= err_total+=len(b);eh.update(b);chunk=b[:max(0,MAX_STDERR-err_kept)]\nFILE_15_L263= if chunk:stream.write_all(efd,chunk);err_kept+=len(chunk)\nFILE_15_L264= need(deadline>time.monotonic(),'PRODUCER_TIMEOUT')\nFILE_15_L265= try:rc=p.wait(timeout=deadline-time.monotonic())\nFILE_15_L266= except subprocess.TimeoutExpired:raise old.PVEError('PRODUCER_TIMEOUT') from None\nFILE_15_L267= need(rc==0,'PRODUCER_RC_FAILED_PARTIAL_RETAINED');need(total>0,'EMPTY_ARCHIVE');check()\nFILE_15_L268= st=os.fstat(fd);named=os.stat(dest.name,dir_fd=parent,follow_symlinks=False)\nFILE_15_L269= need(st.st_dev==initial.st_dev and st.st_ino==initial.st_ino and t.ident(st)==t.ident(named) and st.st_nlink==1 and st.st_size==total,'PRODUCER_FILE_IDENTITY_CHANGED')\nFILE_15_L270= os.fchmod(fd,0o400);os.fsync(fd);os.fsync(parent);good=True\nFILE_15_L306= scratch.probe(uid,work);emit('MAPPED_UID_ACCESS_AND_ISOLATION_PROBE','PASS')\nFILE_15_L307= def free_guard():\nFILE_15_L308= scratch.check()\nFILE_15_L309= for path,reserve,reason in ((work,old.LOCAL_RESERVE,'STAGING_RESERVE_REACHED_PARTIAL_RETAINED'),(scratch.path,256*1024**2,'PVE_TEMP_RESERVE_LOW')):\nFILE_15_L310= v=os.statvfs(path);need(v.f_frsize*v.f_bavail>=reserve,reason)\nFILE_15_L311= free_guard();guard();dest=work/'guest-110.tar.zst'\nFILE_15_L312= result=capture_archive(old.dump_argv(job,tools['vzdump']['path'],scratch.path,int(time.time())),dest,job['archive_cap_bytes'],seconds,free_guard)\nFILE_15_L317= need(n==result['size'] and h==result['sha256'] and list(identity)==result['identity'],'PRODUCER_READBACK_MISMATCH')\nFILE_15_L318= guard();old.validate_tools(tools);scratch.close(empty_only=True);complete=True;emit('PVE_TEMP_EMPTY_REMOVED','YES')\nFILE_15_L319= return {**result,'path':str(dest),'vmid':110,'type':'lxc','node':job['node'],'config_sha256':job['config_sha256'],\nFILE_15_L320= 'compression_test_ok':True,'restored':False,'state':'PRODUCED_COMPRESSION_CHECKED_NOT_CLOUD_SEALED','local_payload_retained':True}\nFILE_15_L321= finally:\nFILE_15_L322= m=work/'PRODUCER_PROCESS.json'\nFILE_15_L323= if m.exists():\nFILE_16_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/pve282.py\nFILE_16_BYTES=6195\nFILE_16_SHA256=73c6cb7773eb8e82d1e7ed5ab4733b4afb88f74ae69c09125d0378d6e480e012\nFILE_16_CONTEXT_LINE_COUNT=58\nFILE_16_L1=\"\"\"282R1 bounded CT112 adapter; proven 270 capture/temp/Perl implementation unchanged.\nFILE_16_L2=Expected source hash must be supplied from the immutable-hash-bound 265 plan.\nFILE_16_L3=No changes to source guest configuration; no source110 backup or guest deletion.\nFILE_16_L4=\"\"\"\nFILE_16_L5=import copy,json,os,time\nFILE_16_L6=from pathlib import Path\nFILE_16_L7=import v2core as core\nFILE_16_L8=import transport261 as t\nFILE_16_L9=import stream263 as stream\nFILE_16_L10=import pve265 as old\nFILE_16_L11=import pve270 as proven\nFILE_16_L12=import guest266 as g\nFILE_16_L13=need=old.need\nFILE_16_L14=PerlPin=proven.PerlPin\nFILE_16_L15=host_mapping=proven.host_mapping\nFILE_16_L26= need(core.valid_hash(expected_config) and job.get('config_sha256')==expected_config,'CT112_PLAN_CONFIG_ANCHOR')\nFILE_16_L27= return True\nFILE_16_L28=\nFILE_16_L29=def select112(current,baseline,now):\nFILE_16_L30= rows=g.plan_rows(current);previous=g.plan_rows(baseline)\nFILE_16_L31= by_id={j['vmid']:j for j in previous}\nFILE_16_L32= need(TARGET_VMID in by_id,'CT112_MISSING_FROM_ACCEPTED265')\nFILE_16_L33= g.same_state(baseline,current,TARGET_VMID)\nFILE_16_L34= need({j['vmid'] for j in rows}==set(by_id),'ACCEPTED265_MEMBERSHIP_CHANGED')\nFILE_16_L35= for row in rows:\nFILE_16_L36= need(row['config_sha256']==by_id[row['vmid']]['config_sha256'],'ACCEPTED265_GUEST_CONFIG_CHANGED')\nFILE_16_L37= selected=[j for j in rows if j['vmid']==TARGET_VMID]\nFILE_16_L38= need(len(selected)==1,'CT112_NOT_UNIQUE')\nFILE_16_L39= job=copy.deepcopy(selected[0]);old.validate_job(job,now)\nFILE_16_L40= need(current.get('global_blockers')==[],'GLOBAL_DEFAULT_BLOCK')\nFILE_16_L41= need(job.get('compression_dependent') is False and job.get('configured_full_cycle_fits') is True,'CT112_FULL_CYCLE_SPACE_UNPROVEN')\nFILE_16_L42= disks=job.get('disks');need(type(disks) is list and len(disks)==1,'CT112_SINGLE_ROOTFS_REQUIRED')\nFILE_16_L53=def live_gate(job,pvesh_path,pvesh_sha,expected_config):\nFILE_16_L54= require_target(job,expected_config)\nFILE_16_L55= vals=[]\nFILE_16_L56= for part in ('config','status/current','snapshot'):\nFILE_16_L57= need(t.sha(t.read_secure(Path(pvesh_path),16*1024**2)[0])==pvesh_sha,'PVESH_CHANGED')\nFILE_16_L58= rc,b=t.bounded_process([str(pvesh_path),'get','/nodes/pve01/lxc/112/'+part,'--output-format','json'],dict(old.ENV),262144,30)\nFILE_16_L59= need(rc==0,'CT112_GATE_READ_FAILED')\nFILE_16_L60= try:vals.append(json.loads(b))\nFILE_16_L61= except (ValueError,UnicodeError):raise old.PVEError('CT112_GATE_JSON') from None\nFILE_16_L62= validate_ct(*vals,expected_config)\nFILE_16_L63= return True\nFILE_16_L64=\nFILE_16_L79= scratch.probe(uid,work);emit('MAPPED_UID_ACCESS_AND_ISOLATION_PROBE','PASS')\nFILE_16_L80= def free_guard():\nFILE_16_L81= scratch.check()\nFILE_16_L82= for path,reserve,reason in ((work,old.LOCAL_RESERVE,'STAGING_RESERVE_REACHED_PARTIAL_RETAINED'),(scratch.path,256*1024**2,'PVE_TEMP_RESERVE_LOW')):\nFILE_16_L83= v=os.statvfs(path);need(v.f_frsize*v.f_bavail>=reserve,reason)\nFILE_16_L84= free_guard();guard();dest=work/'guest-112.tar.zst'\nFILE_16_L85= result=capture_archive(old.dump_argv(job,tools['vzdump']['path'],scratch.path,int(time.time())),dest,job['archive_cap_bytes'],seconds,free_guard)\nFILE_16_L90= need(n==result['size'] and h==result['sha256'] and list(identity)==result['identity'],'PRODUCER_READBACK_MISMATCH')\nFILE_16_L91= guard();old.validate_tools(tools);scratch.close(empty_only=True);complete=True;emit('PVE_TEMP_EMPTY_REMOVED','YES')\nFILE_16_L92= return {**result,'path':str(dest),'vmid':112,'type':'lxc','node':job['node'],'config_sha256':job['config_sha256'],\nFILE_16_L93= 'compression_test_ok':True,'restored':False,'state':'PRODUCED_COMPRESSION_CHECKED_NOT_CLOUD_SEALED','local_payload_retained':True}\nFILE_16_L94= finally:\nFILE_16_L95= m=work/'PRODUCER_PROCESS.json'\nFILE_16_L96= if m.exists():\nFILE_17_PATH=/opt/homelab-backup-v2/releases/backup-v2-accepted-486r1/candidate411/restore262.py\nFILE_17_BYTES=14701\nFILE_17_SHA256=56d1b961c8d5654d5e2ee2755268db46bd2202bca11e69788febf991cfaa79f1\nFILE_17_CONTEXT_LINE_COUNT=180\nFILE_17_L1=\"\"\"262R1 bounded cloud-discovered recovery. No live action on import.\nFILE_17_L2=\nFILE_17_L3=Cloud access is strictly lsjson/cat. No source-local workspace/manifest/receipt\nFILE_17_L4=is read. The external accepted manifest digest is a trust anchor, not placement.\nFILE_17_L5=\"\"\"\nFILE_17_L6=import hashlib\nFILE_17_L7=import io\nFILE_17_L8=import json\nFILE_17_L9=import os\nFILE_17_L10=from pathlib import Path\nFILE_17_L11=import re\nFILE_17_L12=import stat\nFILE_17_L13=import tarfile\nFILE_17_L14=import time\nFILE_17_L15=import v2core as core\nFILE_17_L16=import transport261 as t\nFILE_17_L17=\nFILE_17_L18=SOURCE_NAMES=frozenset(('etc/pve/HOMELAB_ASSISTANT_ERROR_REGISTER.md','etc/pve/31_HOMELAB_REFERENCE.md',\nFILE_17_L19= 'usr/local/sbin/homelab-control-backup','etc/systemd/system/homelab-control-backup.service'))\nFILE_17_L20=ALL_NAMES=SOURCE_NAMES|{'SOURCE_INDEX.json'}\nFILE_17_L21=MAX_GENERATIONS=64\nFILE_17_L22=SEAL_KEYS={'schema_version','state','generation','logical_id','manifest_sha256','replicas','receipts','acceptance'}\nFILE_17_L23=\nFILE_17_L24=def strict_json(data,limit):\nFILE_17_L25= t.need(type(data) is bytes and len(data)<=limit,'JSON_BOUND')\nFILE_17_L29= t.need(k not in result,'JSON_DUPLICATE_KEY');result[k]=v\nFILE_17_L30= return result\nFILE_17_L31= def bad_constant(value):raise t.Stop('JSON_NONFINITE_NUMBER')\nDEPENDENCY_PATH_COUNT=28\nDEPENDENCY_PATH_1=/opt/homelab-backup-v2/releases/core-260r1\nDEPENDENCY_PATH_2=/opt/homelab-backup-v2/releases/core-260r1/v2core.py\nDEPENDENCY_PATH_3=/opt/homelab-backup-v2/releases/ct-backup-282r1\nDEPENDENCY_PATH_4=/opt/homelab-backup-v2/releases/ct-backup-282r1/guest266.py\nDEPENDENCY_PATH_5=/opt/homelab-backup-v2/releases/ct-backup-282r1/pve282.py\nDEPENDENCY_PATH_6=/opt/homelab-backup-v2/releases/ct-backup-282r1/test_guest266.py\nDEPENDENCY_PATH_7=/opt/homelab-backup-v2/releases/ct-backup-282r1/test_perl270.py\nDEPENDENCY_PATH_8=/opt/homelab-backup-v2/releases/ct-backup-282r1/test_producer282.py\nDEPENDENCY_PATH_9=/opt/homelab-backup-v2/releases/ct-backup-282r1/test_pve282.py\nDEPENDENCY_PATH_10=/opt/homelab-backup-v2/releases/large-cloud-264r1\nDEPENDENCY_PATH_11=/opt/homelab-backup-v2/releases/large-cloud-264r1/large264.py\nDEPENDENCY_PATH_12=/opt/homelab-backup-v2/releases/pve-producer-265r1\nDEPENDENCY_PATH_13=/opt/homelab-backup-v2/releases/pve-producer-265r1/PLAN.json\nDEPENDENCY_PATH_14=/opt/homelab-backup-v2/releases/pve-producer-265r1/pve265.py\nDEPENDENCY_PATH_15=/opt/homelab-backup-v2/releases/pve-producer-265r1/test_pve265.py\nDEPENDENCY_PATH_16=/opt/homelab-backup-v2/releases/pve-retry-268r1\nDEPENDENCY_PATH_17=/opt/homelab-backup-v2/releases/pve-retry-270r1\nDEPENDENCY_PATH_18=/opt/homelab-backup-v2/releases/pve-retry-270r1/pve270.py\nDEPENDENCY_PATH_19=/opt/homelab-backup-v2/releases/pve-retry-270r1/test_pve270.py\nDEPENDENCY_PATH_20=/opt/homelab-backup-v2/releases/pve-run-266r1\nDEPENDENCY_PATH_21=/opt/homelab-backup-v2/releases/restore-262r1\nDEPENDENCY_PATH_22=/opt/homelab-backup-v2/releases/restore-262r1/restore262.py\nDEPENDENCY_PATH_23=/opt/homelab-backup-v2/releases/stream-263r1\nDEPENDENCY_PATH_24=/opt/homelab-backup-v2/releases/stream-263r1/nodeplan263.py\nDEPENDENCY_PATH_25=/opt/homelab-backup-v2/releases/stream-263r1/stream263.py\nDEPENDENCY_PATH_26=/opt/homelab-backup-v2/releases/transport-261r1\nDEPENDENCY_PATH_27=/opt/homelab-backup-v2/releases/transport-261r1/transport261.py\nDEPENDENCY_PATH_28=/opt/homelab-backup-v2/releases/vm-backup-283r1\nHAS_RCLONE_SOURCE=true\nHAS_OBJECT_PATH_CONTRACT=true\nDECISION=PASS_BACKUP213_EXACT_CLOUD_OBJECT_CONTRACT_CAPTURED\nNEXT_GATE=BUILD_CORRECTED_CLOUD_GENERATION_RECOVERY\nCLOUD_READS=0\nCLOUD_WRITES=0\nVPS_SSH_ATTEMPTS=0\nMESSENGERS214_CLOSED=false\nMAJOR_STAGES_REMAINING=8\nNEWFI213_END=true\n"
|
|
}
|