CHAT_OUTPUT_BEGIN COMMAND_ID=CLUSTER-REFERENCE-STATE-AUDIT-149 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=2af6ffbc1ab71f8fd13302a48794faa713dfcde5a4c90652ace8ab2355e3c2e4 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 OUTPUT_BEGIN === IMMUTABLE_COMMAND_RESULTS === --- COMMAND_ID=CLUSTER-REFERENCE-MODE-CONFIRM-145 --- JSON_COMMIT=072668fbc56c580756f0ad7a6a30e4a6af953794 STATUS=OK RC=0 REASON=None EXECUTION_STARTED=True DUPLICATE_BLOCKED=False TXT_COMMIT=072668fbc56c580756f0ad7a6a30e4a6af953794 VALID_MODES=change,read-only,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_ROOT=ABSENT REFERENCE_CLI=ABSENT CLUSTER_REFERENCE_STATE_AUDIT=COMPLETE OUTPUT_END CHAT_OUTPUT_END