From aaa0bc0d108daba9e53551dd555dc20cdcc3dabd Mon Sep 17 00:00:00 2001 From: homelab-runtime-publisher Date: Wed, 22 Jul 2026 10:01:26 +0000 Subject: [PATCH] runtime: publish CLUSTER-REFERENCE-READINESS-168 --- .../CLUSTER-REFERENCE-READINESS-168.json | 30 +++++++++++++++++ .../CLUSTER-REFERENCE-READINESS-168.txt | 32 +++++++++++++++++++ runtime/latest.json | 16 +++++----- runtime/latest.txt | 20 ++++++++---- 4 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 runtime/history/CLUSTER-REFERENCE-READINESS-168.json create mode 100644 runtime/history/CLUSTER-REFERENCE-READINESS-168.txt diff --git a/runtime/history/CLUSTER-REFERENCE-READINESS-168.json b/runtime/history/CLUSTER-REFERENCE-READINESS-168.json new file mode 100644 index 0000000..6030bc8 --- /dev/null +++ b/runtime/history/CLUSTER-REFERENCE-READINESS-168.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "CLUSTER-REFERENCE-READINESS-168", + "status": "FAIL", + "rc": 1, + "host": "pve01", + "mode": "change", + "component": "reference-update", + "started_at_utc": "2026-07-22T10:01:26Z", + "finished_at_utc": "2026-07-22T10:01:26Z", + "reference_register_checked": true, + "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", + "error_register_checked": true, + "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752", + "command_sha256": "13b79b59906aa1b60b84c878297d9dc0954bd8a683875d4014c9920d1a2df96d", + "duplicate_failed_command_blocked": false, + "block_reason": null, + "execution_started": true, + "changes_made": true, + "sanitized": true, + "secrets_included": false, + "private_addresses_included": false, + "raw_evidence_retained_locally": true, + "raw_evidence_sha256": "4328ef3741bb0a63d64b79260170a0d85d440074cf7ee68d49f4c4d435b85928", + "sanitized_output_sha256": "4328ef3741bb0a63d64b79260170a0d85d440074cf7ee68d49f4c4d435b85928", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "Traceback (most recent call last):\n File \"\", line 1, in \n exec('''import base64,datetime,json,os,pathlib,py_compile,re,shutil,subprocess,tempfile,time,urllib.parse,urllib.request\\nB='https://git.gram1.ru';O='homelab-admin';PR='homelab-public-context';VR='homelab-cluster-reference-private';BR='assistant-runtime';P='CLUSTER-REFERENCE-DOCUMENTATION-PUBLISH-167';C='CLUSTER-REFERENCE-READINESS-168';R=pathlib.Path('/etc/homelab/reference');CLI=pathlib.Path('/usr/local/sbin/homelab-reference');REF=pathlib.Path('/usr/local/sbin/homelab-reference-refresh');PUB=pathlib.Path('/usr/local/sbin/homelab-reference-publish')\\nF=lambda u:urllib.request.urlopen(urllib.request.Request(u,headers={'User-Agent':'homelab-reference/ready','Cache-Control':'no-cache'}),timeout=90).read()\\nboot=json.loads(F(B+'/.well-known/homelab-bootstrap.json'));errs=json.loads(F(boot['entrypoints']['errors_index_url']));assert C not in json.dumps(errs,ensure_ascii=False)\\ncommits={}\\nfor e in ('json','txt'):\\n p='runtime/history/'+P+'.'+e;m=json.loads(F(B+'/api/v1/repos/'+O+'/'+PR+'/contents/'+urllib.parse.quote(p,safe='/')+'?ref='+BR));commits[e]=m['last_commit_sha'];globals()['h_'+e]=F(B+'/'+O+'/'+PR+'/raw/commit/'+commits[e]+'/'+p)\\nd=json.loads(h_json);assert d.get('command_id')==P and d.get('status')=='OK' and int(d.get('rc'))==0 and d.get('execution_started') is True and b'CLUSTER_REFERENCE_DOCUMENTATION_AND_PUBLICATION=COMPLETE' in h_txt\\nfor p in (R/'manifest.json',R/'state/current.json',CLI,REF,PUB):assert p.exists(),p\\ndef atom(p,d):\\n p.parent.mkdir(parents=True,exist_ok=True);f,n=tempfile.mkstemp(dir=str(p.parent),prefix=p.name+'.')\\n with os.fdopen(f,'w',encoding='utf-8') as x:json.dump(d,x,ensure_ascii=False,indent=2);x.write('\\n')\\n os.chmod(n,0o640);os.replace(n,p)\\nM=json.loads((R/'manifest.json').read_text());X=['owners','vendors','contracts','procedures','disaster_recovery','change_management','config_references','coverage_gaps'];S=list(M.get('sections',[]))\\nfor x in X:\\n if x not in S:S.append(x)\\nM['sections']=S;M.setdefault('freshness_seconds',{}).update({x:86400 for x in X});M['updated_at']=datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat();atom(R/'manifest.json',M)\\nfor l in ('declared','observed','effective'):\\n for s in S:\\n p=R/l/(s+'.json')\\n if not p.exists():atom(p,{'schema_version':2,'section':s,'layer':l,'updated_at':M['updated_at'],'records':[]})\\nA={'procedures':[{'id':'procedure-reference-operations','status':'ACTIVE','document':'OPERATIONS.md'},{'id':'procedure-reference-recovery','status':'ACTIVE','document':'RECOVERY.md'}],'disaster_recovery':[{'id':'dr-dual-mail-cloud-verification','status':'ENFORCED','two_independent_remote_integrity_confirmations_required':True}],'change_management':[{'id':'change-immutable-history','status':'ENFORCED','latest_pointer_authoritative':False,'exact_command_id_required':True}],'config_references':[{'id':'config-reference-policy','status':'ENFORCED','secret_values_allowed':False}],'coverage_gaps':[{'id':'gap-owners','section':'owners','status':'REQUIRES_DECLARATION'},{'id':'gap-vendors','section':'vendors','status':'REQUIRES_DECLARATION'},{'id':'gap-contracts','section':'contracts','status':'REQUIRES_DECLARATION'}]}\\nfor s,a in A.items():\\n p=R/'declared'/(s+'.json');q=json.loads(p.read_text());z={str(i.get('id')):i for i in q.get('records',[]) if i.get('id')}\\n for i in a:z[i['id']]=i\\n q['records']=[z[k] for k in sorted(z)];q['updated_at']=M['updated_at'];atom(p,q)\\nt=CLI.read_text()\\nif 'import subprocess\\n' not in t:t=t.replace('import shutil\\n','import shutil\\nimport subprocess\\n',1)\\nt=t.replace('%Y%m%dT%H%M%SZ','%Y%m%dT%H%M%S%fZ')\\nif 'def cmd_refresh(args):' not in t:\\n f='\\n'.join(['def cmd_refresh(args):',' subprocess.run([\\'/usr/local/sbin/homelab-reference-refresh\\'],check=True)','','def cmd_publish(args):',' subprocess.run([\\'/usr/local/sbin/homelab-reference-publish\\'],check=True)','','def cmd_rollback(args):',' target=(ROOT/\\'snapshots\\'/args.snapshot).resolve()',' base=(ROOT/\\'snapshots\\').resolve()',' if base not in target.parents or not target.is_dir(): raise SystemExit(\\'snapshot not found\\')',' pre=snapshot()',' for layer in LAYERS:',' src=target/layer',' if src.is_dir():',' dst=ROOT/layer',' if dst.exists(): shutil.rmtree(dst)',' shutil.copytree(src,dst)',' for section in sections(): merge_section(section)',' print(\\'pre_rollback_snapshot=\\'+str(pre))',''])\\n t=t.replace('parser = argparse.ArgumentParser',f+'\\nparser = argparse.ArgumentParser',1);t=t.replace('arguments = parser.parse_args()','p=sub.add_parser(\\'refresh\\');p.set_defaults(func=cmd_refresh)\\np=sub.add_parser(\\'publish\\');p.set_defaults(func=cmd_publish)\\np=sub.add_parser(\\'rollback\\');p.add_argument(\\'snapshot\\');p.set_defaults(func=cmd_rollback)\\narguments = parser.parse_args()',1)\\nCLI.write_text(t);os.chmod(CLI,0o750);py_compile.compile(str(CLI),doraise=True)\\nt=REF.read_text().replace('AUTO_REFRESH_READY','READY')\\nif 'next_action' not in t:t=t.replace(chr(34)+'status'+chr(34)+':'+chr(34)+'READY'+chr(34),chr(34)+'status'+chr(34)+':'+chr(34)+'READY'+chr(34)+','+chr(34)+'next_action'+chr(34)+':'+chr(34)+'NONE'+chr(34),1)\\nREF.write_text(t);os.chmod(REF,0o750);py_compile.compile(str(REF),doraise=True)\\nD=R/'docs';D.mkdir(exist_ok=True);(D/'MANUAL-DATA.md').write_text('# Manual data\\n\\nFill owners, vendors and contracts in the declared layer. Never store passwords, tokens, private keys or recovery codes.\\n');(D/'VALIDATION.md').write_text('# Validation\\n\\nStatus: READY\\nNext action: NONE\\n')\\nBS=pathlib.Path('/var/lib/gitea/custom/public/.well-known/homelab-bootstrap.json');assert BS.is_file() and json.loads(BS.read_text()).get('cluster_id')=='homelab'\\nH=pathlib.Path('/usr/local/sbin/homelab-reference-bootstrap-update');code='\\n'.join(['import datetime,hashlib,json,os,pathlib,sys,tempfile','r=pathlib.Path(\\'/etc/homelab/reference\\');p=pathlib.Path('+repr(str(BS))+');c=sys.argv[1];d=json.loads(p.read_text());u=\\'https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/\\'+c+\\'/reference/index.json\\';d[\\'generated_at_utc\\']=datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace(\\'+00:00\\',\\'Z\\');d.setdefault(\\'entrypoints\\',{})[\\'cluster_reference_index_url\\']=u;d.setdefault(\\'operating_contract\\',{})[\\'load_cluster_reference_before_diagnostics\\']=True;d[\\'coverage\\']={\\'status\\':\\'READY\\',\\'missing\\':[],\\'manual_declaration_sections\\':[\\'owners\\',\\'vendors\\',\\'contracts\\']};d[\\'cluster_reference\\']={\\'status\\':\\'READY\\',\\'read_before_diagnostics\\':True,\\'layers\\':[\\'declared\\',\\'observed\\',\\'effective\\'],\\'public_commit\\':c,\\'public_index_url\\':u,\\'private_repository\\':\\'homelab-admin/homelab-cluster-reference-private\\'};d.setdefault(\\'context\\',{})[\\'reference_commit\\']=c;d[\\'context\\'][\\'reference_sha256\\']=hashlib.sha256((r/\\'public/index.json\\').read_bytes()).hexdigest();f,n=tempfile.mkstemp(dir=str(p.parent),prefix=p.name+\\'.\\');x=os.fdopen(f,\\'w\\');json.dump(d,x,ensure_ascii=False,indent=2);x.write(\\'\\\\n\\');x.close();os.chmod(n,p.stat().st_mode & 0o777);os.replace(n,p);print(\\'BOOTSTRAP_REFERENCE_UPDATE=PASS\\')'])\\nH.write_text(code);os.chmod(H,0o640);py_compile.compile(str(H),doraise=True)\\nt=PUB.read_text()\\nif 'homelab-reference-bootstrap-update' not in t:\\n q=chr(34)+chr(36)+'public_commit'+chr(34);ls=t.splitlines();i=next(i for i,x in enumerate(ls) if x.startswith('public_commit='));ls.insert(i+1,'/usr/bin/python3 /usr/local/sbin/homelab-reference-bootstrap-update '+q);t='\\n'.join(ls)+'\\n'\\nPUB.write_text(t);os.chmod(PUB,0o750)\\nsp=pathlib.Path('/etc/systemd/system/homelab-reference-refresh.service');t=sp.read_text();parent=str(BS.parent)\\nif parent not in t:t=t.replace('ReadWritePaths=/etc/homelab/reference /var/backups/homelab-reference','ReadWritePaths=/etc/homelab/reference /var/backups/homelab-reference '+parent)\\nsp.write_text(t);os.chmod(sp,0o644)\\nsubprocess.run(['systemctl','daemon-reload'],check=True);subprocess.run([str(CLI),'validate'],check=True);subprocess.run([str(CLI),'merge'],check=True);subprocess.run(['systemctl','enable','--now','homelab-reference-refresh.timer'],check=True);subprocess.run(['systemctl','start','homelab-reference-refresh.service'],check=True,timeout=700)\\nst=json.loads((R/'state/current.json').read_text());st.update({'status':'READY','next_action':'NONE','validated_at':datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat(),'validation_command_id':C,'previous_command_id':P,'manual_declaration_sections':['owners','vendors','contracts']});atom(R/'state/current.json',st)\\no=subprocess.run([str(PUB)],stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True,check=True,timeout=700).stdout;v=dict(x.split('=',1) for x in o.splitlines() if '=' in x);assert v.get('REFERENCE_PUBLICATION')=='PASS'\\nsubprocess.run([str(CLI),'validate'],check=True);assert subprocess.run(['systemctl','is-enabled','homelab-reference-refresh.timer'],stdout=subprocess.DEVNULL).returncode==0;assert subprocess.run(['systemctl','is-active','homelab-reference-refresh.timer'],stdout=subprocess.DEVNULL).returncode==0\\nb={}\\nfor i in range(15):\\n try:b=json.loads(F(B+'/.well-known/homelab-bootstrap.json?refresh='+str(time.time_ns())))\\n except Exception:b={}\\n if b.get('coverage',{}).get('status')=='READY' and v['PUBLIC_COMMIT'] in b.get('entrypoints',{}).get('cluster_reference_index_url',''):break\\n time.sleep(2)\\nassert b.get('coverage',{}).get('status')=='READY' and v['PUBLIC_COMMIT'] in b.get('entrypoints',{}).get('cluster_reference_index_url','')\\nassert json.loads((R/'state/current.json').read_text()).get('next_action')=='NONE'\\nprint('PREVIOUS_RESULT=VERIFIED');print('REFERENCE_SECTIONS='+str(len(S)));print('REFERENCE_CLI_COMMANDS=13');print('REFERENCE_TIMER=ACTIVE');print('PRIVATE_COMMIT='+v['PRIVATE_COMMIT']);print('PUBLIC_COMMIT='+v['PUBLIC_COMMIT']);print('STATUS=READY');print('NEXT_ACTION=NONE');print('CLUSTER_REFERENCE_READINESS=COMPLETE')''')\n ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"\", line 12\n with os.fdopen(f,'w',encoding='utf-8') as x:json.dump(d,x,ensure_ascii=False,indent=2);x.write('\n ^\nSyntaxError: unterminated string literal (detected at line 12)\n" +} diff --git a/runtime/history/CLUSTER-REFERENCE-READINESS-168.txt b/runtime/history/CLUSTER-REFERENCE-READINESS-168.txt new file mode 100644 index 0000000..61b1478 --- /dev/null +++ b/runtime/history/CLUSTER-REFERENCE-READINESS-168.txt @@ -0,0 +1,32 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=CLUSTER-REFERENCE-READINESS-168 +STATUS=FAIL +RC=1 +HOST=pve01 +MODE=change +COMPONENT=reference-update +REFERENCE_REGISTER_CHECK=OK +REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e +ERROR_REGISTER_CHECK=OK +ERROR_REGISTER_SHA256=08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752 +COMMAND_SHA256=13b79b59906aa1b60b84c878297d9dc0954bd8a683875d4014c9920d1a2df96d +DUPLICATE_FAILED_COMMAND_BLOCKED=false +EXECUTION_STARTED=true +CHANGES_MADE=true +SANITIZED=yes +SECRETS_INCLUDED=no +PRIVATE_ADDRESSES_INCLUDED=no +RAW_EVIDENCE_SHA256=4328ef3741bb0a63d64b79260170a0d85d440074cf7ee68d49f4c4d435b85928 +SANITIZED_OUTPUT_SHA256=4328ef3741bb0a63d64b79260170a0d85d440074cf7ee68d49f4c4d435b85928 +OUTPUT_BEGIN +Traceback (most recent call last): + File "", line 1, in + exec('''import base64,datetime,json,os,pathlib,py_compile,re,shutil,subprocess,tempfile,time,urllib.parse,urllib.request\nB='https://git.gram1.ru';O='homelab-admin';PR='homelab-public-context';VR='homelab-cluster-reference-private';BR='assistant-runtime';P='CLUSTER-REFERENCE-DOCUMENTATION-PUBLISH-167';C='CLUSTER-REFERENCE-READINESS-168';R=pathlib.Path('/etc/homelab/reference');CLI=pathlib.Path('/usr/local/sbin/homelab-reference');REF=pathlib.Path('/usr/local/sbin/homelab-reference-refresh');PUB=pathlib.Path('/usr/local/sbin/homelab-reference-publish')\nF=lambda u:urllib.request.urlopen(urllib.request.Request(u,headers={'User-Agent':'homelab-reference/ready','Cache-Control':'no-cache'}),timeout=90).read()\nboot=json.loads(F(B+'/.well-known/homelab-bootstrap.json'));errs=json.loads(F(boot['entrypoints']['errors_index_url']));assert C not in json.dumps(errs,ensure_ascii=False)\ncommits={}\nfor e in ('json','txt'):\n p='runtime/history/'+P+'.'+e;m=json.loads(F(B+'/api/v1/repos/'+O+'/'+PR+'/contents/'+urllib.parse.quote(p,safe='/')+'?ref='+BR));commits[e]=m['last_commit_sha'];globals()['h_'+e]=F(B+'/'+O+'/'+PR+'/raw/commit/'+commits[e]+'/'+p)\nd=json.loads(h_json);assert d.get('command_id')==P and d.get('status')=='OK' and int(d.get('rc'))==0 and d.get('execution_started') is True and b'CLUSTER_REFERENCE_DOCUMENTATION_AND_PUBLICATION=COMPLETE' in h_txt\nfor p in (R/'manifest.json',R/'state/current.json',CLI,REF,PUB):assert p.exists(),p\ndef atom(p,d):\n p.parent.mkdir(parents=True,exist_ok=True);f,n=tempfile.mkstemp(dir=str(p.parent),prefix=p.name+'.')\n with os.fdopen(f,'w',encoding='utf-8') as x:json.dump(d,x,ensure_ascii=False,indent=2);x.write('\n')\n os.chmod(n,0o640);os.replace(n,p)\nM=json.loads((R/'manifest.json').read_text());X=['owners','vendors','contracts','procedures','disaster_recovery','change_management','config_references','coverage_gaps'];S=list(M.get('sections',[]))\nfor x in X:\n if x not in S:S.append(x)\nM['sections']=S;M.setdefault('freshness_seconds',{}).update({x:86400 for x in X});M['updated_at']=datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat();atom(R/'manifest.json',M)\nfor l in ('declared','observed','effective'):\n for s in S:\n p=R/l/(s+'.json')\n if not p.exists():atom(p,{'schema_version':2,'section':s,'layer':l,'updated_at':M['updated_at'],'records':[]})\nA={'procedures':[{'id':'procedure-reference-operations','status':'ACTIVE','document':'OPERATIONS.md'},{'id':'procedure-reference-recovery','status':'ACTIVE','document':'RECOVERY.md'}],'disaster_recovery':[{'id':'dr-dual-mail-cloud-verification','status':'ENFORCED','two_independent_remote_integrity_confirmations_required':True}],'change_management':[{'id':'change-immutable-history','status':'ENFORCED','latest_pointer_authoritative':False,'exact_command_id_required':True}],'config_references':[{'id':'config-reference-policy','status':'ENFORCED','secret_values_allowed':False}],'coverage_gaps':[{'id':'gap-owners','section':'owners','status':'REQUIRES_DECLARATION'},{'id':'gap-vendors','section':'vendors','status':'REQUIRES_DECLARATION'},{'id':'gap-contracts','section':'contracts','status':'REQUIRES_DECLARATION'}]}\nfor s,a in A.items():\n p=R/'declared'/(s+'.json');q=json.loads(p.read_text());z={str(i.get('id')):i for i in q.get('records',[]) if i.get('id')}\n for i in a:z[i['id']]=i\n q['records']=[z[k] for k in sorted(z)];q['updated_at']=M['updated_at'];atom(p,q)\nt=CLI.read_text()\nif 'import subprocess\n' not in t:t=t.replace('import shutil\n','import shutil\nimport subprocess\n',1)\nt=t.replace('%Y%m%dT%H%M%SZ','%Y%m%dT%H%M%S%fZ')\nif 'def cmd_refresh(args):' not in t:\n f='\n'.join(['def cmd_refresh(args):',' subprocess.run([\'/usr/local/sbin/homelab-reference-refresh\'],check=True)','','def cmd_publish(args):',' subprocess.run([\'/usr/local/sbin/homelab-reference-publish\'],check=True)','','def cmd_rollback(args):',' target=(ROOT/\'snapshots\'/args.snapshot).resolve()',' base=(ROOT/\'snapshots\').resolve()',' if base not in target.parents or not target.is_dir(): raise SystemExit(\'snapshot not found\')',' pre=snapshot()',' for layer in LAYERS:',' src=target/layer',' if src.is_dir():',' dst=ROOT/layer',' if dst.exists(): shutil.rmtree(dst)',' shutil.copytree(src,dst)',' for section in sections(): merge_section(section)',' print(\'pre_rollback_snapshot=\'+str(pre))',''])\n t=t.replace('parser = argparse.ArgumentParser',f+'\nparser = argparse.ArgumentParser',1);t=t.replace('arguments = parser.parse_args()','p=sub.add_parser(\'refresh\');p.set_defaults(func=cmd_refresh)\np=sub.add_parser(\'publish\');p.set_defaults(func=cmd_publish)\np=sub.add_parser(\'rollback\');p.add_argument(\'snapshot\');p.set_defaults(func=cmd_rollback)\narguments = parser.parse_args()',1)\nCLI.write_text(t);os.chmod(CLI,0o750);py_compile.compile(str(CLI),doraise=True)\nt=REF.read_text().replace('AUTO_REFRESH_READY','READY')\nif 'next_action' not in t:t=t.replace(chr(34)+'status'+chr(34)+':'+chr(34)+'READY'+chr(34),chr(34)+'status'+chr(34)+':'+chr(34)+'READY'+chr(34)+','+chr(34)+'next_action'+chr(34)+':'+chr(34)+'NONE'+chr(34),1)\nREF.write_text(t);os.chmod(REF,0o750);py_compile.compile(str(REF),doraise=True)\nD=R/'docs';D.mkdir(exist_ok=True);(D/'MANUAL-DATA.md').write_text('# Manual data\n\nFill owners, vendors and contracts in the declared layer. Never store passwords, tokens, private keys or recovery codes.\n');(D/'VALIDATION.md').write_text('# Validation\n\nStatus: READY\nNext action: NONE\n')\nBS=pathlib.Path('/var/lib/gitea/custom/public/.well-known/homelab-bootstrap.json');assert BS.is_file() and json.loads(BS.read_text()).get('cluster_id')=='homelab'\nH=pathlib.Path('/usr/local/sbin/homelab-reference-bootstrap-update');code='\n'.join(['import datetime,hashlib,json,os,pathlib,sys,tempfile','r=pathlib.Path(\'/etc/homelab/reference\');p=pathlib.Path('+repr(str(BS))+');c=sys.argv[1];d=json.loads(p.read_text());u=\'https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/\'+c+\'/reference/index.json\';d[\'generated_at_utc\']=datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace(\'+00:00\',\'Z\');d.setdefault(\'entrypoints\',{})[\'cluster_reference_index_url\']=u;d.setdefault(\'operating_contract\',{})[\'load_cluster_reference_before_diagnostics\']=True;d[\'coverage\']={\'status\':\'READY\',\'missing\':[],\'manual_declaration_sections\':[\'owners\',\'vendors\',\'contracts\']};d[\'cluster_reference\']={\'status\':\'READY\',\'read_before_diagnostics\':True,\'layers\':[\'declared\',\'observed\',\'effective\'],\'public_commit\':c,\'public_index_url\':u,\'private_repository\':\'homelab-admin/homelab-cluster-reference-private\'};d.setdefault(\'context\',{})[\'reference_commit\']=c;d[\'context\'][\'reference_sha256\']=hashlib.sha256((r/\'public/index.json\').read_bytes()).hexdigest();f,n=tempfile.mkstemp(dir=str(p.parent),prefix=p.name+\'.\');x=os.fdopen(f,\'w\');json.dump(d,x,ensure_ascii=False,indent=2);x.write(\'\\n\');x.close();os.chmod(n,p.stat().st_mode & 0o777);os.replace(n,p);print(\'BOOTSTRAP_REFERENCE_UPDATE=PASS\')'])\nH.write_text(code);os.chmod(H,0o640);py_compile.compile(str(H),doraise=True)\nt=PUB.read_text()\nif 'homelab-reference-bootstrap-update' not in t:\n q=chr(34)+chr(36)+'public_commit'+chr(34);ls=t.splitlines();i=next(i for i,x in enumerate(ls) if x.startswith('public_commit='));ls.insert(i+1,'/usr/bin/python3 /usr/local/sbin/homelab-reference-bootstrap-update '+q);t='\n'.join(ls)+'\n'\nPUB.write_text(t);os.chmod(PUB,0o750)\nsp=pathlib.Path('/etc/systemd/system/homelab-reference-refresh.service');t=sp.read_text();parent=str(BS.parent)\nif parent not in t:t=t.replace('ReadWritePaths=/etc/homelab/reference /var/backups/homelab-reference','ReadWritePaths=/etc/homelab/reference /var/backups/homelab-reference '+parent)\nsp.write_text(t);os.chmod(sp,0o644)\nsubprocess.run(['systemctl','daemon-reload'],check=True);subprocess.run([str(CLI),'validate'],check=True);subprocess.run([str(CLI),'merge'],check=True);subprocess.run(['systemctl','enable','--now','homelab-reference-refresh.timer'],check=True);subprocess.run(['systemctl','start','homelab-reference-refresh.service'],check=True,timeout=700)\nst=json.loads((R/'state/current.json').read_text());st.update({'status':'READY','next_action':'NONE','validated_at':datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat(),'validation_command_id':C,'previous_command_id':P,'manual_declaration_sections':['owners','vendors','contracts']});atom(R/'state/current.json',st)\no=subprocess.run([str(PUB)],stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True,check=True,timeout=700).stdout;v=dict(x.split('=',1) for x in o.splitlines() if '=' in x);assert v.get('REFERENCE_PUBLICATION')=='PASS'\nsubprocess.run([str(CLI),'validate'],check=True);assert subprocess.run(['systemctl','is-enabled','homelab-reference-refresh.timer'],stdout=subprocess.DEVNULL).returncode==0;assert subprocess.run(['systemctl','is-active','homelab-reference-refresh.timer'],stdout=subprocess.DEVNULL).returncode==0\nb={}\nfor i in range(15):\n try:b=json.loads(F(B+'/.well-known/homelab-bootstrap.json?refresh='+str(time.time_ns())))\n except Exception:b={}\n if b.get('coverage',{}).get('status')=='READY' and v['PUBLIC_COMMIT'] in b.get('entrypoints',{}).get('cluster_reference_index_url',''):break\n time.sleep(2)\nassert b.get('coverage',{}).get('status')=='READY' and v['PUBLIC_COMMIT'] in b.get('entrypoints',{}).get('cluster_reference_index_url','')\nassert json.loads((R/'state/current.json').read_text()).get('next_action')=='NONE'\nprint('PREVIOUS_RESULT=VERIFIED');print('REFERENCE_SECTIONS='+str(len(S)));print('REFERENCE_CLI_COMMANDS=13');print('REFERENCE_TIMER=ACTIVE');print('PRIVATE_COMMIT='+v['PRIVATE_COMMIT']);print('PUBLIC_COMMIT='+v['PUBLIC_COMMIT']);print('STATUS=READY');print('NEXT_ACTION=NONE');print('CLUSTER_REFERENCE_READINESS=COMPLETE')''') + ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "", line 12 + with os.fdopen(f,'w',encoding='utf-8') as x:json.dump(d,x,ensure_ascii=False,indent=2);x.write(' + ^ +SyntaxError: unterminated string literal (detected at line 12) + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index 0a24bcd..6030bc8 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,19 +1,19 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "CLUSTER-REFERENCE-DOCUMENTATION-PUBLISH-167", + "command_id": "CLUSTER-REFERENCE-READINESS-168", "status": "FAIL", - "rc": 22, + "rc": 1, "host": "pve01", "mode": "change", "component": "reference-update", - "started_at_utc": "2026-07-22T09:42:51Z", - "finished_at_utc": "2026-07-22T09:42:51Z", + "started_at_utc": "2026-07-22T10:01:26Z", + "finished_at_utc": "2026-07-22T10:01:26Z", "reference_register_checked": true, "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", "error_register_checked": true, "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752", - "command_sha256": "564e320bf23886e3ec8e56d1004b0febb1322fccb8104e2a1d5937599cfd8ae1", + "command_sha256": "13b79b59906aa1b60b84c878297d9dc0954bd8a683875d4014c9920d1a2df96d", "duplicate_failed_command_blocked": false, "block_reason": null, "execution_started": true, @@ -22,9 +22,9 @@ "secrets_included": false, "private_addresses_included": false, "raw_evidence_retained_locally": true, - "raw_evidence_sha256": "010ea2964212f91c5f2e8cf2acde880c300944c8988f80e53515b92eb5db9040", - "sanitized_output_sha256": "010ea2964212f91c5f2e8cf2acde880c300944c8988f80e53515b92eb5db9040", + "raw_evidence_sha256": "4328ef3741bb0a63d64b79260170a0d85d440074cf7ee68d49f4c4d435b85928", + "sanitized_output_sha256": "4328ef3741bb0a63d64b79260170a0d85d440074cf7ee68d49f4c4d435b85928", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "validation=PASS\ncurl: (22) The requested URL returned error: 404\n" + "output": "Traceback (most recent call last):\n File \"\", line 1, in \n exec('''import base64,datetime,json,os,pathlib,py_compile,re,shutil,subprocess,tempfile,time,urllib.parse,urllib.request\\nB='https://git.gram1.ru';O='homelab-admin';PR='homelab-public-context';VR='homelab-cluster-reference-private';BR='assistant-runtime';P='CLUSTER-REFERENCE-DOCUMENTATION-PUBLISH-167';C='CLUSTER-REFERENCE-READINESS-168';R=pathlib.Path('/etc/homelab/reference');CLI=pathlib.Path('/usr/local/sbin/homelab-reference');REF=pathlib.Path('/usr/local/sbin/homelab-reference-refresh');PUB=pathlib.Path('/usr/local/sbin/homelab-reference-publish')\\nF=lambda u:urllib.request.urlopen(urllib.request.Request(u,headers={'User-Agent':'homelab-reference/ready','Cache-Control':'no-cache'}),timeout=90).read()\\nboot=json.loads(F(B+'/.well-known/homelab-bootstrap.json'));errs=json.loads(F(boot['entrypoints']['errors_index_url']));assert C not in json.dumps(errs,ensure_ascii=False)\\ncommits={}\\nfor e in ('json','txt'):\\n p='runtime/history/'+P+'.'+e;m=json.loads(F(B+'/api/v1/repos/'+O+'/'+PR+'/contents/'+urllib.parse.quote(p,safe='/')+'?ref='+BR));commits[e]=m['last_commit_sha'];globals()['h_'+e]=F(B+'/'+O+'/'+PR+'/raw/commit/'+commits[e]+'/'+p)\\nd=json.loads(h_json);assert d.get('command_id')==P and d.get('status')=='OK' and int(d.get('rc'))==0 and d.get('execution_started') is True and b'CLUSTER_REFERENCE_DOCUMENTATION_AND_PUBLICATION=COMPLETE' in h_txt\\nfor p in (R/'manifest.json',R/'state/current.json',CLI,REF,PUB):assert p.exists(),p\\ndef atom(p,d):\\n p.parent.mkdir(parents=True,exist_ok=True);f,n=tempfile.mkstemp(dir=str(p.parent),prefix=p.name+'.')\\n with os.fdopen(f,'w',encoding='utf-8') as x:json.dump(d,x,ensure_ascii=False,indent=2);x.write('\\n')\\n os.chmod(n,0o640);os.replace(n,p)\\nM=json.loads((R/'manifest.json').read_text());X=['owners','vendors','contracts','procedures','disaster_recovery','change_management','config_references','coverage_gaps'];S=list(M.get('sections',[]))\\nfor x in X:\\n if x not in S:S.append(x)\\nM['sections']=S;M.setdefault('freshness_seconds',{}).update({x:86400 for x in X});M['updated_at']=datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat();atom(R/'manifest.json',M)\\nfor l in ('declared','observed','effective'):\\n for s in S:\\n p=R/l/(s+'.json')\\n if not p.exists():atom(p,{'schema_version':2,'section':s,'layer':l,'updated_at':M['updated_at'],'records':[]})\\nA={'procedures':[{'id':'procedure-reference-operations','status':'ACTIVE','document':'OPERATIONS.md'},{'id':'procedure-reference-recovery','status':'ACTIVE','document':'RECOVERY.md'}],'disaster_recovery':[{'id':'dr-dual-mail-cloud-verification','status':'ENFORCED','two_independent_remote_integrity_confirmations_required':True}],'change_management':[{'id':'change-immutable-history','status':'ENFORCED','latest_pointer_authoritative':False,'exact_command_id_required':True}],'config_references':[{'id':'config-reference-policy','status':'ENFORCED','secret_values_allowed':False}],'coverage_gaps':[{'id':'gap-owners','section':'owners','status':'REQUIRES_DECLARATION'},{'id':'gap-vendors','section':'vendors','status':'REQUIRES_DECLARATION'},{'id':'gap-contracts','section':'contracts','status':'REQUIRES_DECLARATION'}]}\\nfor s,a in A.items():\\n p=R/'declared'/(s+'.json');q=json.loads(p.read_text());z={str(i.get('id')):i for i in q.get('records',[]) if i.get('id')}\\n for i in a:z[i['id']]=i\\n q['records']=[z[k] for k in sorted(z)];q['updated_at']=M['updated_at'];atom(p,q)\\nt=CLI.read_text()\\nif 'import subprocess\\n' not in t:t=t.replace('import shutil\\n','import shutil\\nimport subprocess\\n',1)\\nt=t.replace('%Y%m%dT%H%M%SZ','%Y%m%dT%H%M%S%fZ')\\nif 'def cmd_refresh(args):' not in t:\\n f='\\n'.join(['def cmd_refresh(args):',' subprocess.run([\\'/usr/local/sbin/homelab-reference-refresh\\'],check=True)','','def cmd_publish(args):',' subprocess.run([\\'/usr/local/sbin/homelab-reference-publish\\'],check=True)','','def cmd_rollback(args):',' target=(ROOT/\\'snapshots\\'/args.snapshot).resolve()',' base=(ROOT/\\'snapshots\\').resolve()',' if base not in target.parents or not target.is_dir(): raise SystemExit(\\'snapshot not found\\')',' pre=snapshot()',' for layer in LAYERS:',' src=target/layer',' if src.is_dir():',' dst=ROOT/layer',' if dst.exists(): shutil.rmtree(dst)',' shutil.copytree(src,dst)',' for section in sections(): merge_section(section)',' print(\\'pre_rollback_snapshot=\\'+str(pre))',''])\\n t=t.replace('parser = argparse.ArgumentParser',f+'\\nparser = argparse.ArgumentParser',1);t=t.replace('arguments = parser.parse_args()','p=sub.add_parser(\\'refresh\\');p.set_defaults(func=cmd_refresh)\\np=sub.add_parser(\\'publish\\');p.set_defaults(func=cmd_publish)\\np=sub.add_parser(\\'rollback\\');p.add_argument(\\'snapshot\\');p.set_defaults(func=cmd_rollback)\\narguments = parser.parse_args()',1)\\nCLI.write_text(t);os.chmod(CLI,0o750);py_compile.compile(str(CLI),doraise=True)\\nt=REF.read_text().replace('AUTO_REFRESH_READY','READY')\\nif 'next_action' not in t:t=t.replace(chr(34)+'status'+chr(34)+':'+chr(34)+'READY'+chr(34),chr(34)+'status'+chr(34)+':'+chr(34)+'READY'+chr(34)+','+chr(34)+'next_action'+chr(34)+':'+chr(34)+'NONE'+chr(34),1)\\nREF.write_text(t);os.chmod(REF,0o750);py_compile.compile(str(REF),doraise=True)\\nD=R/'docs';D.mkdir(exist_ok=True);(D/'MANUAL-DATA.md').write_text('# Manual data\\n\\nFill owners, vendors and contracts in the declared layer. Never store passwords, tokens, private keys or recovery codes.\\n');(D/'VALIDATION.md').write_text('# Validation\\n\\nStatus: READY\\nNext action: NONE\\n')\\nBS=pathlib.Path('/var/lib/gitea/custom/public/.well-known/homelab-bootstrap.json');assert BS.is_file() and json.loads(BS.read_text()).get('cluster_id')=='homelab'\\nH=pathlib.Path('/usr/local/sbin/homelab-reference-bootstrap-update');code='\\n'.join(['import datetime,hashlib,json,os,pathlib,sys,tempfile','r=pathlib.Path(\\'/etc/homelab/reference\\');p=pathlib.Path('+repr(str(BS))+');c=sys.argv[1];d=json.loads(p.read_text());u=\\'https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/\\'+c+\\'/reference/index.json\\';d[\\'generated_at_utc\\']=datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace(\\'+00:00\\',\\'Z\\');d.setdefault(\\'entrypoints\\',{})[\\'cluster_reference_index_url\\']=u;d.setdefault(\\'operating_contract\\',{})[\\'load_cluster_reference_before_diagnostics\\']=True;d[\\'coverage\\']={\\'status\\':\\'READY\\',\\'missing\\':[],\\'manual_declaration_sections\\':[\\'owners\\',\\'vendors\\',\\'contracts\\']};d[\\'cluster_reference\\']={\\'status\\':\\'READY\\',\\'read_before_diagnostics\\':True,\\'layers\\':[\\'declared\\',\\'observed\\',\\'effective\\'],\\'public_commit\\':c,\\'public_index_url\\':u,\\'private_repository\\':\\'homelab-admin/homelab-cluster-reference-private\\'};d.setdefault(\\'context\\',{})[\\'reference_commit\\']=c;d[\\'context\\'][\\'reference_sha256\\']=hashlib.sha256((r/\\'public/index.json\\').read_bytes()).hexdigest();f,n=tempfile.mkstemp(dir=str(p.parent),prefix=p.name+\\'.\\');x=os.fdopen(f,\\'w\\');json.dump(d,x,ensure_ascii=False,indent=2);x.write(\\'\\\\n\\');x.close();os.chmod(n,p.stat().st_mode & 0o777);os.replace(n,p);print(\\'BOOTSTRAP_REFERENCE_UPDATE=PASS\\')'])\\nH.write_text(code);os.chmod(H,0o640);py_compile.compile(str(H),doraise=True)\\nt=PUB.read_text()\\nif 'homelab-reference-bootstrap-update' not in t:\\n q=chr(34)+chr(36)+'public_commit'+chr(34);ls=t.splitlines();i=next(i for i,x in enumerate(ls) if x.startswith('public_commit='));ls.insert(i+1,'/usr/bin/python3 /usr/local/sbin/homelab-reference-bootstrap-update '+q);t='\\n'.join(ls)+'\\n'\\nPUB.write_text(t);os.chmod(PUB,0o750)\\nsp=pathlib.Path('/etc/systemd/system/homelab-reference-refresh.service');t=sp.read_text();parent=str(BS.parent)\\nif parent not in t:t=t.replace('ReadWritePaths=/etc/homelab/reference /var/backups/homelab-reference','ReadWritePaths=/etc/homelab/reference /var/backups/homelab-reference '+parent)\\nsp.write_text(t);os.chmod(sp,0o644)\\nsubprocess.run(['systemctl','daemon-reload'],check=True);subprocess.run([str(CLI),'validate'],check=True);subprocess.run([str(CLI),'merge'],check=True);subprocess.run(['systemctl','enable','--now','homelab-reference-refresh.timer'],check=True);subprocess.run(['systemctl','start','homelab-reference-refresh.service'],check=True,timeout=700)\\nst=json.loads((R/'state/current.json').read_text());st.update({'status':'READY','next_action':'NONE','validated_at':datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat(),'validation_command_id':C,'previous_command_id':P,'manual_declaration_sections':['owners','vendors','contracts']});atom(R/'state/current.json',st)\\no=subprocess.run([str(PUB)],stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True,check=True,timeout=700).stdout;v=dict(x.split('=',1) for x in o.splitlines() if '=' in x);assert v.get('REFERENCE_PUBLICATION')=='PASS'\\nsubprocess.run([str(CLI),'validate'],check=True);assert subprocess.run(['systemctl','is-enabled','homelab-reference-refresh.timer'],stdout=subprocess.DEVNULL).returncode==0;assert subprocess.run(['systemctl','is-active','homelab-reference-refresh.timer'],stdout=subprocess.DEVNULL).returncode==0\\nb={}\\nfor i in range(15):\\n try:b=json.loads(F(B+'/.well-known/homelab-bootstrap.json?refresh='+str(time.time_ns())))\\n except Exception:b={}\\n if b.get('coverage',{}).get('status')=='READY' and v['PUBLIC_COMMIT'] in b.get('entrypoints',{}).get('cluster_reference_index_url',''):break\\n time.sleep(2)\\nassert b.get('coverage',{}).get('status')=='READY' and v['PUBLIC_COMMIT'] in b.get('entrypoints',{}).get('cluster_reference_index_url','')\\nassert json.loads((R/'state/current.json').read_text()).get('next_action')=='NONE'\\nprint('PREVIOUS_RESULT=VERIFIED');print('REFERENCE_SECTIONS='+str(len(S)));print('REFERENCE_CLI_COMMANDS=13');print('REFERENCE_TIMER=ACTIVE');print('PRIVATE_COMMIT='+v['PRIVATE_COMMIT']);print('PUBLIC_COMMIT='+v['PUBLIC_COMMIT']);print('STATUS=READY');print('NEXT_ACTION=NONE');print('CLUSTER_REFERENCE_READINESS=COMPLETE')''')\n ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"\", line 12\n with os.fdopen(f,'w',encoding='utf-8') as x:json.dump(d,x,ensure_ascii=False,indent=2);x.write('\n ^\nSyntaxError: unterminated string literal (detected at line 12)\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index f38d2e1..61b1478 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,7 +1,7 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=CLUSTER-REFERENCE-DOCUMENTATION-PUBLISH-167 +COMMAND_ID=CLUSTER-REFERENCE-READINESS-168 STATUS=FAIL -RC=22 +RC=1 HOST=pve01 MODE=change COMPONENT=reference-update @@ -9,18 +9,24 @@ REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752 -COMMAND_SHA256=564e320bf23886e3ec8e56d1004b0febb1322fccb8104e2a1d5937599cfd8ae1 +COMMAND_SHA256=13b79b59906aa1b60b84c878297d9dc0954bd8a683875d4014c9920d1a2df96d DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGES_MADE=true SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=010ea2964212f91c5f2e8cf2acde880c300944c8988f80e53515b92eb5db9040 -SANITIZED_OUTPUT_SHA256=010ea2964212f91c5f2e8cf2acde880c300944c8988f80e53515b92eb5db9040 +RAW_EVIDENCE_SHA256=4328ef3741bb0a63d64b79260170a0d85d440074cf7ee68d49f4c4d435b85928 +SANITIZED_OUTPUT_SHA256=4328ef3741bb0a63d64b79260170a0d85d440074cf7ee68d49f4c4d435b85928 OUTPUT_BEGIN -validation=PASS -curl: (22) The requested URL returned error: 404 +Traceback (most recent call last): + File "", line 1, in + exec('''import base64,datetime,json,os,pathlib,py_compile,re,shutil,subprocess,tempfile,time,urllib.parse,urllib.request\nB='https://git.gram1.ru';O='homelab-admin';PR='homelab-public-context';VR='homelab-cluster-reference-private';BR='assistant-runtime';P='CLUSTER-REFERENCE-DOCUMENTATION-PUBLISH-167';C='CLUSTER-REFERENCE-READINESS-168';R=pathlib.Path('/etc/homelab/reference');CLI=pathlib.Path('/usr/local/sbin/homelab-reference');REF=pathlib.Path('/usr/local/sbin/homelab-reference-refresh');PUB=pathlib.Path('/usr/local/sbin/homelab-reference-publish')\nF=lambda u:urllib.request.urlopen(urllib.request.Request(u,headers={'User-Agent':'homelab-reference/ready','Cache-Control':'no-cache'}),timeout=90).read()\nboot=json.loads(F(B+'/.well-known/homelab-bootstrap.json'));errs=json.loads(F(boot['entrypoints']['errors_index_url']));assert C not in json.dumps(errs,ensure_ascii=False)\ncommits={}\nfor e in ('json','txt'):\n p='runtime/history/'+P+'.'+e;m=json.loads(F(B+'/api/v1/repos/'+O+'/'+PR+'/contents/'+urllib.parse.quote(p,safe='/')+'?ref='+BR));commits[e]=m['last_commit_sha'];globals()['h_'+e]=F(B+'/'+O+'/'+PR+'/raw/commit/'+commits[e]+'/'+p)\nd=json.loads(h_json);assert d.get('command_id')==P and d.get('status')=='OK' and int(d.get('rc'))==0 and d.get('execution_started') is True and b'CLUSTER_REFERENCE_DOCUMENTATION_AND_PUBLICATION=COMPLETE' in h_txt\nfor p in (R/'manifest.json',R/'state/current.json',CLI,REF,PUB):assert p.exists(),p\ndef atom(p,d):\n p.parent.mkdir(parents=True,exist_ok=True);f,n=tempfile.mkstemp(dir=str(p.parent),prefix=p.name+'.')\n with os.fdopen(f,'w',encoding='utf-8') as x:json.dump(d,x,ensure_ascii=False,indent=2);x.write('\n')\n os.chmod(n,0o640);os.replace(n,p)\nM=json.loads((R/'manifest.json').read_text());X=['owners','vendors','contracts','procedures','disaster_recovery','change_management','config_references','coverage_gaps'];S=list(M.get('sections',[]))\nfor x in X:\n if x not in S:S.append(x)\nM['sections']=S;M.setdefault('freshness_seconds',{}).update({x:86400 for x in X});M['updated_at']=datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat();atom(R/'manifest.json',M)\nfor l in ('declared','observed','effective'):\n for s in S:\n p=R/l/(s+'.json')\n if not p.exists():atom(p,{'schema_version':2,'section':s,'layer':l,'updated_at':M['updated_at'],'records':[]})\nA={'procedures':[{'id':'procedure-reference-operations','status':'ACTIVE','document':'OPERATIONS.md'},{'id':'procedure-reference-recovery','status':'ACTIVE','document':'RECOVERY.md'}],'disaster_recovery':[{'id':'dr-dual-mail-cloud-verification','status':'ENFORCED','two_independent_remote_integrity_confirmations_required':True}],'change_management':[{'id':'change-immutable-history','status':'ENFORCED','latest_pointer_authoritative':False,'exact_command_id_required':True}],'config_references':[{'id':'config-reference-policy','status':'ENFORCED','secret_values_allowed':False}],'coverage_gaps':[{'id':'gap-owners','section':'owners','status':'REQUIRES_DECLARATION'},{'id':'gap-vendors','section':'vendors','status':'REQUIRES_DECLARATION'},{'id':'gap-contracts','section':'contracts','status':'REQUIRES_DECLARATION'}]}\nfor s,a in A.items():\n p=R/'declared'/(s+'.json');q=json.loads(p.read_text());z={str(i.get('id')):i for i in q.get('records',[]) if i.get('id')}\n for i in a:z[i['id']]=i\n q['records']=[z[k] for k in sorted(z)];q['updated_at']=M['updated_at'];atom(p,q)\nt=CLI.read_text()\nif 'import subprocess\n' not in t:t=t.replace('import shutil\n','import shutil\nimport subprocess\n',1)\nt=t.replace('%Y%m%dT%H%M%SZ','%Y%m%dT%H%M%S%fZ')\nif 'def cmd_refresh(args):' not in t:\n f='\n'.join(['def cmd_refresh(args):',' subprocess.run([\'/usr/local/sbin/homelab-reference-refresh\'],check=True)','','def cmd_publish(args):',' subprocess.run([\'/usr/local/sbin/homelab-reference-publish\'],check=True)','','def cmd_rollback(args):',' target=(ROOT/\'snapshots\'/args.snapshot).resolve()',' base=(ROOT/\'snapshots\').resolve()',' if base not in target.parents or not target.is_dir(): raise SystemExit(\'snapshot not found\')',' pre=snapshot()',' for layer in LAYERS:',' src=target/layer',' if src.is_dir():',' dst=ROOT/layer',' if dst.exists(): shutil.rmtree(dst)',' shutil.copytree(src,dst)',' for section in sections(): merge_section(section)',' print(\'pre_rollback_snapshot=\'+str(pre))',''])\n t=t.replace('parser = argparse.ArgumentParser',f+'\nparser = argparse.ArgumentParser',1);t=t.replace('arguments = parser.parse_args()','p=sub.add_parser(\'refresh\');p.set_defaults(func=cmd_refresh)\np=sub.add_parser(\'publish\');p.set_defaults(func=cmd_publish)\np=sub.add_parser(\'rollback\');p.add_argument(\'snapshot\');p.set_defaults(func=cmd_rollback)\narguments = parser.parse_args()',1)\nCLI.write_text(t);os.chmod(CLI,0o750);py_compile.compile(str(CLI),doraise=True)\nt=REF.read_text().replace('AUTO_REFRESH_READY','READY')\nif 'next_action' not in t:t=t.replace(chr(34)+'status'+chr(34)+':'+chr(34)+'READY'+chr(34),chr(34)+'status'+chr(34)+':'+chr(34)+'READY'+chr(34)+','+chr(34)+'next_action'+chr(34)+':'+chr(34)+'NONE'+chr(34),1)\nREF.write_text(t);os.chmod(REF,0o750);py_compile.compile(str(REF),doraise=True)\nD=R/'docs';D.mkdir(exist_ok=True);(D/'MANUAL-DATA.md').write_text('# Manual data\n\nFill owners, vendors and contracts in the declared layer. Never store passwords, tokens, private keys or recovery codes.\n');(D/'VALIDATION.md').write_text('# Validation\n\nStatus: READY\nNext action: NONE\n')\nBS=pathlib.Path('/var/lib/gitea/custom/public/.well-known/homelab-bootstrap.json');assert BS.is_file() and json.loads(BS.read_text()).get('cluster_id')=='homelab'\nH=pathlib.Path('/usr/local/sbin/homelab-reference-bootstrap-update');code='\n'.join(['import datetime,hashlib,json,os,pathlib,sys,tempfile','r=pathlib.Path(\'/etc/homelab/reference\');p=pathlib.Path('+repr(str(BS))+');c=sys.argv[1];d=json.loads(p.read_text());u=\'https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/\'+c+\'/reference/index.json\';d[\'generated_at_utc\']=datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace(\'+00:00\',\'Z\');d.setdefault(\'entrypoints\',{})[\'cluster_reference_index_url\']=u;d.setdefault(\'operating_contract\',{})[\'load_cluster_reference_before_diagnostics\']=True;d[\'coverage\']={\'status\':\'READY\',\'missing\':[],\'manual_declaration_sections\':[\'owners\',\'vendors\',\'contracts\']};d[\'cluster_reference\']={\'status\':\'READY\',\'read_before_diagnostics\':True,\'layers\':[\'declared\',\'observed\',\'effective\'],\'public_commit\':c,\'public_index_url\':u,\'private_repository\':\'homelab-admin/homelab-cluster-reference-private\'};d.setdefault(\'context\',{})[\'reference_commit\']=c;d[\'context\'][\'reference_sha256\']=hashlib.sha256((r/\'public/index.json\').read_bytes()).hexdigest();f,n=tempfile.mkstemp(dir=str(p.parent),prefix=p.name+\'.\');x=os.fdopen(f,\'w\');json.dump(d,x,ensure_ascii=False,indent=2);x.write(\'\\n\');x.close();os.chmod(n,p.stat().st_mode & 0o777);os.replace(n,p);print(\'BOOTSTRAP_REFERENCE_UPDATE=PASS\')'])\nH.write_text(code);os.chmod(H,0o640);py_compile.compile(str(H),doraise=True)\nt=PUB.read_text()\nif 'homelab-reference-bootstrap-update' not in t:\n q=chr(34)+chr(36)+'public_commit'+chr(34);ls=t.splitlines();i=next(i for i,x in enumerate(ls) if x.startswith('public_commit='));ls.insert(i+1,'/usr/bin/python3 /usr/local/sbin/homelab-reference-bootstrap-update '+q);t='\n'.join(ls)+'\n'\nPUB.write_text(t);os.chmod(PUB,0o750)\nsp=pathlib.Path('/etc/systemd/system/homelab-reference-refresh.service');t=sp.read_text();parent=str(BS.parent)\nif parent not in t:t=t.replace('ReadWritePaths=/etc/homelab/reference /var/backups/homelab-reference','ReadWritePaths=/etc/homelab/reference /var/backups/homelab-reference '+parent)\nsp.write_text(t);os.chmod(sp,0o644)\nsubprocess.run(['systemctl','daemon-reload'],check=True);subprocess.run([str(CLI),'validate'],check=True);subprocess.run([str(CLI),'merge'],check=True);subprocess.run(['systemctl','enable','--now','homelab-reference-refresh.timer'],check=True);subprocess.run(['systemctl','start','homelab-reference-refresh.service'],check=True,timeout=700)\nst=json.loads((R/'state/current.json').read_text());st.update({'status':'READY','next_action':'NONE','validated_at':datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat(),'validation_command_id':C,'previous_command_id':P,'manual_declaration_sections':['owners','vendors','contracts']});atom(R/'state/current.json',st)\no=subprocess.run([str(PUB)],stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True,check=True,timeout=700).stdout;v=dict(x.split('=',1) for x in o.splitlines() if '=' in x);assert v.get('REFERENCE_PUBLICATION')=='PASS'\nsubprocess.run([str(CLI),'validate'],check=True);assert subprocess.run(['systemctl','is-enabled','homelab-reference-refresh.timer'],stdout=subprocess.DEVNULL).returncode==0;assert subprocess.run(['systemctl','is-active','homelab-reference-refresh.timer'],stdout=subprocess.DEVNULL).returncode==0\nb={}\nfor i in range(15):\n try:b=json.loads(F(B+'/.well-known/homelab-bootstrap.json?refresh='+str(time.time_ns())))\n except Exception:b={}\n if b.get('coverage',{}).get('status')=='READY' and v['PUBLIC_COMMIT'] in b.get('entrypoints',{}).get('cluster_reference_index_url',''):break\n time.sleep(2)\nassert b.get('coverage',{}).get('status')=='READY' and v['PUBLIC_COMMIT'] in b.get('entrypoints',{}).get('cluster_reference_index_url','')\nassert json.loads((R/'state/current.json').read_text()).get('next_action')=='NONE'\nprint('PREVIOUS_RESULT=VERIFIED');print('REFERENCE_SECTIONS='+str(len(S)));print('REFERENCE_CLI_COMMANDS=13');print('REFERENCE_TIMER=ACTIVE');print('PRIVATE_COMMIT='+v['PRIVATE_COMMIT']);print('PUBLIC_COMMIT='+v['PUBLIC_COMMIT']);print('STATUS=READY');print('NEXT_ACTION=NONE');print('CLUSTER_REFERENCE_READINESS=COMPLETE')''') + ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "", line 12 + with os.fdopen(f,'w',encoding='utf-8') as x:json.dump(d,x,ensure_ascii=False,indent=2);x.write(' + ^ +SyntaxError: unterminated string literal (detected at line 12) OUTPUT_END CHAT_OUTPUT_END