{
  "schema_version": 1,
  "channel": "homelab-runtime",
  "command_id": "RESULT-API-PATCH-AUDIT-20260727T075149Z",
  "status": "OK",
  "rc": 0,
  "host": "pve01",
  "mode": "verify",
  "component": "result-integration",
  "started_at_utc": "2026-07-27T07:52:45Z",
  "finished_at_utc": "2026-07-27T07:52:45Z",
  "reference_register_checked": true,
  "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e",
  "error_register_checked": true,
  "error_register_sha256": "24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83",
  "command_sha256": "b564f92f4324ba19d5c6752e0c53111024fd37092acacc2281d2ab9ac7f39359",
  "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": "1dabd515e3ddd0d132d8f6cd354770e78207200337dfda97f41dcacb8b3b576d",
  "sanitized_output_sha256": "1dabd515e3ddd0d132d8f6cd354770e78207200337dfda97f41dcacb8b3b576d",
  "output_truncated_in_json": false,
  "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt",
  "output": "{\"adapter_functions\":{\"atomic_json\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"path\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"value\"}],\"is_async\":false,\"line_end\":238,\"line_start\":202,\"name\":\"atomic_json\"},\"dispatch\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"request\"}],\"is_async\":false,\"line_end\":2502,\"line_start\":2419,\"name\":\"dispatch\"},\"load_json\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"path\"}],\"is_async\":false,\"line_end\":248,\"line_start\":241,\"name\":\"load_json\"},\"public_state\":{\"arguments\":[{\"has_default\":false,\"kind\":\"keyword_only\",\"name\":\"short_id\"},{\"has_default\":false,\"kind\":\"keyword_only\",\"name\":\"session_token\"},{\"has_default\":false,\"kind\":\"keyword_only\",\"name\":\"client_ip\"}],\"is_async\":false,\"line_end\":1324,\"line_start\":1311,\"name\":\"public_state\"},\"run_command\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"args\"},{\"has_default\":true,\"kind\":\"keyword_only\",\"name\":\"timeout\"},{\"has_default\":true,\"kind\":\"keyword_only\",\"name\":\"env\"}],\"is_async\":false,\"line_end\":673,\"line_start\":658,\"name\":\"run_command\"},\"sanitize_state\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"state\"}],\"is_async\":false,\"line_end\":1372,\"line_start\":1327,\"name\":\"sanitize_state\"},\"sha256_file\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"path\"}],\"is_async\":false,\"line_end\":199,\"line_start\":194,\"name\":\"sha256_file\"},\"state_path\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"short_id\"}],\"is_async\":false,\"line_end\":638,\"line_start\":635,\"name\":\"state_path\"},\"worker\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"short_id\"}],\"is_async\":false,\"line_end\":2183,\"line_start\":1994,\"name\":\"worker\"}},\"backup_changed\":false,\"changes_made\":false,\"checks\":{\"adapter_functions_complete\":true,\"adapter_healthy\":true,\"adapter_sha\":true,\"current_running_once\":true,\"no_invalid_states\":true,\"no_other_running\":true,\"portal_functions_complete\":true,\"portal_handler_do_get_present\":true,\"portal_handler_present\":true,\"portal_handler_reply_present\":true,\"portal_healthy\":true,\"portal_sha\":true,\"runner_sha\":true,\"source_excerpts_sanitized\":true},\"cluster_changed\":false,\"command_id\":\"RESULT-API-PATCH-AUDIT-20260727T075149Z\",\"gitea_changed\":false,\"plan_contract\":{\"adapter_operations\":[\"result_public\",\"result_public_key\"],\"create\":[\"/var/lib/homelab-command-adapter/result-signing/private.pem\",\"/var/lib/homelab-command-adapter/result-signing/public.pem\"],\"modify\":[\"/usr/local/sbin/homelab-command-adapter\",\"/usr/local/sbin/homelab-command-portal\"],\"preserve\":[\"/usr/local/sbin/homelab-chat-run\",\"existing state files\",\"existing evidence objects\",\"backup\",\"cluster\",\"Gitea history\"],\"public_routes\":[\"/.well-known/homelab-result/<command_id>/<capsule_sha256>.json\",\"/.well-known/homelab-result-key.pem\"]},\"portal_classes\":{\"Handler\":{\"line_end\":892,\"line_start\":451,\"methods\":[{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"fmt\"},{\"has_default\":false,\"kind\":\"var_positional\",\"name\":\"args\"}],\"is_async\":false,\"line_end\":469,\"line_start\":455,\"name\":\"log_message\"},{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"status\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"content_type\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"body\"},{\"has_default\":true,\"kind\":\"keyword_only\",\"name\":\"headers\"}],\"is_async\":false,\"line_end\":504,\"line_start\":471,\"name\":\"reply\"},{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"location\"},{\"has_default\":true,\"kind\":\"keyword_only\",\"name\":\"headers\"}],\"is_async\":false,\"line_end\":519,\"line_start\":506,\"name\":\"redirect\"},{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"status\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"message\"}],\"is_async\":false,\"line_end\":529,\"line_start\":521,\"name\":\"error_reply\"},{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"}],\"is_async\":false,\"line_end\":535,\"line_start\":531,\"name\":\"content_length\"},{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"},{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"limit\"}],\"is_async\":false,\"line_end\":544,\"line_start\":537,\"name\":\"read_body\"},{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"}],\"is_async\":false,\"line_end\":551,\"line_start\":546,\"name\":\"path_parts\"},{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"}],\"is_async\":false,\"line_end\":749,\"line_start\":553,\"name\":\"do_GET\"},{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"self\"}],\"is_async\":false,\"line_end\":892,\"line_start\":751,\"name\":\"do_POST\"}],\"name\":\"Handler\"}},\"portal_functions\":{\"adapter_call\":{\"arguments\":[{\"has_default\":false,\"kind\":\"positional_or_keyword\",\"name\":\"request\"}],\"is_async\":false,\"line_end\":91,\"line_start\":44,\"name\":\"adapter_call\"}},\"private_addresses_included\":false,\"rollback_started\":false,\"sanitized\":true,\"schema\":1,\"secrets_included\":false,\"service_files\":{\"adapter\":\"[Unit]\\nDescription=Homelab command adapter\\nAfter=network-online.target\\nWants=network-online.target\\n\\n[Service]\\nType=simple\\nExecStart=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve\\nUser=root\\nGroup=homelab-command-portal\\nUMask=0027\\nRuntimeDirectory=homelab-command-adapter\\nRuntimeDirectoryMode=0750\\nRestart=on-failure\\nRestartSec=2\\nNoNewPrivileges=false\\nPrivateTmp=true\\nProtectClock=true\\nProtectControlGroups=true\\nProtectKernelLogs=true\\nProtectKernelModules=true\\nProtectKernelTunables=true\\nRestrictRealtime=true\\nLockPersonality=true\\nMemoryDenyWriteExecute=true\\nSystemCallArchitectures=native\\nTimeoutStopSec=15\\n\\n[Install]\\nWantedBy=multi-user.target\\n\",\"portal\":\"[Unit]\\nDescription=Homelab command portal\\nAfter=network-online.target homelab-command-adapter.service\\nRequires=homelab-command-adapter.service\\nWants=network-online.target\\nStartLimitIntervalSec=30\\nStartLimitBurst=3\\n\\n[Service]\\nType=simple\\nExecStartPre=/usr/bin/python3 -B /usr/local/sbin/homelab-command-portal --self-test\\nExecStart=/usr/bin/python3 -B /usr/local/sbin/homelab-command-portal\\nUser=homelab-command-portal\\nGroup=homelab-command-portal\\nUMask=0077\\nRestart=on-failure\\nRestartSec=2\\nNoNewPrivileges=true\\nPrivateTmp=true\\nPrivateDevices=true\\nProtectSystem=strict\\nProtectHome=true\\nReadWritePaths=/var/lib/homelab-command-portal\\nProtectClock=true\\nProtectControlGroups=true\\nProtectKernelLogs=true\\nProtectKernelModules=true\\nProtectKernelTunables=true\\nRestrictSUIDSGID=true\\nRestrictRealtime=true\\nLockPersonality=true\\nMemoryDenyWriteExecute=true\\nRestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX\\nSystemCallArchitectures=native\\nTimeoutStopSec=15\\n\\n[Install]\\nWantedBy=multi-user.target\\n\"},\"services\":{\"adapter\":{\"active\":\"active\",\"pid\":\"976008\",\"restarts\":\"0\",\"sub\":\"running\"},\"portal\":{\"active\":\"active\",\"pid\":\"976035\",\"restarts\":\"0\",\"sub\":\"running\"}},\"source_excerpts\":{\"adapter_dispatch\":\"2414:         \\\"ok\\\": True,\\n2415:         \\\"result\\\": value,\\n2416:     }\\n2417: \\n2418: \\n2419: def dispatch(request: dict[str, Any]) -> dict[str, Any]:\\n2420:     operation = request.get(\\\"op\\\")\\n2421:     if operation == \\\"health\\\":\\n2422:         return response_ok(\\n2423:             {\\n2424:                 \\\"status\\\": \\\"ok\\\",\\n2425:                 \\\"version\\\": 1,\\n2426:             }\\n2427:         )\\n2428:     if operation == \\\"bind_enrollment\\\":\\n2429:         return response_ok(\\n2430:             bind_enrollment(\\n2431:                 str(request.get(\\\"token\\\", \\\"\\\")),\\n2432:                 str(request.get(\\\"client_ip\\\", \\\"\\\")),\\n2433:             )\\n2434:         )\\n2435:     if operation == \\\"enroll\\\":\\n2436:         return response_ok(\\n2437:             enroll_device(\\n2438:                 str(request.get(\\\"token\\\", \\\"\\\")),\\n2439:                 str(request.get(\\\"client_ip\\\", \\\"\\\")),\\n2440:             )\\n2441:         )\\n2442:     if operation == \\\"import\\\":\\n2443:         return response_ok(\\n2444:             import_capsule(\\n2445:                 device_token=[REDACTED]\\n2446:                     request.get(\\\"device_token\\\", \\\"\\\")\\n2447:                 ),\\n2448:                 client_ip=str(\\n2449:                     request.get(\\\"client_ip\\\", \\\"\\\")\\n2450:                 ),\\n2451:                 upload_path=str(\\n2452:                     request.get(\\\"upload_path\\\", \\\"\\\")\\n2453:                 ),\\n2454:             )\\n2455:         )\\n2456:     if operation == \\\"consume_bootstrap\\\":\\n2457:         return response_ok(\\n2458:             consume_bootstrap(\\n2459:                 short_id=str(request.get(\\\"short_id\\\", \\\"\\\")),\\n2460:                 token=[REDACTED]\\\"token\\\", \\\"\\\")),\\n2461:                 client_ip=str(\\n2462:                     request.get(\\\"client_ip\\\", \\\"\\\")\\n2463:                 ),\\n2464:             )\\n2465:         )\\n2466:     if operation == \\\"state\\\":\\n2467:         return response_ok(\\n2468:             public_state(\\n2469:                 short_id=str(request.get(\\\"short_id\\\", \\\"\\\")),\\n2470:                 session_token=[REDACTED]\\n2471:                     request.get(\\\"session_token\\\", \\\"\\\")\\n2472:                 ),\\n2473:                 client_ip=str(\\n2474:                     request.get(\\\"client_ip\\\", \\\"\\\")\\n2475:                 ),\\n2476:             )\\n2477:         )\\n2478:     if operation == \\\"execute\\\":\\n2479:         return response_ok(\\n2480:             start_execution(\\n2481:                 short_id=str(request.get(\\\"short_id\\\", \\\"\\\")),\\n2482:                 session_token=[REDACTED]\\n2483:                     request.get(\\\"session_token\\\", \\\"\\\")\\n2484:                 ),\\n2485:                 client_ip=str(\\n2486:                     request.get(\\\"client_ip\\\", \\\"\\\")\\n2487:                 ),\\n2488:             )\\n2489:         )\\n2490:     if operation == \\\"evidence_url\\\":\\n2491:         return response_ok(\\n2492:             evidence_url(\\n2493:                 short_id=str(request.get(\\\"short_id\\\", \\\"\\\")),\\n2494:                 session_token=[REDACTED]\\n2495:                     request.get(\\\"session_token\\\", \\\"\\\")\\n2496:                 ),\\n2497:                 client_ip=str(\\n2498:                     request.get(\\\"client_ip\\\", \\\"\\\")\\n2499:                 ),\\n2500:             )\\n2501:         )\\n2502:     raise AdapterError(\\\"unsupported operation\\\")\\n2503: \\n2504: \\n2505: class Handler(socketserver.StreamRequestHandler):\\n2506:     def handle(self) -> None:\\n2507:         credentials = self.request.getsockopt(\",\"adapter_public_state\":\"1306:         ):\\n1307:             return session\\n1308:     raise AdapterError(\\\"session authorization failed\\\")\\n1309: \\n1310: \\n1311: def public_state(\\n1312:     *,\\n1313:     short_id: str,\\n1314:     session_token: [REDACTED]\\n1315:     client_ip: str,\\n1316: ) -> dict[str, Any]:\\n1317:     with GlobalLock():\\n1318:         state = load_json(state_path(short_id))\\n1319:         authorize_session(\\n1320:             state,\\n1321:             session_token=[REDACTED]\\n1322:             client_ip=client_ip,\\n1323:         )\\n1324:         return sanitize_state(state)\\n1325: \\n1326: \\n1327: def sanitize_state(state: dict[str, Any]) -> dict[str, Any]:\\n1328:     execution = state.get(\\\"execution\\\")\\n1329:     public_execution = None\",\"adapter_sanitize_state\":\"1322:             client_ip=client_ip,\\n1323:         )\\n1324:         return sanitize_state(state)\\n1325: \\n1326: \\n1327: def sanitize_state(state: dict[str, Any]) -> dict[str, Any]:\\n1328:     execution = state.get(\\\"execution\\\")\\n1329:     public_execution = None\\n1330:     if isinstance(execution, dict):\\n1331:         public_execution = {\\n1332:             key: execution.get(key)\\n1333:             for key in (\\n1334:                 \\\"started_at_utc\\\",\\n1335:                 \\\"finished_at_utc\\\",\\n1336:                 \\\"runner_rc\\\",\\n1337:                 \\\"runner_document_rc\\\",\\n1338:                 \\\"runner_status\\\",\\n1339:                 \\\"runner_wrapper_matches_document\\\",\\n1340:                 \\\"runner_json_sha256\\\",\\n1341:                 \\\"runner_text_sha256\\\",\\n1342:             )\\n1343:             if key in execution\\n1344:         }\\n1345: \\n1346:     evidence = state.get(\\\"evidence\\\")\\n1347:     public_evidence = None\\n1348:     if isinstance(evidence, dict):\\n1349:         public_evidence = {\\n1350:             key: evidence.get(key)\\n1351:             for key in (\\n1352:                 \\\"object_key\\\",\\n1353:                 \\\"sha256\\\",\\n1354:                 \\\"bytes\\\",\\n1355:                 \\\"gateway_verified\\\",\\n1356:             )\\n1357:             if key in evidence\\n1358:         }\\n1359: \\n1360:     return {\\n1361:         \\\"schema_version\\\": 1,\\n1362:         \\\"short_id\\\": state[\\\"short_id\\\"],\\n1363:         \\\"capsule_sha256\\\": state[\\\"capsule_sha256\\\"],\\n1364:         \\\"capsule_bytes\\\": state[\\\"capsule_bytes\\\"],\\n1365:         \\\"manifest\\\": state[\\\"manifest\\\"],\\n1366:         \\\"imported_at_utc\\\": state[\\\"imported_at_utc\\\"],\\n1367:         \\\"command_object\\\": state[\\\"command_object\\\"],\\n1368:         \\\"status\\\": state[\\\"status\\\"],\\n1369:         \\\"execution\\\": public_execution,\\n1370:         \\\"evidence\\\": public_evidence,\\n1371:         \\\"error\\\": state.get(\\\"error\\\"),\\n1372:     }\\n1373: \\n1374: \\n1375: def start_execution(\\n1376:     *,\\n1377:     short_id: str,\",\"adapter_worker_finalization\":\"2058:             state[\\\"manifest\\\"][\\\"command_id\\\"],\\n2059:             started_epoch,\\n2060:         )\\n2061:         runner_document = load_json(runner_json)\\n2062: \\n2063:         bundle, evidence_sha, evidence_bytes = (\\n2064:             create_evidence_bundle(\\n2065:                 state=state,\\n2066:                 runner_json=runner_json,\\n2067:                 runner_txt=runner_txt,\\n2068:             )\\n2069:         )\\n2070:         prefix = (\\n2071:             \\\"portal-tests\\\"\\n2072:             if state[\\\"manifest\\\"][\\\"component\\\"]\\n2073:             == \\\"command-portal-smoke\\\"\\n2074:             else \\\"portal\\\"\\n2075:         )\\n2076:         object_key = (\\n2077:             f\\\"{prefix}/\\\"\\n2078:             f\\\"{state['manifest']['command_id']}/\\\"\\n2079:             f\\\"{state['capsule_sha256']}/\\\"\\n2080:             \\\"evidence.tgz\\\"\\n2081:         )\\n2082:         upload_evidence(\\n2083:             bundle,\\n2084:             object_key,\\n2085:             evidence_sha,\\n2086:         )\\n2087: \\n2088:         with GlobalLock():\\n2089:             current = load_json(path)\\n2090:             if not worker_state_owned(\\n2091:                 current,\\n2092:                 os.getpid(),\\n2093:             ):\\n2094:                 raise AdapterError(\\n2095:                     \\\"worker finalization ownership lost\\\"\\n2096:                 )\\n2097:             document_status = str(\\n2098:                 runner_document.get(\\\"status\\\", \\\"FAIL\\\")\\n2099:             )\\n2100:             try:\\n2101:                 document_rc = int(runner_document[\\\"rc\\\"])\\n2102:             except (KeyError, TypeError, ValueError) as exc:\\n2103:                 raise AdapterError(\\\"runner artifact rc invalid\\\") from exc\\n2104:             wrapper_matches = result.returncode == document_rc\\n2105:             current[\\\"status\\\"] = (\\n2106:                 document_status if wrapper_matches else \\\"FAIL\\\"\\n2107:             )\\n2108:             current[\\\"execution\\\"].update(\\n2109:                 {\\n2110:                     \\\"finished_at_utc\\\": iso(),\\n2111:                     \\\"runner_rc\\\": result.returncode,\\n2112:                     \\\"runner_document_rc\\\": document_rc,\\n2113:                     \\\"runner_status\\\": document_status,\\n2114:                     \\\"runner_wrapper_matches_document\\\": wrapper_matches,\\n2115:                     \\\"runner_json\\\": str(runner_json),\\n2116:                     \\\"runner_text\\\": str(runner_txt),\\n2117:                     \\\"runner_json_sha256\\\": sha256_file(\\n2118:                         runner_json\\n2119:                     ),\\n2120:                     \\\"runner_text_sha256\\\": sha256_file(\\n2121:                         runner_txt\\n2122:                     ),\\n2123:                 }\\n2124:             )\\n2125:             current[\\\"evidence\\\"] = {\\n2126:                 \\\"object_key\\\": object_key,\\n2127:                 \\\"sha256\\\": evidence_sha,\\n2128:                 \\\"bytes\\\": evidence_bytes,\\n2129:                 \\\"local_bundle\\\": str(bundle),\\n2130:                 \\\"gateway_verified\\\": True,\\n2131:             }\\n2132:             current[\\\"error\\\"] = (\\n2133:                 None\\n2134:                 if wrapper_matches\\n2135:                 else {\\n2136:                     \\\"type\\\": \\\"RunnerWrapperMismatch\\\",\\n2137:                     \\\"message\\\": (\\n2138:                         \\\"existing runner returned a different rc \\\"\\n2139:                         \\\"after writing its public artifact; \\\"\\n2140:                         \\\"runtime publication or wrapper completion failed\\\"\\n2141:                     ),\\n2142:                 }\\n2143:             )\\n2144:             atomic_json(path, current)\\n2145:         return 0\\n2146: \\n2147:     except Exception as exc:\\n2148:         try:\\n2149:             with wrapper_log.open(\\n2150:                 \\\"a\\\",\\n2151:                 encoding=\\\"utf-8\\\",\\n2152:                 errors=\\\"replace\\\",\\n2153:             ) as stream:\\n2154:                 stream.write(\\n2155:                     f\\\"WORKER_ERROR={type(exc).__name__}:{exc}\\\\\\\\n\\\"\\n2156:                 )\\n2157:             os.chmod(wrapper_log, 0o640)\\n2158:         except Exception:\\n2159:             pass\\n2160: \\n2161:         with GlobalLock():\\n2162:             try:\\n2163:                 current = load_json(path)\\n2164:                 if worker_state_owned(\\n2165:                     current,\\n2166:                     os.getpid(),\\n2167:                 ):\\n2168:                     current[\\\"status\\\"] = \\\"FAIL\\\"\\n2169:                     if isinstance(\\n2170:                         current.get(\\\"execution\\\"),\\n2171:                         dict,\\n2172:                     ):\\n2173:                         current[\\\"execution\\\"][\\n2174:                             \\\"finished_at_utc\\\"\\n2175:                         ] = iso()\\n2176:                     current[\\\"error\\\"] = {\\n2177:                         \\\"type\\\": type(exc).__name__,\\n2178:                         \\\"message\\\": str(exc)[:4000],\\n2179:                     }\\n2180:                     atomic_json(path, current)\\n2181:             except Exception:\\n2182:                 pass\\n2183:         return 1\",\"portal_Handler_do_GET\":\"550:             keep_blank_values=True,\\n551:         )\\n552: \\n553:     def do_GET(self) -> None:\\n554:         try:\\n555:             path, query = self.path_parts()\\n556: \\n557:             if path == \\\"/healthz\\\":\\n558:                 parse_client(self, allow_local_health=True)\\n559:                 result = adapter_call({\\\"op\\\": \\\"health\\\"})\\n560:                 body = (\\n561:                     json.dumps(\\n562:                         {\\n563:                             \\\"status\\\": \\\"ok\\\",\\n564:                             \\\"version\\\": 1,\\n565:                             \\\"adapter\\\": result[\\\"status\\\"],\\n566:                         },\\n567:                         separators=(\\\",\\\", \\\":\\\"),\\n568:                         sort_keys=True,\\n569:                     )\\n570:                     + \\\"\\\\n\\\"\\n571:                 ).encode()\\n572:                 self.reply(\\n573:                     200,\\n574:                     \\\"application/json; charset=utf-8\\\",\\n575:                     body,\\n576:                 )\\n577:                 return\\n578: \\n579:             client_ip = parse_client(self)\\n580: \\n581:             if path == \\\"/bridge/bridge.cmd\\\":\\n582:                 self.reply(\\n583:                     200,\\n584:                     \\\"application/octet-stream\\\",\\n585:                     BRIDGE_CMD.encode(\\\"utf-8\\\"),\\n586:                     headers={\\n587:                         \\\"Content-Disposition\\\": (\\n588:                             'attachment; filename=\\\"bridge.cmd\\\"'\\n589:                         )\\n590:                     },\\n591:                 )\\n592:                 return\\n593: \\n594:             if path.startswith(\\\"/enroll/\\\"):\\n595:                 relative = path[len(\\\"/enroll/\\\") :]\\n596:                 if relative.endswith(\\\"/bridge-setup.cmd\\\"):\\n597:                     token = [REDACTED]\\n598:                         : -len(\\\"/bridge-setup.cmd\\\")\\n599:                     ]\\n600:                     adapter_call(\\n601:                         {\\n602:                             \\\"op\\\": \\\"bind_enrollment\\\",\\n603:                             \\\"token\\\": token,\\n604:                             \\\"client_ip\\\": client_ip,\\n605:                         }\\n606:                     )\\n607:                     self.reply(\\n608:                         200,\\n609:                         \\\"application/octet-stream\\\",\\n610:                         setup_script(token),\\n611:                         headers={\\n612:                             \\\"Content-Disposition\\\": (\\n613:                                 'attachment; '\\n614:                                 'filename=\\\"HomelabBridgeSetup.cmd\\\"'\\n615:                             )\\n616:                         },\\n617:                     )\\n618:                     return\\n619: \\n620:                 token = [REDACTED]\\n621:                 info = adapter_call(\\n622:                     {\\n623:                         \\\"op\\\": \\\"bind_enrollment\\\",\\n624:                         \\\"token\\\": token,\\n625:                         \\\"client_ip\\\": client_ip,\\n626:                     }\\n627:                 )\\n628:                 body = f\\\"\\\"\\\"<!doctype html>\\n629: <html lang=\\\"ru\\\"><head><meta charset=\\\"utf-8\\\">\\n630: <meta name=\\\"robots\\\" content=\\\"noindex,nofollow,noarchive\\\">\\n631: <title>Homelab Bridge</title>\\n632: <style>body{{font-family:Segoe UI,Arial;background:#111827;color:#e5e7eb;max-width:760px;margin:40px auto;padding:20px}}a{{display:inline-block;background:#60a5fa;color:#172554;padding:12px 18px;border-radius:8px;text-decoration:none;font-weight:700}}</style>\\n633: </head><body>\\n634: <h1>Установка Homelab Bridge</h1>\\n635: <p>Профиль: {html.escape(str(info['label']))}</p>\\n636: <p>Ссылка одноразовая и уже привязана к этому NetBird-адресу.</p>\\n637: <p><a href=\\\"{html.escape(path)}/bridge-setup.cmd\\\">Скачать установщик</a></p>\\n638: <p>После запуска установщика файлы <code>.hcmd</code> будут открываться двойным кликом.</p>\\n639: </body></html>\\\"\\\"\\\".encode()\\n640:                 self.reply(\\n641:                     200,\\n642:                     \\\"text/html; charset=utf-8\\\",\\n643:                     body,\\n644:                 )\\n645:                 return\\n646: \\n647:             match = re.fullmatch(\\n648:                 r\\\"/r/([A-Z2-7]{10,20})\\\",\\n649:                 path,\\n650:             )\\n651:             if match:\\n652:                 short_id = safe_short(match.group(1))\\n653:                 token_values = query.get(\\\"t\\\", [])\\n654:                 if token_values:\\n655:                     token = [REDACTED]\\n656:                     session = adapter_call(\\n657:                         {\\n658:                             \\\"op\\\": \\\"consume_bootstrap\\\",\\n659:                             \\\"short_id\\\": short_id,\\n660:                             \\\"token\\\": token,\\n661:                             \\\"client_ip\\\": client_ip,\\n662:                         }\\n663:                     )\\n664:                     cookie = (\\n665:                         f\\\"__Host-HLSESSION={session['session_token']}; \\\"\\n666:                         f\\\"Max-Age={8 * 3600}; Path=/; \\\"\\n667:                         \\\"Secure; HttpOnly; SameSite=Strict\\\"\\n668:                     )\\n669:                     self.redirect(\\n670:                         f\\\"/r/{short_id}\\\",\\n671:                         headers={\\\"Set-Cookie\\\": cookie},\\n672:                     )\\n673:                     return\\n674: \\n675:                 session_token = [REDACTED]\\n676:                 state = adapter_call(\\n677:                     {\\n678:                         \\\"op\\\": \\\"state\\\",\\n679:                         \\\"short_id\\\": short_id,\\n680:                         \\\"session_token\\\": session_token,\\n681:                         \\\"client_ip\\\": client_ip,\\n682:                     }\\n683:                 )\\n684:                 self.reply(\\n685:                     200,\\n686:                     \\\"text/html; charset=utf-8\\\",\\n687:                     render_card(state, session_token),\\n688:                 )\\n689:                 return\\n690: \\n691:             evidence_match = re.fullmatch(\\n692:                 r\\\"/r/([A-Z2-7]{10,20})/evidence\\\",\\n693:                 path,\\n694:             )\\n695:             if evidence_match:\\n696:                 short_id = safe_short(\\n697:                     evidence_match.group(1)\\n698:                 )\\n699:                 signed = adapter_call(\\n700:                     {\\n701:                         \\\"op\\\": \\\"evidence_url\\\",\\n702:                         \\\"short_id\\\": short_id,\\n703:                         \\\"session_token\\\": cookie_session(self),\\n704:                         \\\"client_ip\\\": client_ip,\\n705:                     }\\n706:                 )\\n707:                 self.redirect(str(signed[\\\"url\\\"]))\\n708:                 return\\n709: \\n710:             state_match = re.fullmatch(\\n711:                 r\\\"/api/state/([A-Z2-7]{10,20})\\\",\\n712:                 path,\\n713:             )\\n714:             if state_match:\\n715:                 short_id = safe_short(\\n716:                     state_match.group(1)\\n717:                 )\\n718:                 state = adapter_call(\\n719:                     {\\n720:                         \\\"op\\\": \\\"state\\\",\\n721:                         \\\"short_id\\\": short_id,\\n722:                         \\\"session_token\\\": cookie_session(self),\\n723:                         \\\"client_ip\\\": client_ip,\\n724:                     }\\n725:                 )\\n726:                 self.reply(\\n727:                     200,\\n728:                     \\\"application/json; charset=utf-8\\\",\\n729:                     (\\n730:                         json.dumps(\\n731:                             state,\\n732:                             ensure_ascii=False,\\n733:                             separators=(\\\",\\\", \\\":\\\"),\\n734:                             sort_keys=True,\\n735:                         )\\n736:                         + \\\"\\\\n\\\"\\n737:                     ).encode(),\\n738:                 )\\n739:                 return\\n740: \\n741:             self.error_reply(404, \\\"not found\\\")\\n742: \\n743:         except PortalError as exc:\\n744:             self.error_reply(403, str(exc))\\n745:         except Exception as exc:\\n746:             self.error_reply(\\n747:                 500,\\n748:                 f\\\"{type(exc).__name__}:{str(exc)[:1000]}\\\",\\n749:             )\\n750: \\n751:     def do_POST(self) -> None:\\n752:         try:\",\"portal_Handler_error_reply\":\"518:             headers=values,\\n519:         )\\n520: \\n521:     def error_reply(self, status: int, message: str) -> None:\\n522:         body = (\\n523:             f\\\"PORTAL_ERROR={html.escape(message)}\\\\n\\\"\\n524:         ).encode()\\n525:         self.reply(\\n526:             status,\\n527:             \\\"text/plain; charset=utf-8\\\",\\n528:             body,\\n529:         )\\n530: \\n531:     def content_length(self) -> int:\\n532:         raw = self.headers.get(\\\"Content-Length\\\")\",\"portal_Handler_path_parts\":\"543:             raise PortalError(\\\"short request body\\\")\\n544:         return body\\n545: \\n546:     def path_parts(self) -> tuple[str, dict[str, list[str]]]:\\n547:         parsed = urllib.parse.urlsplit(self.path)\\n548:         return parsed.path, urllib.parse.parse_qs(\\n549:             parsed.query,\\n550:             keep_blank_values=True,\\n551:         )\\n552: \\n553:     def do_GET(self) -> None:\\n554:         try:\",\"portal_Handler_reply\":\"468:             f\\\"{self.client_address[0]} - {message}\\\\n\\\"\\n469:         )\\n470: \\n471:     def reply(\\n472:         self,\\n473:         status: int,\\n474:         content_type: str,\\n475:         body: bytes,\\n476:         *,\\n477:         headers: dict[str, str] | None = None,\\n478:     ) -> None:\\n479:         self.send_response(status)\\n480:         self.send_header(\\\"Content-Type\\\", content_type)\\n481:         self.send_header(\\\"Content-Length\\\", str(len(body)))\\n482:         self.send_header(\\n483:             \\\"Cache-Control\\\",\\n484:             \\\"no-store, no-cache, must-revalidate, max-age=0\\\",\\n485:         )\\n486:         self.send_header(\\\"Pragma\\\", \\\"no-cache\\\")\\n487:         self.send_header(\\\"Expires\\\", \\\"0\\\")\\n488:         self.send_header(\\n489:             \\\"X-Robots-Tag\\\",\\n490:             \\\"noindex, nofollow,noarchive\\\",\\n491:         )\\n492:         self.send_header(\\\"X-Content-Type-Options\\\", \\\"nosniff\\\")\\n493:         self.send_header(\\\"Referrer-Policy\\\", \\\"no-referrer\\\")\\n494:         self.send_header(\\n495:             \\\"Content-Security-Policy\\\",\\n496:             \\\"default-src 'none'; style-src 'unsafe-inline'; \\\"\\n497:             \\\"form-action 'self'; frame-ancestors 'none'; \\\"\\n498:             \\\"base-uri 'none'\\\",\\n499:         )\\n500:         for key, value in (headers or {}).items():\\n501:             self.send_header(key, value)\\n502:         self.end_headers()\\n503:         if body:\\n504:             self.wfile.write(body)\\n505: \\n506:     def redirect(\\n507:         self,\"},\"source_sha256\":{\"adapter\":\"8d0af84dcfcf6ddbfd1c4e6cbb059cef66b4cfc6c75bfd66da649acc229c7f5e\",\"portal\":\"8056faf4ef6348f0b06319ad3c49fbfeeadf25b6370f857ea19569bd27652ee2\",\"runner\":\"b248a4c32c9cc64e5747e7dce6c7fc0a23f5124a77c71ce72e27a81aceae9d2d\"},\"states\":{\"current_running\":[{\"command_id\":\"RESULT-API-PATCH-AUDIT-20260727T075149Z\",\"state_file\":\"275ZUEB6ZH.json\"}],\"invalid\":[],\"other_running\":[]},\"status\":\"OK\"}\n"
}
