34 lines
31 KiB
Plaintext
34 lines
31 KiB
Plaintext
CHAT_OUTPUT_BEGIN
|
|
COMMAND_ID=RESULT-API-PATCH-AUDIT-20260727T075149Z
|
|
STATUS=OK
|
|
RC=0
|
|
HOST=pve01
|
|
MODE=verify
|
|
COMPONENT=result-integration
|
|
REFERENCE_REGISTER_CHECK=OK
|
|
REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e
|
|
ERROR_REGISTER_CHECK=OK
|
|
ERROR_REGISTER_SHA256=24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83
|
|
COMMAND_SHA256=b564f92f4324ba19d5c6752e0c53111024fd37092acacc2281d2ab9ac7f39359
|
|
DUPLICATE_FAILED_COMMAND_BLOCKED=false
|
|
EXECUTION_STARTED=true
|
|
CHANGE_DECLARED=false
|
|
RESULT_CONTRACT_VALID=true
|
|
RESULT_CONTRACT_STATUS=NOT_APPLICABLE
|
|
RESULT_CONTRACT_ERROR=NONE
|
|
COMMAND_RC=0
|
|
CHANGES_MADE=false
|
|
ROLLBACK_STARTED=false
|
|
ROLLBACK_RESTORED=null
|
|
MUTATION_OUTCOME=NO_MUTATION
|
|
SANITIZED=yes
|
|
SECRETS_INCLUDED=no
|
|
PRIVATE_ADDRESSES_INCLUDED=no
|
|
RAW_EVIDENCE_SHA256=1dabd515e3ddd0d132d8f6cd354770e78207200337dfda97f41dcacb8b3b576d
|
|
SANITIZED_OUTPUT_SHA256=1dabd515e3ddd0d132d8f6cd354770e78207200337dfda97f41dcacb8b3b576d
|
|
OUTPUT_BEGIN
|
|
{"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"}
|
|
|
|
OUTPUT_END
|
|
CHAT_OUTPUT_END
|