diff --git a/runtime/history/CLUSTER-REFERENCE-DECISION-150.json b/runtime/history/CLUSTER-REFERENCE-DECISION-150.json new file mode 100644 index 0000000..11ceb3d --- /dev/null +++ b/runtime/history/CLUSTER-REFERENCE-DECISION-150.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "CLUSTER-REFERENCE-DECISION-150", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "read-only", + "component": "cluster-audit", + "started_at_utc": "2026-07-22T07:31:03Z", + "finished_at_utc": "2026-07-22T07:31:03Z", + "reference_register_checked": true, + "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", + "error_register_checked": true, + "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752", + "command_sha256": "f659dc6ec9518f7fb4c604dd67fc3f3368adeb24943e95c3cc29c17abb0b991d", + "duplicate_failed_command_blocked": false, + "block_reason": null, + "execution_started": true, + "changes_made": false, + "sanitized": true, + "secrets_included": false, + "private_addresses_included": false, + "raw_evidence_retained_locally": true, + "raw_evidence_sha256": "a3f3f7df5bcf2d5de3cb15388230e69e5e4b697cf9a913821dd88d3b53742c03", + "sanitized_output_sha256": "a3f3f7df5bcf2d5de3cb15388230e69e5e4b697cf9a913821dd88d3b53742c03", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "JSON_IMMUTABLE_COMMIT=151931133ec23f2f687a868614c35ff76b77281c\nTXT_IMMUTABLE_COMMIT=151931133ec23f2f687a868614c35ff76b77281c\n=== PREVIOUS_RESULT ===\nSTATUS=OK\nRC=0\nREASON=\nEXECUTION_STARTED=true\n=== MODE_DECISION ===\nVALID_MODES=change,read-only,transport-test,verify\nSAFE_WRITE_MODES=change,transport-test,verify\nSAFE_WRITE_MODE=UNRESOLVED\n=== REFERENCE_STATE ===\nREFERENCE_ROOT=ABSENT\nREFERENCE_FILES=0\nREFERENCE_MANIFEST=ABSENT\nNEXT_ACTION=RESOLVE_WRITE_MODE\nCLUSTER_REFERENCE_DECISION=COMPLETE\n" +} diff --git a/runtime/history/CLUSTER-REFERENCE-DECISION-150.txt b/runtime/history/CLUSTER-REFERENCE-DECISION-150.txt new file mode 100644 index 0000000..ac959a9 --- /dev/null +++ b/runtime/history/CLUSTER-REFERENCE-DECISION-150.txt @@ -0,0 +1,41 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=CLUSTER-REFERENCE-DECISION-150 +STATUS=OK +RC=0 +HOST=pve01 +MODE=read-only +COMPONENT=cluster-audit +REFERENCE_REGISTER_CHECK=OK +REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e +ERROR_REGISTER_CHECK=OK +ERROR_REGISTER_SHA256=08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752 +COMMAND_SHA256=f659dc6ec9518f7fb4c604dd67fc3f3368adeb24943e95c3cc29c17abb0b991d +DUPLICATE_FAILED_COMMAND_BLOCKED=false +EXECUTION_STARTED=true +CHANGES_MADE=false +SANITIZED=yes +SECRETS_INCLUDED=no +PRIVATE_ADDRESSES_INCLUDED=no +RAW_EVIDENCE_SHA256=a3f3f7df5bcf2d5de3cb15388230e69e5e4b697cf9a913821dd88d3b53742c03 +SANITIZED_OUTPUT_SHA256=a3f3f7df5bcf2d5de3cb15388230e69e5e4b697cf9a913821dd88d3b53742c03 +OUTPUT_BEGIN +JSON_IMMUTABLE_COMMIT=151931133ec23f2f687a868614c35ff76b77281c +TXT_IMMUTABLE_COMMIT=151931133ec23f2f687a868614c35ff76b77281c +=== PREVIOUS_RESULT === +STATUS=OK +RC=0 +REASON= +EXECUTION_STARTED=true +=== MODE_DECISION === +VALID_MODES=change,read-only,transport-test,verify +SAFE_WRITE_MODES=change,transport-test,verify +SAFE_WRITE_MODE=UNRESOLVED +=== REFERENCE_STATE === +REFERENCE_ROOT=ABSENT +REFERENCE_FILES=0 +REFERENCE_MANIFEST=ABSENT +NEXT_ACTION=RESOLVE_WRITE_MODE +CLUSTER_REFERENCE_DECISION=COMPLETE + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index a855d35..11ceb3d 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,19 +1,19 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "CLUSTER-REFERENCE-STATE-AUDIT-149", + "command_id": "CLUSTER-REFERENCE-DECISION-150", "status": "OK", "rc": 0, "host": "pve01", "mode": "read-only", "component": "cluster-audit", - "started_at_utc": "2026-07-22T07:25:10Z", - "finished_at_utc": "2026-07-22T07:25:13Z", + "started_at_utc": "2026-07-22T07:31:03Z", + "finished_at_utc": "2026-07-22T07:31:03Z", "reference_register_checked": true, "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", "error_register_checked": true, "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752", - "command_sha256": "2af6ffbc1ab71f8fd13302a48794faa713dfcde5a4c90652ace8ab2355e3c2e4", + "command_sha256": "f659dc6ec9518f7fb4c604dd67fc3f3368adeb24943e95c3cc29c17abb0b991d", "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": "8fda57d15c1339215b841cef0152a9d2ff5e74b8ecb22d0a7b22050900061148", - "sanitized_output_sha256": "c5ff5c4350fa2306f6847ecfe42105b46c49aa92a065610327cb1a9f0e9498bc", + "raw_evidence_sha256": "a3f3f7df5bcf2d5de3cb15388230e69e5e4b697cf9a913821dd88d3b53742c03", + "sanitized_output_sha256": "a3f3f7df5bcf2d5de3cb15388230e69e5e4b697cf9a913821dd88d3b53742c03", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "=== IMMUTABLE_COMMAND_RESULTS ===\n--- COMMAND_ID=CLUSTER-REFERENCE-MODE-CONFIRM-145 ---\nJSON_COMMIT=072668fbc56c580756f0ad7a6a30e4a6af953794\nSTATUS=OK\nRC=0\nREASON=None\nEXECUTION_STARTED=True\nDUPLICATE_BLOCKED=False\nTXT_COMMIT=072668fbc56c580756f0ad7a6a30e4a6af953794\nVALID_MODES=change,read-only,transport-test,verify\nSAFE_WRITE_MODE=UNRESOLVED\nCLUSTER_REFERENCE_MODE_CONFIRM=COMPLETE\nERROR_REGISTERED=no\n--- COMMAND_ID=CLUSTER-REFERENCE-FRAMEWORK-146 ---\nJSON_HISTORY=MISSING\nTXT_HISTORY=MISSING\nERROR_REGISTERED=no\n--- COMMAND_ID=CLUSTER-REFERENCE-SOURCE-AUDIT-147 ---\nJSON_COMMIT=4ef5989856165ac24b02ba54455d3782e16a7cae\nSTATUS=FAIL\nRC=22\nREASON=None\nEXECUTION_STARTED=True\nDUPLICATE_BLOCKED=False\nTXT_COMMIT=4ef5989856165ac24b02ba54455d3782e16a7cae\nERROR_REGISTERED=no\n--- COMMAND_ID=CLUSTER-REFERENCE-FOUNDATION-148 ---\nJSON_HISTORY=MISSING\nTXT_HISTORY=MISSING\nERROR_REGISTERED=no\n=== RUNNER_MODE_RULES ===\n3-umask 077\n4-\n5-usage() {\n6- cat >&2 <<'USAGE'\n7-Usage:\n8- homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]\n9-\n10-MODE:\n11: read-only\n12- verify\n13: change\n14- transport-test\n15-\n16-Environment:\n17- HOMELAB_ALLOW_REPEAT=1 Allow exact repeat of a previously failed command.\n18- HOMELAB_TIMEOUT=SECONDS Optional command timeout.\n19-USAGE\n20- exit 64\n21-}\n22-\n23-[ \"$#\" -ge 5 ] || usage\n24-\n25-COMMAND_ID=\"$1\"\n26-MODE=\"$2\"\n27-COMPONENT=\"$3\"\n28-shift 3\n29-\n30-[ \"${1:-}\" = '--' ] || usage\n31-shift\n32-[ \"$#\" -ge 1 ] || usage\n33-\n--\n43- ''|*[!A-Za-z0-9._-]*)\n44- echo 'RESULT=FAIL'\n45- echo 'REASON=INVALID_COMPONENT'\n46- exit 66\n47- ;;\n48-esac\n49-\n50-case \"$MODE\" in\n51: read-only|verify|change|transport-test)\n52- ;;\n53- *)\n54- echo 'RESULT=FAIL'\n55: echo 'REASON=INVALID_MODE'\n56- exit 67\n57- ;;\n58-esac\n59-\n60-for TOOL in \\\n61- awk \\\n62- curl \\\n63- flock \\\n64- python3 \\\n65- scp \\\n66- sha256sum \\\n67- ssh\n68-do\n69- command -v \"$TOOL\" >/dev/null 2>&1 || {\n70- echo 'RESULT=FAIL'\n71- echo \"REASON=REQUIRED_TOOL_MISSING:$TOOL\"\n72- exit 68\n73- }\n74-done\n75-\n--\n139- print value\n140- }\n141- ' \"$LEDGER\"\n142-)\"\n143-\n144-RUN_STARTED=true\n145-REPEAT_BLOCKED=false\n146-BLOCK_REASON=''\n147:CHANGES_MADE=false\n148-\n149-case \"$MODE\" in\n150: change)\n151: CHANGES_MADE=true\n152- ;;\n153-esac\n154-\n155-if [ -n \"$PREVIOUS_FAILED_RC\" ] &&\n156- [ \"${HOMELAB_ALLOW_REPEAT:-0}\" != 1 ]; then\n157-\n158- RUN_STARTED=false\n159- REPEAT_BLOCKED=true\n160- BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT'\n161- RC=73\n162- STATUS='BLOCKED'\n163-\n164- {\n165- echo 'COMMAND_EXECUTION_BLOCKED=yes'\n166- echo 'REASON=EXACT_FAILED_COMMAND_REPEAT'\n167- echo \"PREVIOUS_RC=$PREVIOUS_FAILED_RC\"\n168- echo \"COMMAND_SHA256=$COMMAND_SHA256\"\n169- echo\n170- echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.'\n171- } >\"$RAW_FILE\"\n--\n298- text = (\n299- first\n300- + \"\\n\\n\"\n301- + \"===== PUBLIC OUTPUT TRUNCATED; FULL RAW LOG RETAINED LOCALLY =====\"\n302- + \"\\n\\n\"\n303- + last\n304- )\n305-\n306:target.write_text(text, encoding=\"utf-8\")\n307-PY\n308-\n309-SANITIZED_SHA256=\"$(\n310- sha256sum \"$SANITIZED_FILE\" |\n311- awk '{print $1}'\n312-)\"\n313-\n314-python3 - \\\n315- \"$JSON_FILE\" \\\n316- \"$SANITIZED_FILE\" \\\n317- \"$COMMAND_ID\" \\\n318- \"$STATUS\" \\\n319- \"$RC\" \\\n320- \"$HOST_SHORT\" \\\n321- \"$MODE\" \\\n322- \"$COMPONENT\" \\\n323- \"$STARTED_AT\" \\\n324- \"$FINISHED_AT\" \\\n325- \"$REFERENCE_SHA256\" \\\n326- \"$ERROR_REGISTER_SHA256\" \\\n327- \"$COMMAND_SHA256\" \\\n328- \"$RAW_SHA256\" \\\n329- \"$SANITIZED_SHA256\" \\\n330- \"$RUN_STARTED\" \\\n331- \"$REPEAT_BLOCKED\" \\\n332- \"$BLOCK_REASON\" \\\n333: \"$CHANGES_MADE\" <<'PY'\n334-import json\n335-import sys\n336-from pathlib import Path\n337-\n338-(\n339- json_path,\n340- output_path,\n341- command_id,\n342- status,\n343- rc,\n344- host,\n345- mode,\n346- component,\n347- started,\n348- finished,\n349- reference_sha,\n350- error_sha,\n351- command_sha,\n352- raw_sha,\n353- sanitized_sha,\n354- run_started,\n355- repeat_blocked,\n356- block_reason,\n357: changes_made,\n358-) = sys.argv[1:]\n359-\n360-output = Path(output_path).read_text(\n361- encoding=\"utf-8\",\n362- errors=\"replace\",\n363-)\n364-\n365-encoded = output.encode(\"utf-8\")\n366-json_limit = 300_000\n367-output_truncated = len(encoded) > json_limit\n368-\n369-if output_truncated:\n370- output_preview = encoded[:json_limit].decode(\n371- \"utf-8\",\n372- errors=\"ignore\",\n373- )\n374-else:\n375- output_preview = output\n376-\n377-document = {\n--\n388- \"reference_register_checked\": True,\n389- \"reference_sha256\": reference_sha,\n390- \"error_register_checked\": True,\n391- \"error_register_sha256\": error_sha,\n392- \"command_sha256\": command_sha,\n393- \"duplicate_failed_command_blocked\": repeat_blocked == \"true\",\n394- \"block_reason\": block_reason or None,\n395- \"execution_started\": run_started == \"true\",\n396: \"changes_made\": changes_made == \"true\",\n397- \"sanitized\": True,\n398- \"secrets_included\": False,\n399- \"private_addresses_included\": False,\n400- \"raw_evidence_retained_locally\": True,\n401- \"raw_evidence_sha256\": raw_sha,\n402- \"sanitized_output_sha256\": sanitized_sha,\n403- \"output_truncated_in_json\": output_truncated,\n404- \"full_sanitized_output_url\": (\n405- \"https://git.gram1.ru/.well-known/\"\n406- \"homelab-runtime/latest.txt\"\n407- ),\n408- \"output\": output_preview,\n409-}\n410-\n411:Path(json_path).write_text(\n412- json.dumps(\n413- document,\n414- ensure_ascii=False,\n415- indent=2,\n416- )\n417- + \"\\n\",\n418- encoding=\"utf-8\",\n419-)\n420-PY\n421-\n422-{\n423- echo 'CHAT_OUTPUT_BEGIN'\n424- echo \"COMMAND_ID=$COMMAND_ID\"\n425- echo \"STATUS=$STATUS\"\n426- echo \"RC=$RC\"\n427- echo \"HOST=$HOST_SHORT\"\n428- echo \"MODE=$MODE\"\n429- echo \"COMPONENT=$COMPONENT\"\n430- echo 'REFERENCE_REGISTER_CHECK=OK'\n431- echo \"REFERENCE_SHA256=$REFERENCE_SHA256\"\n432- echo 'ERROR_REGISTER_CHECK=OK'\n433- echo \"ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256\"\n434- echo \"COMMAND_SHA256=$COMMAND_SHA256\"\n435- echo \"DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED\"\n436- echo \"EXECUTION_STARTED=$RUN_STARTED\"\n437: echo \"CHANGES_MADE=$CHANGES_MADE\"\n438- echo 'SANITIZED=yes'\n439- echo 'SECRETS_INCLUDED=no'\n440- echo 'PRIVATE_ADDRESSES_INCLUDED=no'\n441- echo \"RAW_EVIDENCE_SHA256=$RAW_SHA256\"\n442- echo \"SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256\"\n443- echo 'OUTPUT_BEGIN'\n444- cat \"$SANITIZED_FILE\"\n445- echo\n446- echo 'OUTPUT_END'\n447- echo 'CHAT_OUTPUT_END'\n448-} >\"$TXT_FILE\"\n449-\n450-chmod 0600 \\\n451- \"$RAW_FILE\" \\\n452- \"$SANITIZED_FILE\" \\\n453- \"$JSON_FILE\" \\\n454- \"$TXT_FILE\"\n455-\n456-TARGET=debian@[PRIVATE_IP]\n457-REMOTE_PREFIX=\"/tmp/homelab-runtime-${COMMAND_ID}-$$\"\n=== PARTIAL_REFERENCE_STATE ===\nREFERENCE_ROOT=ABSENT\nREFERENCE_CLI=ABSENT\nCLUSTER_REFERENCE_STATE_AUDIT=COMPLETE\n" + "output": "JSON_IMMUTABLE_COMMIT=151931133ec23f2f687a868614c35ff76b77281c\nTXT_IMMUTABLE_COMMIT=151931133ec23f2f687a868614c35ff76b77281c\n=== PREVIOUS_RESULT ===\nSTATUS=OK\nRC=0\nREASON=\nEXECUTION_STARTED=true\n=== MODE_DECISION ===\nVALID_MODES=change,read-only,transport-test,verify\nSAFE_WRITE_MODES=change,transport-test,verify\nSAFE_WRITE_MODE=UNRESOLVED\n=== REFERENCE_STATE ===\nREFERENCE_ROOT=ABSENT\nREFERENCE_FILES=0\nREFERENCE_MANIFEST=ABSENT\nNEXT_ACTION=RESOLVE_WRITE_MODE\nCLUSTER_REFERENCE_DECISION=COMPLETE\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index 47f0eda..ac959a9 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,5 +1,5 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=CLUSTER-REFERENCE-STATE-AUDIT-149 +COMMAND_ID=CLUSTER-REFERENCE-DECISION-150 STATUS=OK RC=0 HOST=pve01 @@ -9,302 +9,33 @@ REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752 -COMMAND_SHA256=2af6ffbc1ab71f8fd13302a48794faa713dfcde5a4c90652ace8ab2355e3c2e4 +COMMAND_SHA256=f659dc6ec9518f7fb4c604dd67fc3f3368adeb24943e95c3cc29c17abb0b991d DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGES_MADE=false SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=8fda57d15c1339215b841cef0152a9d2ff5e74b8ecb22d0a7b22050900061148 -SANITIZED_OUTPUT_SHA256=c5ff5c4350fa2306f6847ecfe42105b46c49aa92a065610327cb1a9f0e9498bc +RAW_EVIDENCE_SHA256=a3f3f7df5bcf2d5de3cb15388230e69e5e4b697cf9a913821dd88d3b53742c03 +SANITIZED_OUTPUT_SHA256=a3f3f7df5bcf2d5de3cb15388230e69e5e4b697cf9a913821dd88d3b53742c03 OUTPUT_BEGIN -=== IMMUTABLE_COMMAND_RESULTS === ---- COMMAND_ID=CLUSTER-REFERENCE-MODE-CONFIRM-145 --- -JSON_COMMIT=072668fbc56c580756f0ad7a6a30e4a6af953794 +JSON_IMMUTABLE_COMMIT=151931133ec23f2f687a868614c35ff76b77281c +TXT_IMMUTABLE_COMMIT=151931133ec23f2f687a868614c35ff76b77281c +=== PREVIOUS_RESULT === STATUS=OK RC=0 -REASON=None -EXECUTION_STARTED=True -DUPLICATE_BLOCKED=False -TXT_COMMIT=072668fbc56c580756f0ad7a6a30e4a6af953794 +REASON= +EXECUTION_STARTED=true +=== MODE_DECISION === VALID_MODES=change,read-only,transport-test,verify +SAFE_WRITE_MODES=change,transport-test,verify SAFE_WRITE_MODE=UNRESOLVED -CLUSTER_REFERENCE_MODE_CONFIRM=COMPLETE -ERROR_REGISTERED=no ---- COMMAND_ID=CLUSTER-REFERENCE-FRAMEWORK-146 --- -JSON_HISTORY=MISSING -TXT_HISTORY=MISSING -ERROR_REGISTERED=no ---- COMMAND_ID=CLUSTER-REFERENCE-SOURCE-AUDIT-147 --- -JSON_COMMIT=4ef5989856165ac24b02ba54455d3782e16a7cae -STATUS=FAIL -RC=22 -REASON=None -EXECUTION_STARTED=True -DUPLICATE_BLOCKED=False -TXT_COMMIT=4ef5989856165ac24b02ba54455d3782e16a7cae -ERROR_REGISTERED=no ---- COMMAND_ID=CLUSTER-REFERENCE-FOUNDATION-148 --- -JSON_HISTORY=MISSING -TXT_HISTORY=MISSING -ERROR_REGISTERED=no -=== RUNNER_MODE_RULES === -3-umask 077 -4- -5-usage() { -6- cat >&2 <<'USAGE' -7-Usage: -8- homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...] -9- -10-MODE: -11: read-only -12- verify -13: change -14- transport-test -15- -16-Environment: -17- HOMELAB_ALLOW_REPEAT=1 Allow exact repeat of a previously failed command. -18- HOMELAB_TIMEOUT=SECONDS Optional command timeout. -19-USAGE -20- exit 64 -21-} -22- -23-[ "$#" -ge 5 ] || usage -24- -25-COMMAND_ID="$1" -26-MODE="$2" -27-COMPONENT="$3" -28-shift 3 -29- -30-[ "${1:-}" = '--' ] || usage -31-shift -32-[ "$#" -ge 1 ] || usage -33- --- -43- ''|*[!A-Za-z0-9._-]*) -44- echo 'RESULT=FAIL' -45- echo 'REASON=INVALID_COMPONENT' -46- exit 66 -47- ;; -48-esac -49- -50-case "$MODE" in -51: read-only|verify|change|transport-test) -52- ;; -53- *) -54- echo 'RESULT=FAIL' -55: echo 'REASON=INVALID_MODE' -56- exit 67 -57- ;; -58-esac -59- -60-for TOOL in \ -61- awk \ -62- curl \ -63- flock \ -64- python3 \ -65- scp \ -66- sha256sum \ -67- ssh -68-do -69- command -v "$TOOL" >/dev/null 2>&1 || { -70- echo 'RESULT=FAIL' -71- echo "REASON=REQUIRED_TOOL_MISSING:$TOOL" -72- exit 68 -73- } -74-done -75- --- -139- print value -140- } -141- ' "$LEDGER" -142-)" -143- -144-RUN_STARTED=true -145-REPEAT_BLOCKED=false -146-BLOCK_REASON='' -147:CHANGES_MADE=false -148- -149-case "$MODE" in -150: change) -151: CHANGES_MADE=true -152- ;; -153-esac -154- -155-if [ -n "$PREVIOUS_FAILED_RC" ] && -156- [ "${HOMELAB_ALLOW_REPEAT:-0}" != 1 ]; then -157- -158- RUN_STARTED=false -159- REPEAT_BLOCKED=true -160- BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT' -161- RC=73 -162- STATUS='BLOCKED' -163- -164- { -165- echo 'COMMAND_EXECUTION_BLOCKED=yes' -166- echo 'REASON=EXACT_FAILED_COMMAND_REPEAT' -167- echo "PREVIOUS_RC=$PREVIOUS_FAILED_RC" -168- echo "COMMAND_SHA256=$COMMAND_SHA256" -169- echo -170- echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.' -171- } >"$RAW_FILE" --- -298- text = ( -299- first -300- + "\n\n" -301- + "===== PUBLIC OUTPUT TRUNCATED; FULL RAW LOG RETAINED LOCALLY =====" -302- + "\n\n" -303- + last -304- ) -305- -306:target.write_text(text, encoding="utf-8") -307-PY -308- -309-SANITIZED_SHA256="$( -310- sha256sum "$SANITIZED_FILE" | -311- awk '{print $1}' -312-)" -313- -314-python3 - \ -315- "$JSON_FILE" \ -316- "$SANITIZED_FILE" \ -317- "$COMMAND_ID" \ -318- "$STATUS" \ -319- "$RC" \ -320- "$HOST_SHORT" \ -321- "$MODE" \ -322- "$COMPONENT" \ -323- "$STARTED_AT" \ -324- "$FINISHED_AT" \ -325- "$REFERENCE_SHA256" \ -326- "$ERROR_REGISTER_SHA256" \ -327- "$COMMAND_SHA256" \ -328- "$RAW_SHA256" \ -329- "$SANITIZED_SHA256" \ -330- "$RUN_STARTED" \ -331- "$REPEAT_BLOCKED" \ -332- "$BLOCK_REASON" \ -333: "$CHANGES_MADE" <<'PY' -334-import json -335-import sys -336-from pathlib import Path -337- -338-( -339- json_path, -340- output_path, -341- command_id, -342- status, -343- rc, -344- host, -345- mode, -346- component, -347- started, -348- finished, -349- reference_sha, -350- error_sha, -351- command_sha, -352- raw_sha, -353- sanitized_sha, -354- run_started, -355- repeat_blocked, -356- block_reason, -357: changes_made, -358-) = sys.argv[1:] -359- -360-output = Path(output_path).read_text( -361- encoding="utf-8", -362- errors="replace", -363-) -364- -365-encoded = output.encode("utf-8") -366-json_limit = 300_000 -367-output_truncated = len(encoded) > json_limit -368- -369-if output_truncated: -370- output_preview = encoded[:json_limit].decode( -371- "utf-8", -372- errors="ignore", -373- ) -374-else: -375- output_preview = output -376- -377-document = { --- -388- "reference_register_checked": True, -389- "reference_sha256": reference_sha, -390- "error_register_checked": True, -391- "error_register_sha256": error_sha, -392- "command_sha256": command_sha, -393- "duplicate_failed_command_blocked": repeat_blocked == "true", -394- "block_reason": block_reason or None, -395- "execution_started": run_started == "true", -396: "changes_made": changes_made == "true", -397- "sanitized": True, -398- "secrets_included": False, -399- "private_addresses_included": False, -400- "raw_evidence_retained_locally": True, -401- "raw_evidence_sha256": raw_sha, -402- "sanitized_output_sha256": sanitized_sha, -403- "output_truncated_in_json": output_truncated, -404- "full_sanitized_output_url": ( -405- "https://git.gram1.ru/.well-known/" -406- "homelab-runtime/latest.txt" -407- ), -408- "output": output_preview, -409-} -410- -411:Path(json_path).write_text( -412- json.dumps( -413- document, -414- ensure_ascii=False, -415- indent=2, -416- ) -417- + "\n", -418- encoding="utf-8", -419-) -420-PY -421- -422-{ -423- echo 'CHAT_OUTPUT_BEGIN' -424- echo "COMMAND_ID=$COMMAND_ID" -425- echo "STATUS=$STATUS" -426- echo "RC=$RC" -427- echo "HOST=$HOST_SHORT" -428- echo "MODE=$MODE" -429- echo "COMPONENT=$COMPONENT" -430- echo 'REFERENCE_REGISTER_CHECK=OK' -431- echo "REFERENCE_SHA256=$REFERENCE_SHA256" -432- echo 'ERROR_REGISTER_CHECK=OK' -433- echo "ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256" -434- echo "COMMAND_SHA256=$COMMAND_SHA256" -435- echo "DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED" -436- echo "EXECUTION_STARTED=$RUN_STARTED" -437: echo "CHANGES_MADE=$CHANGES_MADE" -438- echo 'SANITIZED=yes' -439- echo 'SECRETS_INCLUDED=no' -440- echo 'PRIVATE_ADDRESSES_INCLUDED=no' -441- echo "RAW_EVIDENCE_SHA256=$RAW_SHA256" -442- echo "SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256" -443- echo 'OUTPUT_BEGIN' -444- cat "$SANITIZED_FILE" -445- echo -446- echo 'OUTPUT_END' -447- echo 'CHAT_OUTPUT_END' -448-} >"$TXT_FILE" -449- -450-chmod 0600 \ -451- "$RAW_FILE" \ -452- "$SANITIZED_FILE" \ -453- "$JSON_FILE" \ -454- "$TXT_FILE" -455- -456-TARGET=debian@[PRIVATE_IP] -457-REMOTE_PREFIX="/tmp/homelab-runtime-${COMMAND_ID}-$$" -=== PARTIAL_REFERENCE_STATE === +=== REFERENCE_STATE === REFERENCE_ROOT=ABSENT -REFERENCE_CLI=ABSENT -CLUSTER_REFERENCE_STATE_AUDIT=COMPLETE +REFERENCE_FILES=0 +REFERENCE_MANIFEST=ABSENT +NEXT_ACTION=RESOLVE_WRITE_MODE +CLUSTER_REFERENCE_DECISION=COMPLETE OUTPUT_END CHAT_OUTPUT_END