From 62a9856e04593a5e9ba6ce0c0d1c1e86e3fb8a1b Mon Sep 17 00:00:00 2001 From: homelab-runtime-publisher Date: Fri, 24 Jul 2026 09:37:55 +0000 Subject: [PATCH] runtime: publish HOMELAB-DUPLICATE-EXACT-LOGIC-427 --- .../HOMELAB-DUPLICATE-EXACT-LOGIC-427.json | 30 + .../HOMELAB-DUPLICATE-EXACT-LOGIC-427.txt | 367 +++++++++ runtime/latest.json | 14 +- runtime/latest.txt | 748 ++++++++---------- 4 files changed, 745 insertions(+), 414 deletions(-) create mode 100644 runtime/history/HOMELAB-DUPLICATE-EXACT-LOGIC-427.json create mode 100644 runtime/history/HOMELAB-DUPLICATE-EXACT-LOGIC-427.txt diff --git a/runtime/history/HOMELAB-DUPLICATE-EXACT-LOGIC-427.json b/runtime/history/HOMELAB-DUPLICATE-EXACT-LOGIC-427.json new file mode 100644 index 0000000..c25e287 --- /dev/null +++ b/runtime/history/HOMELAB-DUPLICATE-EXACT-LOGIC-427.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "HOMELAB-DUPLICATE-EXACT-LOGIC-427", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "read-only", + "component": "cluster-audit", + "started_at_utc": "2026-07-24T09:37:54Z", + "finished_at_utc": "2026-07-24T09:37:54Z", + "reference_register_checked": true, + "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", + "error_register_checked": true, + "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752", + "command_sha256": "7e4f72d9877110d6d6d4ef926a611b1bd8ad15fa4b2ad3ef17e9027ba49bc111", + "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": "8480bb49baedd9fdebe212ee204d07d772e707d3c09045de0c3334fde723f6e9", + "sanitized_output_sha256": "5e8f3e2de086ae3c1d1bf84dcffbcb8dc8770ebefb00aa959db1ff15db3468b9", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "DETAIL=FILE=/usr/local/sbin/homelab-chat-run-linked\nDETAIL=SHA256=5e8725e129fd2055b36fe2fae13fc95fc4b3271074a0e0d4bb7347e7b2f270a1\nDETAIL=EXACT_LOGIC_BEGIN\nDETAIL=TOTAL_LINES=39\nDETAIL=EXACT_LOGIC_END\nDETAIL=FILE=/usr/local/sbin/homelab-chat-run\nDETAIL=SHA256=2a88defef9517f89bc60934dce82097f8e316b08af9417e95167ea5d759a10d9\nDETAIL=EXACT_LOGIC_BEGIN\nDETAIL=SOURCE_LINE=0048:esac\nDETAIL=SOURCE_LINE=0049:\nDETAIL=SOURCE_LINE=0050:case \"$MODE\" in\nDETAIL=SOURCE_LINE=0051: read-only|verify|change|transport-test)\nDETAIL=SOURCE_LINE=0052: ;;\nDETAIL=SOURCE_LINE=0053: *)\nDETAIL=SOURCE_LINE=0054: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0055: echo 'REASON=INVALID_MODE'\nDETAIL=SOURCE_LINE=0056: exit 67\nDETAIL=SOURCE_LINE=0057: ;;\nDETAIL=SOURCE_LINE=0058:esac\nDETAIL=SOURCE_LINE=0059:\nDETAIL=SOURCE_LINE=0060:for TOOL in \\\nDETAIL=SOURCE_LINE=0061: awk \\\nDETAIL=SOURCE_LINE=0062: curl \\\nDETAIL=SOURCE_LINE=0063: flock \\\nDETAIL=SOURCE_LINE=0064: python3 \\\nDETAIL=SOURCE_LINE=0065: scp \\\nDETAIL=SOURCE_LINE=0066: sha256sum \\\nDETAIL=SOURCE_LINE=0067: ssh\nDETAIL=SOURCE_LINE=0068:do\nDETAIL=SOURCE_LINE=0069: command -v \"$TOOL\" >/dev/null 2>&1 || {\nDETAIL=SOURCE_LINE=0070: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0071: echo \"REASON=REQUIRED_TOOL_MISSING:$TOOL\"\nDETAIL=SOURCE_LINE=0072: exit 68\nDETAIL=SOURCE_LINE=0073: }\nDETAIL=SOURCE_LINE=0074:done\nDETAIL=SOURCE_LINE=0075:\nDETAIL=SOURCE_LINE=0076:REFERENCE=/etc/pve/31_HOMELAB_REFERENCE.md\nDETAIL=SOURCE_LINE=0077:ERROR_REGISTER=/etc/pve/HOMELAB_ASSISTANT_ERROR_REGISTER.md\nDETAIL=SOURCE_LINE=0078:\nDETAIL=SOURCE_LINE=0079:[ -r \"$REFERENCE\" ] || {\nDETAIL=SOURCE_LINE=0080: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0081: echo 'REASON=REFERENCE_NOT_READABLE'\nDETAIL=SOURCE_LINE=0082: exit 69\nDETAIL=SOURCE_LINE=0083:}\nDETAIL=SOURCE_LINE=0084:\nDETAIL=SOURCE_LINE=0085:[ -r \"$ERROR_REGISTER\" ] || {\nDETAIL=SOURCE_LINE=0086: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0087: echo 'REASON=ERROR_REGISTER_NOT_READABLE'\nDETAIL=SOURCE_LINE=0088: exit 70\nDETAIL=SOURCE_LINE=0089:}\nDETAIL=SOURCE_LINE=0090:\nDETAIL=SOURCE_LINE=0091:STATE_DIR=/var/lib/homelab-chat-run\nDETAIL=SOURCE_LINE=0092:RAW_DIR=\"$STATE_DIR/raw\"\nDETAIL=SOURCE_LINE=0093:PUBLIC_DIR=\"$STATE_DIR/public\"\nDETAIL=SOURCE_LINE=0094:LEDGER=\"$STATE_DIR/state/command-ledger.tsv\"\nDETAIL=SOURCE_LINE=0095:LOCK=\"$STATE_DIR/state/runner.lock\"\nDETAIL=SOURCE_LINE=0096:\nDETAIL=SOURCE_LINE=0097:mkdir -p \"$RAW_DIR\" \"$PUBLIC_DIR\" \"$(dirname \"$LEDGER\")\"\nDETAIL=SOURCE_LINE=0098:chmod 0700 \"$STATE_DIR\" \"$RAW_DIR\" \"$PUBLIC_DIR\" \"$(dirname \"$LEDGER\")\"\nDETAIL=SOURCE_LINE=0099:touch \"$LEDGER\"\nDETAIL=SOURCE_LINE=0100:chmod 0600 \"$LEDGER\"\nDETAIL=SOURCE_LINE=0101:\nDETAIL=SOURCE_LINE=0102:exec 9>\"$LOCK\"\nDETAIL=SOURCE_LINE=0103:\nDETAIL=SOURCE_LINE=0104:flock -w 60 9 || {\nDETAIL=SOURCE_LINE=0105: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0106: echo 'REASON=RUNNER_LOCK_TIMEOUT'\nDETAIL=SOURCE_LINE=0107: exit 71\nDETAIL=SOURCE_LINE=0108:}\nDETAIL=SOURCE_LINE=0109:\nDETAIL=SOURCE_LINE=0110:STARTED_AT=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\nDETAIL=SOURCE_LINE=0111:STAMP=\"$(date -u +%Y%m%dT%H%M%SZ)\"\nDETAIL=SOURCE_LINE=0112:HOST_SHORT=\"$(hostname -s 2>/dev/null || hostname)\"\nDETAIL=SOURCE_LINE=0113:\nDETAIL=SOURCE_LINE=0114:RAW_FILE=\"$RAW_DIR/${COMMAND_ID}-${STAMP}.log\"\nDETAIL=SOURCE_LINE=0115:SANITIZED_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.txt\"\nDETAIL=SOURCE_LINE=0116:JSON_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.json\"\nDETAIL=SOURCE_LINE=0117:TXT_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}-latest.txt\"\nDETAIL=SOURCE_LINE=0118:\nDETAIL=SOURCE_LINE=0119:REFERENCE_SHA256=\"$(sha256sum \"$REFERENCE\" | awk '{print $1}')\"\nDETAIL=SOURCE_LINE=0120:ERROR_REGISTER_SHA256=\"$(sha256sum \"$ERROR_REGISTER\" | awk '{print $1}')\"\nDETAIL=SOURCE_LINE=0121:\nDETAIL=SOURCE_LINE=0122:COMMAND_SHA256=\"$(\nDETAIL=SOURCE_LINE=0123: {\nDETAIL=SOURCE_LINE=0124: printf '%s\\0' \"$MODE\"\nDETAIL=SOURCE_LINE=0125: printf '%s\\0' \"$COMPONENT\"\nDETAIL=SOURCE_LINE=0126: printf '%s\\0' \"$@\"\nDETAIL=SOURCE_LINE=0127: } |\nDETAIL=SOURCE_LINE=0128: sha256sum |\nDETAIL=SOURCE_LINE=0129: awk '{print $1}'\nDETAIL=SOURCE_LINE=0130:)\"\nDETAIL=SOURCE_LINE=0131:\nDETAIL=SOURCE_LINE=0132:PREVIOUS_FAILED_RC=\"$(\nDETAIL=SOURCE_LINE=0133: awk -F '\\t' -v hash=\"$COMMAND_SHA256\" '\nDETAIL=SOURCE_LINE=0134: $3 == hash && $4 != \"0\" {\nDETAIL=SOURCE_LINE=0135: value=$4\nDETAIL=SOURCE_LINE=0136: }\nDETAIL=SOURCE_LINE=0137:\nDETAIL=SOURCE_LINE=0138: END {\nDETAIL=SOURCE_LINE=0139: print value\nDETAIL=SOURCE_LINE=0140: }\nDETAIL=SOURCE_LINE=0141: ' \"$LEDGER\"\nDETAIL=SOURCE_LINE=0142:)\"\nDETAIL=SOURCE_LINE=0143:\nDETAIL=SOURCE_LINE=0144:RUN_STARTED=true\nDETAIL=SOURCE_LINE=0145:REPEAT_BLOCKED=false\nDETAIL=SOURCE_LINE=0146:BLOCK_REASON=''\nDETAIL=SOURCE_LINE=0147:CHANGES_MADE=false\nDETAIL=SOURCE_LINE=0148:\nDETAIL=SOURCE_LINE=0149:case \"$MODE\" in\nDETAIL=SOURCE_LINE=0150: change)\nDETAIL=SOURCE_LINE=0151: CHANGES_MADE=true\nDETAIL=SOURCE_LINE=0152: ;;\nDETAIL=SOURCE_LINE=0153:esac\nDETAIL=SOURCE_LINE=0154:\nDETAIL=SOURCE_LINE=0155:if [ -n \"$PREVIOUS_FAILED_RC\" ] &&\nDETAIL=SOURCE_LINE=0156: [ \"${HOMELAB_ALLOW_REPEAT:-0}\" != 1 ]; then\nDETAIL=SOURCE_LINE=0157:\nDETAIL=SOURCE_LINE=0158: RUN_STARTED=false\nDETAIL=SOURCE_LINE=0159: REPEAT_BLOCKED=true\nDETAIL=SOURCE_LINE=0160: BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT'\nDETAIL=SOURCE_LINE=0161: RC=73\nDETAIL=SOURCE_LINE=0162: STATUS='BLOCKED'\nDETAIL=SOURCE_LINE=0163:\nDETAIL=SOURCE_LINE=0164: {\nDETAIL=SOURCE_LINE=0165: echo 'COMMAND_EXECUTION_BLOCKED=yes'\nDETAIL=SOURCE_LINE=0166: echo 'REASON=EXACT_FAILED_COMMAND_REPEAT'\nDETAIL=SOURCE_LINE=0167: echo \"PREVIOUS_RC=$PREVIOUS_FAILED_RC\"\nDETAIL=SOURCE_LINE=0168: echo \"COMMAND_SHA256=$COMMAND_SHA256\"\nDETAIL=SOURCE_LINE=0169: echo\nDETAIL=SOURCE_LINE=0170: echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.'\nDETAIL=SOURCE_LINE=0171: } >\"$RAW_FILE\"\nDETAIL=SOURCE_LINE=0172:else\nDETAIL=SOURCE_LINE=0173: set +e\nDETAIL=SOURCE_LINE=0174:\nDETAIL=SOURCE_LINE=0175: if [ -n \"${HOMELAB_TIMEOUT:-}\" ]; then\nDETAIL=SOURCE_LINE=0176: case \"$HOMELAB_TIMEOUT\" in\nDETAIL=SOURCE_LINE=0177: *[!0-9]*|'')\nDETAIL=SOURCE_LINE=0178: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0179: echo 'REASON=INVALID_HOMELAB_TIMEOUT'\nDETAIL=SOURCE_LINE=0180: exit 74\nDETAIL=SOURCE_LINE=0181: ;;\nDETAIL=SOURCE_LINE=0182: esac\nDETAIL=SOURCE_LINE=0183:\nDETAIL=SOURCE_LINE=0184: timeout \\\nDETAIL=SOURCE_LINE=0185: --foreground \\\nDETAIL=SOURCE_LINE=0186: --preserve-status \\\nDETAIL=SOURCE_LINE=0187: \"$HOMELAB_TIMEOUT\" \\\nDETAIL=SOURCE_LINE=0188: \"$@\" >\"$RAW_FILE\" 2>&1\nDETAIL=SOURCE_LINE=0189: RC=$?\nDETAIL=SOURCE_LINE=0190: else\nDETAIL=SOURCE_LINE=0191: \"$@\" >\"$RAW_FILE\" 2>&1\nDETAIL=SOURCE_LINE=0192: RC=$?\nDETAIL=SOURCE_LINE=0193: fi\nDETAIL=SOURCE_LINE=0194:\nDETAIL=SOURCE_LINE=0195: set -e\nDETAIL=SOURCE_LINE=0196:\nDETAIL=SOURCE_LINE=0197: if [ \"$RC\" -eq 0 ]; then\nDETAIL=SOURCE_LINE=0198: STATUS='OK'\nDETAIL=SOURCE_LINE=0199: else\nDETAIL=SOURCE_LINE=0200: STATUS='FAIL'\nDETAIL=SOURCE_LINE=0201: fi\nDETAIL=SOURCE_LINE=0202:fi\nDETAIL=SOURCE_LINE=0203:\nDETAIL=SOURCE_LINE=0204:FINISHED_AT=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\nDETAIL=SOURCE_LINE=0205:RAW_SHA256=\"$(sha256sum \"$RAW_FILE\" | awk '{print $1}')\"\nDETAIL=SOURCE_LINE=0206:\nDETAIL=SOURCE_LINE=0207:python3 - \"$RAW_FILE\" \"$SANITIZED_FILE\" <<'PY'\nDETAIL=SOURCE_LINE=0208:import re\nDETAIL=SOURCE_LINE=0209:import sys\nDETAIL=SOURCE_LINE=0210:from pathlib import Path\nDETAIL=SOURCE_LINE=0211:\nDETAIL=SOURCE_LINE=0212:source = Path(sys.argv[1])\nDETAIL=SOURCE_LINE=0213:target = Path(sys.argv[2])\nDETAIL=SOURCE_LINE=0214:\nDETAIL=SOURCE_LINE=0215:text = source.read_bytes().decode(\"utf-8\", errors=\"replace\")\nDETAIL=SOURCE_LINE=0216:\nDETAIL=SOURCE_LINE=0217:patterns = [\nDETAIL=SOURCE_LINE=0218: (\nDETAIL=SOURCE_LINE=0219: re.compile(\nDETAIL=SOURCE_LINE=0220: r\"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\"\nDETAIL=SOURCE_LINE=0221: r\".*?\"\nDETAIL=SOURCE_LINE=0222: r\"-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\",\nDETAIL=SOURCE_LINE=0223: re.IGNORECASE | re.DOTALL,\nDETAIL=SOURCE_LINE=0224: ),\nDETAIL=SOURCE_LINE=0225: \"[PRIVATE_KEY_REDACTED]\",\nDETAIL=SOURCE_LINE=0226: ),\nDETAIL=SOURCE_LINE=0227: (\nDETAIL=SOURCE_LINE=0228: re.compile(\nDETAIL=SOURCE_LINE=0229: r\"(?im)^(\\s*(?:password|passwd|passphrase|authorization|\"\nDETAIL=SOURCE_LINE=...\nDETAIL=SOURCE_LINE=0292:maximum = 900_000\nDETAIL=SOURCE_LINE=0293:\nDETAIL=SOURCE_LINE=0294:if len(encoded) > maximum:\nDETAIL=SOURCE_LINE=0295: first = encoded[:440_000].decode(\"utf-8\", errors=\"ignore\")\nDETAIL=SOURCE_LINE=0296: last = encoded[-440_000:].decode(\"utf-8\", errors=\"ignore\")\nDETAIL=SOURCE_LINE=0297:\nDETAIL=SOURCE_LINE=0298: text = (\nDETAIL=SOURCE_LINE=0299: first\nDETAIL=SOURCE_LINE=0300: + \"\\n\\n\"\nDETAIL=SOURCE_LINE=0301: + \"===== PUBLIC OUTPUT TRUNCATED; FULL RAW LOG RETAINED LOCALLY =====\"\nDETAIL=SOURCE_LINE=0302: + \"\\n\\n\"\nDETAIL=SOURCE_LINE=0303: + last\nDETAIL=SOURCE_LINE=0304: )\nDETAIL=SOURCE_LINE=0305:\nDETAIL=SOURCE_LINE=0306:target.write_text(text, encoding=\"utf-8\")\nDETAIL=SOURCE_LINE=0307:PY\nDETAIL=SOURCE_LINE=0308:\nDETAIL=SOURCE_LINE=0309:SANITIZED_SHA256=\"$(\nDETAIL=SOURCE_LINE=0310: sha256sum \"$SANITIZED_FILE\" |\nDETAIL=SOURCE_LINE=0311: awk '{print $1}'\nDETAIL=SOURCE_LINE=0312:)\"\nDETAIL=SOURCE_LINE=0313:\nDETAIL=SOURCE_LINE=0314:python3 - \\\nDETAIL=SOURCE_LINE=0315: \"$JSON_FILE\" \\\nDETAIL=SOURCE_LINE=0316: \"$SANITIZED_FILE\" \\\nDETAIL=SOURCE_LINE=0317: \"$COMMAND_ID\" \\\nDETAIL=SOURCE_LINE=0318: \"$STATUS\" \\\nDETAIL=SOURCE_LINE=0319: \"$RC\" \\\nDETAIL=SOURCE_LINE=0320: \"$HOST_SHORT\" \\\nDETAIL=SOURCE_LINE=0321: \"$MODE\" \\\nDETAIL=SOURCE_LINE=0322: \"$COMPONENT\" \\\nDETAIL=SOURCE_LINE=0323: \"$STARTED_AT\" \\\nDETAIL=SOURCE_LINE=0324: \"$FINISHED_AT\" \\\nDETAIL=SOURCE_LINE=0325: \"$REFERENCE_SHA256\" \\\nDETAIL=SOURCE_LINE=0326: \"$ERROR_REGISTER_SHA256\" \\\nDETAIL=SOURCE_LINE=0327: \"$COMMAND_SHA256\" \\\nDETAIL=SOURCE_LINE=0328: \"$RAW_SHA256\" \\\nDETAIL=SOURCE_LINE=0329: \"$SANITIZED_SHA256\" \\\nDETAIL=SOURCE_LINE=0330: \"$RUN_STARTED\" \\\nDETAIL=SOURCE_LINE=0331: \"$REPEAT_BLOCKED\" \\\nDETAIL=SOURCE_LINE=0332: \"$BLOCK_REASON\" \\\nDETAIL=SOURCE_LINE=0333: \"$CHANGES_MADE\" <<'PY'\nDETAIL=SOURCE_LINE=0334:import json\nDETAIL=SOURCE_LINE=0335:import sys\nDETAIL=SOURCE_LINE=0336:from pathlib import Path\nDETAIL=SOURCE_LINE=0337:\nDETAIL=SOURCE_LINE=0338:(\nDETAIL=SOURCE_LINE=0339: json_path,\nDETAIL=SOURCE_LINE=0340: output_path,\nDETAIL=SOURCE_LINE=0341: command_id,\nDETAIL=SOURCE_LINE=0342: status,\nDETAIL=SOURCE_LINE=0343: rc,\nDETAIL=SOURCE_LINE=0344: host,\nDETAIL=SOURCE_LINE=0345: mode,\nDETAIL=SOURCE_LINE=0346: component,\nDETAIL=SOURCE_LINE=0347: started,\nDETAIL=SOURCE_LINE=0348: finished,\nDETAIL=SOURCE_LINE=0349: reference_sha,\nDETAIL=SOURCE_LINE=0350: error_sha,\nDETAIL=SOURCE_LINE=0351: command_sha,\nDETAIL=SOURCE_LINE=0352: raw_sha,\nDETAIL=SOURCE_LINE=0353: sanitized_sha,\nDETAIL=SOURCE_LINE=0354: run_started,\nDETAIL=SOURCE_LINE=0355: repeat_blocked,\nDETAIL=SOURCE_LINE=...\nDETAIL=SOURCE_LINE=0416: )\nDETAIL=SOURCE_LINE=0417: + \"\\n\",\nDETAIL=SOURCE_LINE=0418: encoding=\"utf-8\",\nDETAIL=SOURCE_LINE=0419:)\nDETAIL=SOURCE_LINE=0420:PY\nDETAIL=SOURCE_LINE=0421:\nDETAIL=SOURCE_LINE=0422:{\nDETAIL=SOURCE_LINE=0423: echo 'CHAT_OUTPUT_BEGIN'\nDETAIL=SOURCE_LINE=0424: echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE_LINE=0425: echo \"STATUS=$STATUS\"\nDETAIL=SOURCE_LINE=0426: echo \"RC=$RC\"\nDETAIL=SOURCE_LINE=0427: echo \"HOST=$HOST_SHORT\"\nDETAIL=SOURCE_LINE=0428: echo \"MODE=$MODE\"\nDETAIL=SOURCE_LINE=0429: echo \"COMPONENT=$COMPONENT\"\nDETAIL=SOURCE_LINE=0430: echo 'REFERENCE_REGISTER_CHECK=OK'\nDETAIL=SOURCE_LINE=0431: echo \"REFERENCE_SHA256=$REFERENCE_SHA256\"\nDETAIL=SOURCE_LINE=0432: echo 'ERROR_REGISTER_CHECK=OK'\nDETAIL=SOURCE_LINE=0433: echo \"ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256\"\nDETAIL=SOURCE_LINE=0434: echo \"COMMAND_SHA256=$COMMAND_SHA256\"\nDETAIL=SOURCE_LINE=0435: echo \"DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED\"\nDETAIL=SOURCE_LINE=0436: echo \"EXECUTION_STARTED=$RUN_STARTED\"\nDETAIL=SOURCE_LINE=0437: echo \"CHANGES_MADE=$CHANGES_MADE\"\nDETAIL=SOURCE_LINE=0438: echo 'SANITIZED=yes'\nDETAIL=SOURCE_LINE=0439: echo 'SECRETS_INCLUDED=no'\nDETAIL=SOURCE_LINE=0440: echo 'PRIVATE_ADDRESSES_INCLUDED=no'\nDETAIL=SOURCE_LINE=0441: echo \"RAW_EVIDENCE_SHA256=$RAW_SHA256\"\nDETAIL=SOURCE_LINE=0442: echo \"SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256\"\nDETAIL=SOURCE_LINE=0443: echo 'OUTPUT_BEGIN'\nDETAIL=SOURCE_LINE=0444: cat \"$SANITIZED_FILE\"\nDETAIL=SOURCE_LINE=0445: echo\nDETAIL=SOURCE_LINE=0446: echo 'OUTPUT_END'\nDETAIL=SOURCE_LINE=0447: echo 'CHAT_OUTPUT_END'\nDETAIL=SOURCE_LINE=0448:} >\"$TXT_FILE\"\nDETAIL=SOURCE_LINE=0449:\nDETAIL=SOURCE_LINE=0450:chmod 0600 \\\nDETAIL=SOURCE_LINE=0451: \"$RAW_FILE\" \\\nDETAIL=SOURCE_LINE=0452: \"$SANITIZED_FILE\" \\\nDETAIL=SOURCE_LINE=0453: \"$JSON_FILE\" \\\nDETAIL=SOURCE_LINE=0454: \"$TXT_FILE\"\nDETAIL=SOURCE_LINE=0455:\nDETAIL=SOURCE_LINE=0456:TARGET=debian@[PRIVATE_IP]\nDETAIL=SOURCE_LINE=0457:REMOTE_PREFIX=\"/tmp/homelab-runtime-${COMMAND_ID}-$$\"\nDETAIL=SOURCE_LINE=0458:\nDETAIL=SOURCE_LINE=0459:SSH_OPTS=(\nDETAIL=SOURCE_LINE=...\nDETAIL=SOURCE_LINE=0509: PUBLIC_VISIBLE=true\nDETAIL=SOURCE_LINE=0510: break\nDETAIL=SOURCE_LINE=0511: fi\nDETAIL=SOURCE_LINE=0512:\nDETAIL=SOURCE_LINE=0513: sleep 2\nDETAIL=SOURCE_LINE=0514:done\nDETAIL=SOURCE_LINE=0515:\nDETAIL=SOURCE_LINE=0516:if [ \"$PUBLIC_VISIBLE\" != true ]; then\nDETAIL=SOURCE_LINE=0517: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0518: echo 'REASON=PUBLIC_RUNTIME_RESULT_NOT_VISIBLE'\nDETAIL=SOURCE_LINE=0519: echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE_LINE=0520: echo \"LOCAL_RAW_FILE=$RAW_FILE\"\nDETAIL=SOURCE_LINE=0521: exit 75\nDETAIL=SOURCE_LINE=0522:fi\nDETAIL=SOURCE_LINE=0523:\nDETAIL=SOURCE_LINE=0524:printf '%s\\t%s\\t%s\\t%s\\t%s\\t%s\\n' \\\nDETAIL=SOURCE_LINE=0525: \"$FINISHED_AT\" \\\nDETAIL=SOURCE_LINE=0526: \"$COMMAND_ID\" \\\nDETAIL=SOURCE_LINE=0527: \"$COMMAND_SHA256\" \\\nDETAIL=SOURCE_LINE=0528: \"$RC\" \\\nDETAIL=SOURCE_LINE=0529: \"$STATUS\" \\\nDETAIL=SOURCE_LINE=0530: \"$COMPONENT\" >>\"$LEDGER\"\nDETAIL=SOURCE_LINE=0531:\nDETAIL=SOURCE_LINE=0532:echo\nDETAIL=SOURCE_LINE=0533:echo '===== HOMELAB CHAT RUN COMPLETE ====='\nDETAIL=SOURCE_LINE=0534:echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE_LINE=0535:echo \"STATUS=$STATUS\"\nDETAIL=SOURCE_LINE=0536:echo \"RC=$RC\"\nDETAIL=SOURCE_LINE=0537:echo 'REFERENCE_REGISTER_CHECK=OK'\nDETAIL=SOURCE_LINE=0538:echo 'ERROR_REGISTER_CHECK=OK'\nDETAIL=SOURCE_LINE=0539:echo \"DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED\"\nDETAIL=SOURCE_LINE=0540:echo 'GITEA_PUBLICATION=OK'\nDETAIL=SOURCE_LINE=0541:echo \"PUBLIC_URL=$PUBLIC_URL\"\nDETAIL=SOURCE_LINE=0542:echo \"LOCAL_RAW_FILE=$RAW_FILE\"\nDETAIL=SOURCE_LINE=0543:echo 'SHELL_SESSION_PRESERVED=yes'\nDETAIL=SOURCE_LINE=0544:\nDETAIL=SOURCE_LINE=0545:exit \"$RC\"\nDETAIL=TOTAL_LINES=545\nDETAIL=EXACT_LOGIC_END\nDETAIL=DUPLICATE_EXACT_LOGIC_AUDIT=PASS\nDETAIL=SECRET_VALUES_OUTPUT=NONE\nCHANGES_MADE=NO\n" +} diff --git a/runtime/history/HOMELAB-DUPLICATE-EXACT-LOGIC-427.txt b/runtime/history/HOMELAB-DUPLICATE-EXACT-LOGIC-427.txt new file mode 100644 index 0000000..ee624d2 --- /dev/null +++ b/runtime/history/HOMELAB-DUPLICATE-EXACT-LOGIC-427.txt @@ -0,0 +1,367 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=HOMELAB-DUPLICATE-EXACT-LOGIC-427 +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=7e4f72d9877110d6d6d4ef926a611b1bd8ad15fa4b2ad3ef17e9027ba49bc111 +DUPLICATE_FAILED_COMMAND_BLOCKED=false +EXECUTION_STARTED=true +CHANGES_MADE=false +SANITIZED=yes +SECRETS_INCLUDED=no +PRIVATE_ADDRESSES_INCLUDED=no +RAW_EVIDENCE_SHA256=8480bb49baedd9fdebe212ee204d07d772e707d3c09045de0c3334fde723f6e9 +SANITIZED_OUTPUT_SHA256=5e8f3e2de086ae3c1d1bf84dcffbcb8dc8770ebefb00aa959db1ff15db3468b9 +OUTPUT_BEGIN +DETAIL=FILE=/usr/local/sbin/homelab-chat-run-linked +DETAIL=SHA256=5e8725e129fd2055b36fe2fae13fc95fc4b3271074a0e0d4bb7347e7b2f270a1 +DETAIL=EXACT_LOGIC_BEGIN +DETAIL=TOTAL_LINES=39 +DETAIL=EXACT_LOGIC_END +DETAIL=FILE=/usr/local/sbin/homelab-chat-run +DETAIL=SHA256=2a88defef9517f89bc60934dce82097f8e316b08af9417e95167ea5d759a10d9 +DETAIL=EXACT_LOGIC_BEGIN +DETAIL=SOURCE_LINE=0048:esac +DETAIL=SOURCE_LINE=0049: +DETAIL=SOURCE_LINE=0050:case "$MODE" in +DETAIL=SOURCE_LINE=0051: read-only|verify|change|transport-test) +DETAIL=SOURCE_LINE=0052: ;; +DETAIL=SOURCE_LINE=0053: *) +DETAIL=SOURCE_LINE=0054: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0055: echo 'REASON=INVALID_MODE' +DETAIL=SOURCE_LINE=0056: exit 67 +DETAIL=SOURCE_LINE=0057: ;; +DETAIL=SOURCE_LINE=0058:esac +DETAIL=SOURCE_LINE=0059: +DETAIL=SOURCE_LINE=0060:for TOOL in \ +DETAIL=SOURCE_LINE=0061: awk \ +DETAIL=SOURCE_LINE=0062: curl \ +DETAIL=SOURCE_LINE=0063: flock \ +DETAIL=SOURCE_LINE=0064: python3 \ +DETAIL=SOURCE_LINE=0065: scp \ +DETAIL=SOURCE_LINE=0066: sha256sum \ +DETAIL=SOURCE_LINE=0067: ssh +DETAIL=SOURCE_LINE=0068:do +DETAIL=SOURCE_LINE=0069: command -v "$TOOL" >/dev/null 2>&1 || { +DETAIL=SOURCE_LINE=0070: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0071: echo "REASON=REQUIRED_TOOL_MISSING:$TOOL" +DETAIL=SOURCE_LINE=0072: exit 68 +DETAIL=SOURCE_LINE=0073: } +DETAIL=SOURCE_LINE=0074:done +DETAIL=SOURCE_LINE=0075: +DETAIL=SOURCE_LINE=0076:REFERENCE=/etc/pve/31_HOMELAB_REFERENCE.md +DETAIL=SOURCE_LINE=0077:ERROR_REGISTER=/etc/pve/HOMELAB_ASSISTANT_ERROR_REGISTER.md +DETAIL=SOURCE_LINE=0078: +DETAIL=SOURCE_LINE=0079:[ -r "$REFERENCE" ] || { +DETAIL=SOURCE_LINE=0080: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0081: echo 'REASON=REFERENCE_NOT_READABLE' +DETAIL=SOURCE_LINE=0082: exit 69 +DETAIL=SOURCE_LINE=0083:} +DETAIL=SOURCE_LINE=0084: +DETAIL=SOURCE_LINE=0085:[ -r "$ERROR_REGISTER" ] || { +DETAIL=SOURCE_LINE=0086: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0087: echo 'REASON=ERROR_REGISTER_NOT_READABLE' +DETAIL=SOURCE_LINE=0088: exit 70 +DETAIL=SOURCE_LINE=0089:} +DETAIL=SOURCE_LINE=0090: +DETAIL=SOURCE_LINE=0091:STATE_DIR=/var/lib/homelab-chat-run +DETAIL=SOURCE_LINE=0092:RAW_DIR="$STATE_DIR/raw" +DETAIL=SOURCE_LINE=0093:PUBLIC_DIR="$STATE_DIR/public" +DETAIL=SOURCE_LINE=0094:LEDGER="$STATE_DIR/state/command-ledger.tsv" +DETAIL=SOURCE_LINE=0095:LOCK="$STATE_DIR/state/runner.lock" +DETAIL=SOURCE_LINE=0096: +DETAIL=SOURCE_LINE=0097:mkdir -p "$RAW_DIR" "$PUBLIC_DIR" "$(dirname "$LEDGER")" +DETAIL=SOURCE_LINE=0098:chmod 0700 "$STATE_DIR" "$RAW_DIR" "$PUBLIC_DIR" "$(dirname "$LEDGER")" +DETAIL=SOURCE_LINE=0099:touch "$LEDGER" +DETAIL=SOURCE_LINE=0100:chmod 0600 "$LEDGER" +DETAIL=SOURCE_LINE=0101: +DETAIL=SOURCE_LINE=0102:exec 9>"$LOCK" +DETAIL=SOURCE_LINE=0103: +DETAIL=SOURCE_LINE=0104:flock -w 60 9 || { +DETAIL=SOURCE_LINE=0105: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0106: echo 'REASON=RUNNER_LOCK_TIMEOUT' +DETAIL=SOURCE_LINE=0107: exit 71 +DETAIL=SOURCE_LINE=0108:} +DETAIL=SOURCE_LINE=0109: +DETAIL=SOURCE_LINE=0110:STARTED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +DETAIL=SOURCE_LINE=0111:STAMP="$(date -u +%Y%m%dT%H%M%SZ)" +DETAIL=SOURCE_LINE=0112:HOST_SHORT="$(hostname -s 2>/dev/null || hostname)" +DETAIL=SOURCE_LINE=0113: +DETAIL=SOURCE_LINE=0114:RAW_FILE="$RAW_DIR/${COMMAND_ID}-${STAMP}.log" +DETAIL=SOURCE_LINE=0115:SANITIZED_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.txt" +DETAIL=SOURCE_LINE=0116:JSON_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.json" +DETAIL=SOURCE_LINE=0117:TXT_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}-latest.txt" +DETAIL=SOURCE_LINE=0118: +DETAIL=SOURCE_LINE=0119:REFERENCE_SHA256="$(sha256sum "$REFERENCE" | awk '{print $1}')" +DETAIL=SOURCE_LINE=0120:ERROR_REGISTER_SHA256="$(sha256sum "$ERROR_REGISTER" | awk '{print $1}')" +DETAIL=SOURCE_LINE=0121: +DETAIL=SOURCE_LINE=0122:COMMAND_SHA256="$( +DETAIL=SOURCE_LINE=0123: { +DETAIL=SOURCE_LINE=0124: printf '%s\0' "$MODE" +DETAIL=SOURCE_LINE=0125: printf '%s\0' "$COMPONENT" +DETAIL=SOURCE_LINE=0126: printf '%s\0' "$@" +DETAIL=SOURCE_LINE=0127: } | +DETAIL=SOURCE_LINE=0128: sha256sum | +DETAIL=SOURCE_LINE=0129: awk '{print $1}' +DETAIL=SOURCE_LINE=0130:)" +DETAIL=SOURCE_LINE=0131: +DETAIL=SOURCE_LINE=0132:PREVIOUS_FAILED_RC="$( +DETAIL=SOURCE_LINE=0133: awk -F '\t' -v hash="$COMMAND_SHA256" ' +DETAIL=SOURCE_LINE=0134: $3 == hash && $4 != "0" { +DETAIL=SOURCE_LINE=0135: value=$4 +DETAIL=SOURCE_LINE=0136: } +DETAIL=SOURCE_LINE=0137: +DETAIL=SOURCE_LINE=0138: END { +DETAIL=SOURCE_LINE=0139: print value +DETAIL=SOURCE_LINE=0140: } +DETAIL=SOURCE_LINE=0141: ' "$LEDGER" +DETAIL=SOURCE_LINE=0142:)" +DETAIL=SOURCE_LINE=0143: +DETAIL=SOURCE_LINE=0144:RUN_STARTED=true +DETAIL=SOURCE_LINE=0145:REPEAT_BLOCKED=false +DETAIL=SOURCE_LINE=0146:BLOCK_REASON='' +DETAIL=SOURCE_LINE=0147:CHANGES_MADE=false +DETAIL=SOURCE_LINE=0148: +DETAIL=SOURCE_LINE=0149:case "$MODE" in +DETAIL=SOURCE_LINE=0150: change) +DETAIL=SOURCE_LINE=0151: CHANGES_MADE=true +DETAIL=SOURCE_LINE=0152: ;; +DETAIL=SOURCE_LINE=0153:esac +DETAIL=SOURCE_LINE=0154: +DETAIL=SOURCE_LINE=0155:if [ -n "$PREVIOUS_FAILED_RC" ] && +DETAIL=SOURCE_LINE=0156: [ "${HOMELAB_ALLOW_REPEAT:-0}" != 1 ]; then +DETAIL=SOURCE_LINE=0157: +DETAIL=SOURCE_LINE=0158: RUN_STARTED=false +DETAIL=SOURCE_LINE=0159: REPEAT_BLOCKED=true +DETAIL=SOURCE_LINE=0160: BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT' +DETAIL=SOURCE_LINE=0161: RC=73 +DETAIL=SOURCE_LINE=0162: STATUS='BLOCKED' +DETAIL=SOURCE_LINE=0163: +DETAIL=SOURCE_LINE=0164: { +DETAIL=SOURCE_LINE=0165: echo 'COMMAND_EXECUTION_BLOCKED=yes' +DETAIL=SOURCE_LINE=0166: echo 'REASON=EXACT_FAILED_COMMAND_REPEAT' +DETAIL=SOURCE_LINE=0167: echo "PREVIOUS_RC=$PREVIOUS_FAILED_RC" +DETAIL=SOURCE_LINE=0168: echo "COMMAND_SHA256=$COMMAND_SHA256" +DETAIL=SOURCE_LINE=0169: echo +DETAIL=SOURCE_LINE=0170: echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.' +DETAIL=SOURCE_LINE=0171: } >"$RAW_FILE" +DETAIL=SOURCE_LINE=0172:else +DETAIL=SOURCE_LINE=0173: set +e +DETAIL=SOURCE_LINE=0174: +DETAIL=SOURCE_LINE=0175: if [ -n "${HOMELAB_TIMEOUT:-}" ]; then +DETAIL=SOURCE_LINE=0176: case "$HOMELAB_TIMEOUT" in +DETAIL=SOURCE_LINE=0177: *[!0-9]*|'') +DETAIL=SOURCE_LINE=0178: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0179: echo 'REASON=INVALID_HOMELAB_TIMEOUT' +DETAIL=SOURCE_LINE=0180: exit 74 +DETAIL=SOURCE_LINE=0181: ;; +DETAIL=SOURCE_LINE=0182: esac +DETAIL=SOURCE_LINE=0183: +DETAIL=SOURCE_LINE=0184: timeout \ +DETAIL=SOURCE_LINE=0185: --foreground \ +DETAIL=SOURCE_LINE=0186: --preserve-status \ +DETAIL=SOURCE_LINE=0187: "$HOMELAB_TIMEOUT" \ +DETAIL=SOURCE_LINE=0188: "$@" >"$RAW_FILE" 2>&1 +DETAIL=SOURCE_LINE=0189: RC=$? +DETAIL=SOURCE_LINE=0190: else +DETAIL=SOURCE_LINE=0191: "$@" >"$RAW_FILE" 2>&1 +DETAIL=SOURCE_LINE=0192: RC=$? +DETAIL=SOURCE_LINE=0193: fi +DETAIL=SOURCE_LINE=0194: +DETAIL=SOURCE_LINE=0195: set -e +DETAIL=SOURCE_LINE=0196: +DETAIL=SOURCE_LINE=0197: if [ "$RC" -eq 0 ]; then +DETAIL=SOURCE_LINE=0198: STATUS='OK' +DETAIL=SOURCE_LINE=0199: else +DETAIL=SOURCE_LINE=0200: STATUS='FAIL' +DETAIL=SOURCE_LINE=0201: fi +DETAIL=SOURCE_LINE=0202:fi +DETAIL=SOURCE_LINE=0203: +DETAIL=SOURCE_LINE=0204:FINISHED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +DETAIL=SOURCE_LINE=0205:RAW_SHA256="$(sha256sum "$RAW_FILE" | awk '{print $1}')" +DETAIL=SOURCE_LINE=0206: +DETAIL=SOURCE_LINE=0207:python3 - "$RAW_FILE" "$SANITIZED_FILE" <<'PY' +DETAIL=SOURCE_LINE=0208:import re +DETAIL=SOURCE_LINE=0209:import sys +DETAIL=SOURCE_LINE=0210:from pathlib import Path +DETAIL=SOURCE_LINE=0211: +DETAIL=SOURCE_LINE=0212:source = Path(sys.argv[1]) +DETAIL=SOURCE_LINE=0213:target = Path(sys.argv[2]) +DETAIL=SOURCE_LINE=0214: +DETAIL=SOURCE_LINE=0215:text = source.read_bytes().decode("utf-8", errors="replace") +DETAIL=SOURCE_LINE=0216: +DETAIL=SOURCE_LINE=0217:patterns = [ +DETAIL=SOURCE_LINE=0218: ( +DETAIL=SOURCE_LINE=0219: re.compile( +DETAIL=SOURCE_LINE=0220: r"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----" +DETAIL=SOURCE_LINE=0221: r".*?" +DETAIL=SOURCE_LINE=0222: r"-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----", +DETAIL=SOURCE_LINE=0223: re.IGNORECASE | re.DOTALL, +DETAIL=SOURCE_LINE=0224: ), +DETAIL=SOURCE_LINE=0225: "[PRIVATE_KEY_REDACTED]", +DETAIL=SOURCE_LINE=0226: ), +DETAIL=SOURCE_LINE=0227: ( +DETAIL=SOURCE_LINE=0228: re.compile( +DETAIL=SOURCE_LINE=0229: r"(?im)^(\s*(?:password|passwd|passphrase|authorization|" +DETAIL=SOURCE_LINE=... +DETAIL=SOURCE_LINE=0292:maximum = 900_000 +DETAIL=SOURCE_LINE=0293: +DETAIL=SOURCE_LINE=0294:if len(encoded) > maximum: +DETAIL=SOURCE_LINE=0295: first = encoded[:440_000].decode("utf-8", errors="ignore") +DETAIL=SOURCE_LINE=0296: last = encoded[-440_000:].decode("utf-8", errors="ignore") +DETAIL=SOURCE_LINE=0297: +DETAIL=SOURCE_LINE=0298: text = ( +DETAIL=SOURCE_LINE=0299: first +DETAIL=SOURCE_LINE=0300: + "\n\n" +DETAIL=SOURCE_LINE=0301: + "===== PUBLIC OUTPUT TRUNCATED; FULL RAW LOG RETAINED LOCALLY =====" +DETAIL=SOURCE_LINE=0302: + "\n\n" +DETAIL=SOURCE_LINE=0303: + last +DETAIL=SOURCE_LINE=0304: ) +DETAIL=SOURCE_LINE=0305: +DETAIL=SOURCE_LINE=0306:target.write_text(text, encoding="utf-8") +DETAIL=SOURCE_LINE=0307:PY +DETAIL=SOURCE_LINE=0308: +DETAIL=SOURCE_LINE=0309:SANITIZED_SHA256="$( +DETAIL=SOURCE_LINE=0310: sha256sum "$SANITIZED_FILE" | +DETAIL=SOURCE_LINE=0311: awk '{print $1}' +DETAIL=SOURCE_LINE=0312:)" +DETAIL=SOURCE_LINE=0313: +DETAIL=SOURCE_LINE=0314:python3 - \ +DETAIL=SOURCE_LINE=0315: "$JSON_FILE" \ +DETAIL=SOURCE_LINE=0316: "$SANITIZED_FILE" \ +DETAIL=SOURCE_LINE=0317: "$COMMAND_ID" \ +DETAIL=SOURCE_LINE=0318: "$STATUS" \ +DETAIL=SOURCE_LINE=0319: "$RC" \ +DETAIL=SOURCE_LINE=0320: "$HOST_SHORT" \ +DETAIL=SOURCE_LINE=0321: "$MODE" \ +DETAIL=SOURCE_LINE=0322: "$COMPONENT" \ +DETAIL=SOURCE_LINE=0323: "$STARTED_AT" \ +DETAIL=SOURCE_LINE=0324: "$FINISHED_AT" \ +DETAIL=SOURCE_LINE=0325: "$REFERENCE_SHA256" \ +DETAIL=SOURCE_LINE=0326: "$ERROR_REGISTER_SHA256" \ +DETAIL=SOURCE_LINE=0327: "$COMMAND_SHA256" \ +DETAIL=SOURCE_LINE=0328: "$RAW_SHA256" \ +DETAIL=SOURCE_LINE=0329: "$SANITIZED_SHA256" \ +DETAIL=SOURCE_LINE=0330: "$RUN_STARTED" \ +DETAIL=SOURCE_LINE=0331: "$REPEAT_BLOCKED" \ +DETAIL=SOURCE_LINE=0332: "$BLOCK_REASON" \ +DETAIL=SOURCE_LINE=0333: "$CHANGES_MADE" <<'PY' +DETAIL=SOURCE_LINE=0334:import json +DETAIL=SOURCE_LINE=0335:import sys +DETAIL=SOURCE_LINE=0336:from pathlib import Path +DETAIL=SOURCE_LINE=0337: +DETAIL=SOURCE_LINE=0338:( +DETAIL=SOURCE_LINE=0339: json_path, +DETAIL=SOURCE_LINE=0340: output_path, +DETAIL=SOURCE_LINE=0341: command_id, +DETAIL=SOURCE_LINE=0342: status, +DETAIL=SOURCE_LINE=0343: rc, +DETAIL=SOURCE_LINE=0344: host, +DETAIL=SOURCE_LINE=0345: mode, +DETAIL=SOURCE_LINE=0346: component, +DETAIL=SOURCE_LINE=0347: started, +DETAIL=SOURCE_LINE=0348: finished, +DETAIL=SOURCE_LINE=0349: reference_sha, +DETAIL=SOURCE_LINE=0350: error_sha, +DETAIL=SOURCE_LINE=0351: command_sha, +DETAIL=SOURCE_LINE=0352: raw_sha, +DETAIL=SOURCE_LINE=0353: sanitized_sha, +DETAIL=SOURCE_LINE=0354: run_started, +DETAIL=SOURCE_LINE=0355: repeat_blocked, +DETAIL=SOURCE_LINE=... +DETAIL=SOURCE_LINE=0416: ) +DETAIL=SOURCE_LINE=0417: + "\n", +DETAIL=SOURCE_LINE=0418: encoding="utf-8", +DETAIL=SOURCE_LINE=0419:) +DETAIL=SOURCE_LINE=0420:PY +DETAIL=SOURCE_LINE=0421: +DETAIL=SOURCE_LINE=0422:{ +DETAIL=SOURCE_LINE=0423: echo 'CHAT_OUTPUT_BEGIN' +DETAIL=SOURCE_LINE=0424: echo "COMMAND_ID=$COMMAND_ID" +DETAIL=SOURCE_LINE=0425: echo "STATUS=$STATUS" +DETAIL=SOURCE_LINE=0426: echo "RC=$RC" +DETAIL=SOURCE_LINE=0427: echo "HOST=$HOST_SHORT" +DETAIL=SOURCE_LINE=0428: echo "MODE=$MODE" +DETAIL=SOURCE_LINE=0429: echo "COMPONENT=$COMPONENT" +DETAIL=SOURCE_LINE=0430: echo 'REFERENCE_REGISTER_CHECK=OK' +DETAIL=SOURCE_LINE=0431: echo "REFERENCE_SHA256=$REFERENCE_SHA256" +DETAIL=SOURCE_LINE=0432: echo 'ERROR_REGISTER_CHECK=OK' +DETAIL=SOURCE_LINE=0433: echo "ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256" +DETAIL=SOURCE_LINE=0434: echo "COMMAND_SHA256=$COMMAND_SHA256" +DETAIL=SOURCE_LINE=0435: echo "DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED" +DETAIL=SOURCE_LINE=0436: echo "EXECUTION_STARTED=$RUN_STARTED" +DETAIL=SOURCE_LINE=0437: echo "CHANGES_MADE=$CHANGES_MADE" +DETAIL=SOURCE_LINE=0438: echo 'SANITIZED=yes' +DETAIL=SOURCE_LINE=0439: echo 'SECRETS_INCLUDED=no' +DETAIL=SOURCE_LINE=0440: echo 'PRIVATE_ADDRESSES_INCLUDED=no' +DETAIL=SOURCE_LINE=0441: echo "RAW_EVIDENCE_SHA256=$RAW_SHA256" +DETAIL=SOURCE_LINE=0442: echo "SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256" +DETAIL=SOURCE_LINE=0443: echo 'OUTPUT_BEGIN' +DETAIL=SOURCE_LINE=0444: cat "$SANITIZED_FILE" +DETAIL=SOURCE_LINE=0445: echo +DETAIL=SOURCE_LINE=0446: echo 'OUTPUT_END' +DETAIL=SOURCE_LINE=0447: echo 'CHAT_OUTPUT_END' +DETAIL=SOURCE_LINE=0448:} >"$TXT_FILE" +DETAIL=SOURCE_LINE=0449: +DETAIL=SOURCE_LINE=0450:chmod 0600 \ +DETAIL=SOURCE_LINE=0451: "$RAW_FILE" \ +DETAIL=SOURCE_LINE=0452: "$SANITIZED_FILE" \ +DETAIL=SOURCE_LINE=0453: "$JSON_FILE" \ +DETAIL=SOURCE_LINE=0454: "$TXT_FILE" +DETAIL=SOURCE_LINE=0455: +DETAIL=SOURCE_LINE=0456:TARGET=debian@[PRIVATE_IP] +DETAIL=SOURCE_LINE=0457:REMOTE_PREFIX="/tmp/homelab-runtime-${COMMAND_ID}-$$" +DETAIL=SOURCE_LINE=0458: +DETAIL=SOURCE_LINE=0459:SSH_OPTS=( +DETAIL=SOURCE_LINE=... +DETAIL=SOURCE_LINE=0509: PUBLIC_VISIBLE=true +DETAIL=SOURCE_LINE=0510: break +DETAIL=SOURCE_LINE=0511: fi +DETAIL=SOURCE_LINE=0512: +DETAIL=SOURCE_LINE=0513: sleep 2 +DETAIL=SOURCE_LINE=0514:done +DETAIL=SOURCE_LINE=0515: +DETAIL=SOURCE_LINE=0516:if [ "$PUBLIC_VISIBLE" != true ]; then +DETAIL=SOURCE_LINE=0517: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0518: echo 'REASON=PUBLIC_RUNTIME_RESULT_NOT_VISIBLE' +DETAIL=SOURCE_LINE=0519: echo "COMMAND_ID=$COMMAND_ID" +DETAIL=SOURCE_LINE=0520: echo "LOCAL_RAW_FILE=$RAW_FILE" +DETAIL=SOURCE_LINE=0521: exit 75 +DETAIL=SOURCE_LINE=0522:fi +DETAIL=SOURCE_LINE=0523: +DETAIL=SOURCE_LINE=0524:printf '%s\t%s\t%s\t%s\t%s\t%s\n' \ +DETAIL=SOURCE_LINE=0525: "$FINISHED_AT" \ +DETAIL=SOURCE_LINE=0526: "$COMMAND_ID" \ +DETAIL=SOURCE_LINE=0527: "$COMMAND_SHA256" \ +DETAIL=SOURCE_LINE=0528: "$RC" \ +DETAIL=SOURCE_LINE=0529: "$STATUS" \ +DETAIL=SOURCE_LINE=0530: "$COMPONENT" >>"$LEDGER" +DETAIL=SOURCE_LINE=0531: +DETAIL=SOURCE_LINE=0532:echo +DETAIL=SOURCE_LINE=0533:echo '===== HOMELAB CHAT RUN COMPLETE =====' +DETAIL=SOURCE_LINE=0534:echo "COMMAND_ID=$COMMAND_ID" +DETAIL=SOURCE_LINE=0535:echo "STATUS=$STATUS" +DETAIL=SOURCE_LINE=0536:echo "RC=$RC" +DETAIL=SOURCE_LINE=0537:echo 'REFERENCE_REGISTER_CHECK=OK' +DETAIL=SOURCE_LINE=0538:echo 'ERROR_REGISTER_CHECK=OK' +DETAIL=SOURCE_LINE=0539:echo "DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED" +DETAIL=SOURCE_LINE=0540:echo 'GITEA_PUBLICATION=OK' +DETAIL=SOURCE_LINE=0541:echo "PUBLIC_URL=$PUBLIC_URL" +DETAIL=SOURCE_LINE=0542:echo "LOCAL_RAW_FILE=$RAW_FILE" +DETAIL=SOURCE_LINE=0543:echo 'SHELL_SESSION_PRESERVED=yes' +DETAIL=SOURCE_LINE=0544: +DETAIL=SOURCE_LINE=0545:exit "$RC" +DETAIL=TOTAL_LINES=545 +DETAIL=EXACT_LOGIC_END +DETAIL=DUPLICATE_EXACT_LOGIC_AUDIT=PASS +DETAIL=SECRET_VALUES_OUTPUT=NONE +CHANGES_MADE=NO + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index e75259e..c25e287 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,19 +1,19 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "HOMELAB-DUPLICATE-FINGERPRINT-AUDIT-426", + "command_id": "HOMELAB-DUPLICATE-EXACT-LOGIC-427", "status": "OK", "rc": 0, "host": "pve01", "mode": "read-only", "component": "cluster-audit", - "started_at_utc": "2026-07-24T09:36:35Z", - "finished_at_utc": "2026-07-24T09:36:35Z", + "started_at_utc": "2026-07-24T09:37:54Z", + "finished_at_utc": "2026-07-24T09:37:54Z", "reference_register_checked": true, "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", "error_register_checked": true, "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752", - "command_sha256": "d95e5a9d8480b33605c127ce6ebdc688d05087f3c0afbdda7c3af1a5129a3d3c", + "command_sha256": "7e4f72d9877110d6d6d4ef926a611b1bd8ad15fa4b2ad3ef17e9027ba49bc111", "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": "db73d9a0e67a6c8cdbb9fcb6ae3ee47c92879dc079fe115a8412abd39ef39ca4", - "sanitized_output_sha256": "b1ad62957baf7f8680f85ae10f1db94077a48c98e438dda3987b551f7a15cb13", + "raw_evidence_sha256": "8480bb49baedd9fdebe212ee204d07d772e707d3c09045de0c3334fde723f6e9", + "sanitized_output_sha256": "5e8f3e2de086ae3c1d1bf84dcffbcb8dc8770ebefb00aa959db1ff15db3468b9", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "DETAIL=FILE=/usr/local/sbin/homelab-chat-run-linked\nDETAIL=SHA256=5e8725e129fd2055b36fe2fae13fc95fc4b3271074a0e0d4bb7347e7b2f270a1\nDETAIL=FILE=/usr/local/sbin/homelab-chat-run\nDETAIL=SHA256=2a88defef9517f89bc60934dce82097f8e316b08af9417e95167ea5d759a10d9\nDETAIL=SOURCE=51- read-only|verify|change|transport-test)\nDETAIL=SOURCE=52- ;;\nDETAIL=SOURCE=53- *)\nDETAIL=SOURCE=54- echo 'RESULT=FAIL'\nDETAIL=SOURCE=55- echo 'REASON=INVALID_MODE'\nDETAIL=SOURCE=56- exit 67\nDETAIL=SOURCE=57- ;;\nDETAIL=SOURCE=58-esac\nDETAIL=SOURCE=59-\nDETAIL=SOURCE=60-for TOOL in \\\nDETAIL=SOURCE=61- awk \\\nDETAIL=SOURCE=62- curl \\\nDETAIL=SOURCE=63- flock \\\nDETAIL=SOURCE=64- python3 \\\nDETAIL=SOURCE=65- scp \\\nDETAIL=SOURCE=66: sha256sum \\\nDETAIL=SOURCE=67- ssh\nDETAIL=SOURCE=68-do\nDETAIL=SOURCE=69- command -v \"$TOOL\" >/dev/null 2>&1 || {\nDETAIL=SOURCE=70- echo 'RESULT=FAIL'\nDETAIL=SOURCE=71- echo \"REASON=REQUIRED_TOOL_MISSING:$TOOL\"\nDETAIL=SOURCE=72- exit 68\nDETAIL=SOURCE=73- }\nDETAIL=SOURCE=74-done\nDETAIL=SOURCE=75-\nDETAIL=SOURCE=76-REFERENCE=/etc/pve/31_HOMELAB_REFERENCE.md\nDETAIL=SOURCE=77-ERROR_REGISTER=/etc/pve/HOMELAB_ASSISTANT_ERROR_REGISTER.md\nDETAIL=SOURCE=78-\nDETAIL=SOURCE=79-[ -r \"$REFERENCE\" ] || {\nDETAIL=SOURCE=80- echo 'RESULT=FAIL'\nDETAIL=SOURCE=81- echo 'REASON=REFERENCE_NOT_READABLE'\nDETAIL=SOURCE=82- exit 69\nDETAIL=SOURCE=83-}\nDETAIL=SOURCE=84-\nDETAIL=SOURCE=85-[ -r \"$ERROR_REGISTER\" ] || {\nDETAIL=SOURCE=86- echo 'RESULT=FAIL'\nDETAIL=SOURCE=87- echo 'REASON=ERROR_REGISTER_NOT_READABLE'\nDETAIL=SOURCE=88- exit 70\nDETAIL=SOURCE=89-}\nDETAIL=SOURCE=90-\nDETAIL=SOURCE=91-STATE_DIR=/var/lib/homelab-chat-run\nDETAIL=SOURCE=92-RAW_DIR=\"$STATE_DIR/raw\"\nDETAIL=SOURCE=93-PUBLIC_DIR=\"$STATE_DIR/public\"\nDETAIL=SOURCE=94-LEDGER=\"$STATE_DIR/state/command-ledger.tsv\"\nDETAIL=SOURCE=95-LOCK=\"$STATE_DIR/state/runner.lock\"\nDETAIL=SOURCE=96-\nDETAIL=SOURCE=--\nDETAIL=SOURCE=104-flock -w 60 9 || {\nDETAIL=SOURCE=105- echo 'RESULT=FAIL'\nDETAIL=SOURCE=106- echo 'REASON=RUNNER_LOCK_TIMEOUT'\nDETAIL=SOURCE=107- exit 71\nDETAIL=SOURCE=108-}\nDETAIL=SOURCE=109-\nDETAIL=SOURCE=110-STARTED_AT=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\nDETAIL=SOURCE=111-STAMP=\"$(date -u +%Y%m%dT%H%M%SZ)\"\nDETAIL=SOURCE=112-HOST_SHORT=\"$(hostname -s 2>/dev/null || hostname)\"\nDETAIL=SOURCE=113-\nDETAIL=SOURCE=114-RAW_FILE=\"$RAW_DIR/${COMMAND_ID}-${STAMP}.log\"\nDETAIL=SOURCE=115-SANITIZED_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.txt\"\nDETAIL=SOURCE=116-JSON_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.json\"\nDETAIL=SOURCE=117-TXT_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}-latest.txt\"\nDETAIL=SOURCE=118-\nDETAIL=SOURCE=119:REFERENCE_SHA256=\"$(sha256sum \"$REFERENCE\" | awk '{print $1}')\"\nDETAIL=SOURCE=120:ERROR_REGISTER_SHA256=\"$(sha256sum \"$ERROR_REGISTER\" | awk '{print $1}')\"\nDETAIL=SOURCE=121-\nDETAIL=SOURCE=122:COMMAND_SHA256=\"$(\nDETAIL=SOURCE=123- {\nDETAIL=SOURCE=124- printf '%s\\0' \"$MODE\"\nDETAIL=SOURCE=125- printf '%s\\0' \"$COMPONENT\"\nDETAIL=SOURCE=126- printf '%s\\0' \"$@\"\nDETAIL=SOURCE=127- } |\nDETAIL=SOURCE=128: sha256sum |\nDETAIL=SOURCE=129- awk '{print $1}'\nDETAIL=SOURCE=130-)\"\nDETAIL=SOURCE=131-\nDETAIL=SOURCE=132-PREVIOUS_FAILED_RC=\"$(\nDETAIL=SOURCE=133: awk -F '\\t' -v hash=\"$COMMAND_SHA256\" '\nDETAIL=SOURCE=134- $3 == hash && $4 != \"0\" {\nDETAIL=SOURCE=135- value=$4\nDETAIL=SOURCE=136- }\nDETAIL=SOURCE=137-\nDETAIL=SOURCE=138- END {\nDETAIL=SOURCE=139- print value\nDETAIL=SOURCE=140- }\nDETAIL=SOURCE=141- ' \"$LEDGER\"\nDETAIL=SOURCE=142-)\"\nDETAIL=SOURCE=143-\nDETAIL=SOURCE=144-RUN_STARTED=true\nDETAIL=SOURCE=145-REPEAT_BLOCKED=false\nDETAIL=SOURCE=146-BLOCK_REASON=''\nDETAIL=SOURCE=147-CHANGES_MADE=false\nDETAIL=SOURCE=148-\nDETAIL=SOURCE=149-case \"$MODE\" in\nDETAIL=SOURCE=150- change)\nDETAIL=SOURCE=151- CHANGES_MADE=true\nDETAIL=SOURCE=152- ;;\nDETAIL=SOURCE=153-esac\nDETAIL=SOURCE=154-\nDETAIL=SOURCE=155-if [ -n \"$PREVIOUS_FAILED_RC\" ] &&\nDETAIL=SOURCE=156- [ \"${HOMELAB_ALLOW_REPEAT:-0}\" != 1 ]; then\nDETAIL=SOURCE=157-\nDETAIL=SOURCE=158- RUN_STARTED=false\nDETAIL=SOURCE=159- REPEAT_BLOCKED=true\nDETAIL=SOURCE=160: BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT'\nDETAIL=SOURCE=161- RC=73\nDETAIL=SOURCE=162- STATUS='BLOCKED'\nDETAIL=SOURCE=163-\nDETAIL=SOURCE=164- {\nDETAIL=SOURCE=165- echo 'COMMAND_EXECUTION_BLOCKED=yes'\nDETAIL=SOURCE=166: echo 'REASON=EXACT_FAILED_COMMAND_REPEAT'\nDETAIL=SOURCE=167- echo \"PREVIOUS_RC=$PREVIOUS_FAILED_RC\"\nDETAIL=SOURCE=168: echo \"COMMAND_SHA256=$COMMAND_SHA256\"\nDETAIL=SOURCE=169- echo\nDETAIL=SOURCE=170- echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.'\nDETAIL=SOURCE=171- } >\"$RAW_FILE\"\nDETAIL=SOURCE=172-else\nDETAIL=SOURCE=173- set +e\nDETAIL=SOURCE=174-\nDETAIL=SOURCE=175- if [ -n \"${HOMELAB_TIMEOUT:-}\" ]; then\nDETAIL=SOURCE=176- case \"$HOMELAB_TIMEOUT\" in\nDETAIL=SOURCE=177- *[!0-9]*|'')\nDETAIL=SOURCE=178- echo 'RESULT=FAIL'\nDETAIL=SOURCE=179- echo 'REASON=INVALID_HOMELAB_TIMEOUT'\nDETAIL=SOURCE=180- exit 74\nDETAIL=SOURCE=181- ;;\nDETAIL=SOURCE=182- esac\nDETAIL=SOURCE=183-\nDETAIL=SOURCE=184- timeout \\\nDETAIL=SOURCE=185- --foreground \\\nDETAIL=SOURCE=186- --preserve-status \\\nDETAIL=SOURCE=187- \"$HOMELAB_TIMEOUT\" \\\nDETAIL=SOURCE=188- \"$@\" >\"$RAW_FILE\" 2>&1\nDETAIL=SOURCE=189- RC=$?\nDETAIL=SOURCE=190- else\nDETAIL=SOURCE=191- \"$@\" >\"$RAW_FILE\" 2>&1\nDETAIL=SOURCE=192- RC=$?\nDETAIL=SOURCE=193- fi\nDETAIL=SOURCE=194-\nDETAIL=SOURCE=195- set -e\nDETAIL=SOURCE=196-\nDETAIL=SOURCE=197- if [ \"$RC\" -eq 0 ]; then\nDETAIL=SOURCE=198- STATUS='OK'\nDETAIL=SOURCE=199- else\nDETAIL=SOURCE=200- STATUS='FAIL'\nDETAIL=SOURCE=201- fi\nDETAIL=SOURCE=202-fi\nDETAIL=SOURCE=203-\nDETAIL=SOURCE=204-FINISHED_AT=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\nDETAIL=SOURCE=205:RAW_SHA256=\"$(sha256sum \"$RAW_FILE\" | awk '{print $1}')\"\nDETAIL=SOURCE=206-\nDETAIL=SOURCE=207-python3 - \"$RAW_FILE\" \"$SANITIZED_FILE\" <<'PY'\nDETAIL=SOURCE=208-import re\nDETAIL=SOURCE=209-import sys\nDETAIL=SOURCE=210-from pathlib import Path\nDETAIL=SOURCE=211-\nDETAIL=SOURCE=212:source = Path(sys.argv[1])\nDETAIL=SOURCE=213:target = Path(sys.argv[2])\nDETAIL=SOURCE=214-\nDETAIL=SOURCE=215-text = source.read_bytes().decode(\"utf-8\", errors=\"replace\")\nDETAIL=SOURCE=216-\nDETAIL=SOURCE=217-patterns = [\nDETAIL=SOURCE=218- (\nDETAIL=SOURCE=219- re.compile(\nDETAIL=SOURCE=220- r\"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\"\nDETAIL=SOURCE=221- r\".*?\"\nDETAIL=SOURCE=222- r\"-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\",\nDETAIL=SOURCE=223- re.IGNORECASE | re.DOTALL,\nDETAIL=SOURCE=224- ),\nDETAIL=SOURCE=225- \"[PRIVATE_KEY_REDACTED]\",\nDETAIL=SOURCE=226- ),\nDETAIL=SOURCE=227- (\nDETAIL=SOURCE=228- re.compile(\nDETAIL=SOURCE=229- r\"(?im)^(\\s*(?:password|passwd|passphrase|authorization|\"\nDETAIL=SOURCE=230- r\"api[_-]?key|access[_-]?token|refresh[_-]?token|\"\nDETAIL=SOURCE=231- r\"private[_-]?key|secret)\\s*[:=]\\s*).*$\"\nDETAIL=SOURCE=232- ),\nDETAIL=SOURCE=233- r\"\\1[REDACTED]\",\nDETAIL=SOURCE=234- ),\nDETAIL=SOURCE=235- (\nDETAIL=SOURCE=236- re.compile(r\"(?i)(Bearer\\s+)[A-Za-z0-9._~+/=-]+\"),\nDETAIL=SOURCE=237- r\"\\1[REDACTED]\",\nDETAIL=SOURCE=238- ),\nDETAIL=SOURCE=239- (\nDETAIL=SOURCE=240- re.compile(r\"\\b10(?:\\.\\d{1,3}){3}\\b\"),\nDETAIL=SOURCE=241- \"[PRIVATE_IP]\",\nDETAIL=SOURCE=242- ),\nDETAIL=SOURCE=243- (\nDETAIL=SOURCE=--\nDETAIL=SOURCE=294-if len(encoded) > maximum:\nDETAIL=SOURCE=295- first = encoded[:440_000].decode(\"utf-8\", errors=\"ignore\")\nDETAIL=SOURCE=296- last = encoded[-440_000:].decode(\"utf-8\", errors=\"ignore\")\nDETAIL=SOURCE=297-\nDETAIL=SOURCE=298- text = (\nDETAIL=SOURCE=299- first\nDETAIL=SOURCE=300- + \"\\n\\n\"\nDETAIL=SOURCE=301- + \"===== PUBLIC OUTPUT TRUNCATED; FULL RAW LOG RETAINED LOCALLY =====\"\nDETAIL=SOURCE=302- + \"\\n\\n\"\nDETAIL=SOURCE=303- + last\nDETAIL=SOURCE=304- )\nDETAIL=SOURCE=305-\nDETAIL=SOURCE=306-target.write_text(text, encoding=\"utf-8\")\nDETAIL=SOURCE=307-PY\nDETAIL=SOURCE=308-\nDETAIL=SOURCE=309:SANITIZED_SHA256=\"$(\nDETAIL=SOURCE=310: sha256sum \"$SANITIZED_FILE\" |\nDETAIL=SOURCE=311- awk '{print $1}'\nDETAIL=SOURCE=312-)\"\nDETAIL=SOURCE=313-\nDETAIL=SOURCE=314-python3 - \\\nDETAIL=SOURCE=315- \"$JSON_FILE\" \\\nDETAIL=SOURCE=316- \"$SANITIZED_FILE\" \\\nDETAIL=SOURCE=317- \"$COMMAND_ID\" \\\nDETAIL=SOURCE=318- \"$STATUS\" \\\nDETAIL=SOURCE=319- \"$RC\" \\\nDETAIL=SOURCE=320- \"$HOST_SHORT\" \\\nDETAIL=SOURCE=321- \"$MODE\" \\\nDETAIL=SOURCE=322- \"$COMPONENT\" \\\nDETAIL=SOURCE=323- \"$STARTED_AT\" \\\nDETAIL=SOURCE=324- \"$FINISHED_AT\" \\\nDETAIL=SOURCE=325: \"$REFERENCE_SHA256\" \\\nDETAIL=SOURCE=326: \"$ERROR_REGISTER_SHA256\" \\\nDETAIL=SOURCE=327: \"$COMMAND_SHA256\" \\\nDETAIL=SOURCE=328: \"$RAW_SHA256\" \\\nDETAIL=SOURCE=329: \"$SANITIZED_SHA256\" \\\nDETAIL=SOURCE=330- \"$RUN_STARTED\" \\\nDETAIL=SOURCE=331- \"$REPEAT_BLOCKED\" \\\nDETAIL=SOURCE=332- \"$BLOCK_REASON\" \\\nDETAIL=SOURCE=333- \"$CHANGES_MADE\" <<'PY'\nDETAIL=SOURCE=334-import json\nDETAIL=SOURCE=335-import sys\nDETAIL=SOURCE=336-from pathlib import Path\nDETAIL=SOURCE=337-\nDETAIL=SOURCE=338-(\nDETAIL=SOURCE=339- json_path,\nDETAIL=SOURCE=340- output_path,\nDETAIL=SOURCE=341- command_id,\nDETAIL=SOURCE=342- status,\nDETAIL=SOURCE=343- rc,\nDETAIL=SOURCE=344- host,\nDETAIL=SOURCE=345- mode,\nDETAIL=SOURCE=346- component,\nDETAIL=SOURCE=347- started,\nDETAIL=SOURCE=348- finished,\nDETAIL=SOURCE=349- reference_sha,\nDETAIL=SOURCE=350- error_sha,\nDETAIL=SOURCE=351- command_sha,\nDETAIL=SOURCE=352- raw_sha,\nDETAIL=SOURCE=353- sanitized_sha,\nDETAIL=SOURCE=354- run_started,\nDETAIL=SOURCE=355- repeat_blocked,\nDETAIL=SOURCE=356- block_reason,\nDETAIL=SOURCE=357- changes_made,\nDETAIL=SOURCE=358:) = sys.argv[1:]\nDETAIL=SOURCE=359-\nDETAIL=SOURCE=360-output = Path(output_path).read_text(\nDETAIL=SOURCE=361- encoding=\"utf-8\",\nDETAIL=SOURCE=362- errors=\"replace\",\nDETAIL=SOURCE=363-)\nDETAIL=SOURCE=364-\nDETAIL=SOURCE=365-encoded = output.encode(\"utf-8\")\nDETAIL=SOURCE=366-json_limit = 300_000\nDETAIL=SOURCE=367-output_truncated = len(encoded) > json_limit\nDETAIL=SOURCE=368-\nDETAIL=SOURCE=369-if output_truncated:\nDETAIL=SOURCE=370- output_preview = encoded[:json_limit].decode(\nDETAIL=SOURCE=371- \"utf-8\",\nDETAIL=SOURCE=372- errors=\"ignore\",\nDETAIL=SOURCE=373- )\nDETAIL=SOURCE=374-else:\nDETAIL=SOURCE=375- output_preview = output\nDETAIL=SOURCE=376-\nDETAIL=SOURCE=377-document = {\nDETAIL=SOURCE=378- \"schema_version\": 1,\nDETAIL=SOURCE=379- \"channel\": \"homelab-runtime\",\nDETAIL=SOURCE=380- \"command_id\": command_id,\nDETAIL=SOURCE=381- \"status\": status,\nDETAIL=SOURCE=382- \"rc\": int(rc),\nDETAIL=SOURCE=383- \"host\": host,\nDETAIL=SOURCE=384- \"mode\": mode,\nDETAIL=SOURCE=385- \"component\": component,\nDETAIL=SOURCE=386- \"started_at_utc\": started,\nDETAIL=SOURCE=387- \"finished_at_utc\": finished,\nDETAIL=SOURCE=388- \"reference_register_checked\": True,\nDETAIL=SOURCE=389: \"reference_sha256\": reference_sha,\nDETAIL=SOURCE=390- \"error_register_checked\": True,\nDETAIL=SOURCE=391: \"error_register_sha256\": error_sha,\nDETAIL=SOURCE=392: \"command_sha256\": command_sha,\nDETAIL=SOURCE=393: \"duplicate_failed_command_blocked\": repeat_blocked == \"true\",\nDETAIL=SOURCE=394- \"block_reason\": block_reason or None,\nDETAIL=SOURCE=395- \"execution_started\": run_started == \"true\",\nDETAIL=SOURCE=396- \"changes_made\": changes_made == \"true\",\nDETAIL=SOURCE=397- \"sanitized\": True,\nDETAIL=SOURCE=398- \"secrets_included\": False,\nDETAIL=SOURCE=399- \"private_addresses_included\": False,\nDETAIL=SOURCE=400- \"raw_evidence_retained_locally\": True,\nDETAIL=SOURCE=401: \"raw_evidence_sha256\": raw_sha,\nDETAIL=SOURCE=402: \"sanitized_output_sha256\": sanitized_sha,\nDETAIL=SOURCE=403- \"output_truncated_in_json\": output_truncated,\nDETAIL=SOURCE=404- \"full_sanitized_output_url\": (\nDETAIL=SOURCE=405- \"https://git.gram1.ru/.well-known/\"\nDETAIL=SOURCE=406- \"homelab-runtime/latest.txt\"\nDETAIL=SOURCE=407- ),\nDETAIL=SOURCE=408- \"output\": output_preview,\nDETAIL=SOURCE=409-}\nDETAIL=SOURCE=410-\nDETAIL=SOURCE=411-Path(json_path).write_text(\nDETAIL=SOURCE=412- json.dumps(\nDETAIL=SOURCE=413- document,\nDETAIL=SOURCE=414- ensure_ascii=False,\nDETAIL=SOURCE=415- indent=2,\nDETAIL=SOURCE=416- )\nDETAIL=SOURCE=417- + \"\\n\",\nDETAIL=SOURCE=418- encoding=\"utf-8\",\nDETAIL=SOURCE=419-)\nDETAIL=SOURCE=420-PY\nDETAIL=SOURCE=421-\nDETAIL=SOURCE=422-{\nDETAIL=SOURCE=423- echo 'CHAT_OUTPUT_BEGIN'\nDETAIL=SOURCE=424- echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE=425- echo \"STATUS=$STATUS\"\nDETAIL=SOURCE=426- echo \"RC=$RC\"\nDETAIL=SOURCE=427- echo \"HOST=$HOST_SHORT\"\nDETAIL=SOURCE=428- echo \"MODE=$MODE\"\nDETAIL=SOURCE=429- echo \"COMPONENT=$COMPONENT\"\nDETAIL=SOURCE=430- echo 'REFERENCE_REGISTER_CHECK=OK'\nDETAIL=SOURCE=431: echo \"REFERENCE_SHA256=$REFERENCE_SHA256\"\nDETAIL=SOURCE=432- echo 'ERROR_REGISTER_CHECK=OK'\nDETAIL=SOURCE=433: echo \"ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256\"\nDETAIL=SOURCE=434: echo \"COMMAND_SHA256=$COMMAND_SHA256\"\nDETAIL=SOURCE=435: echo \"DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED\"\nDETAIL=SOURCE=436- echo \"EXECUTION_STARTED=$RUN_STARTED\"\nDETAIL=SOURCE=437- echo \"CHANGES_MADE=$CHANGES_MADE\"\nDETAIL=SOURCE=438- echo 'SANITIZED=yes'\nDETAIL=SOURCE=439- echo 'SECRETS_INCLUDED=no'\nDETAIL=SOURCE=440- echo 'PRIVATE_ADDRESSES_INCLUDED=no'\nDETAIL=SOURCE=441: echo \"RAW_EVIDENCE_SHA256=$RAW_SHA256\"\nDETAIL=SOURCE=442: echo \"SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256\"\nDETAIL=SOURCE=443- echo 'OUTPUT_BEGIN'\nDETAIL=SOURCE=444- cat \"$SANITIZED_FILE\"\nDETAIL=SOURCE=445- echo\nDETAIL=SOURCE=446- echo 'OUTPUT_END'\nDETAIL=SOURCE=447- echo 'CHAT_OUTPUT_END'\nDETAIL=SOURCE=448-} >\"$TXT_FILE\"\nDETAIL=SOURCE=449-\nDETAIL=SOURCE=450-chmod 0600 \\\nDETAIL=SOURCE=451- \"$RAW_FILE\" \\\nDETAIL=SOURCE=452- \"$SANITIZED_FILE\" \\\nDETAIL=SOURCE=453- \"$JSON_FILE\" \\\nDETAIL=SOURCE=454- \"$TXT_FILE\"\nDETAIL=SOURCE=455-\nDETAIL=SOURCE=456-TARGET=debian@[PRIVATE_IP]\nDETAIL=SOURCE=457-REMOTE_PREFIX=\"/tmp/homelab-runtime-${COMMAND_ID}-$$\"\nDETAIL=SOURCE=458-\nDETAIL=SOURCE=459-SSH_OPTS=(\nDETAIL=SOURCE=460- -o BatchMode=yes\nDETAIL=SOURCE=461- -o ConnectTimeout=10\nDETAIL=SOURCE=462- -o ConnectionAttempts=1\nDETAIL=SOURCE=463- -o StrictHostKeyChecking=yes\nDETAIL=SOURCE=464- -o UserKnownHostsFile=[SENSITIVE_PATH]\nDETAIL=SOURCE=465-)\nDETAIL=SOURCE=466-\nDETAIL=SOURCE=467-scp \\\nDETAIL=SOURCE=468- -q \\\nDETAIL=SOURCE=469- \"${SSH_OPTS[@]}\" \\\nDETAIL=SOURCE=470- \"$JSON_FILE\" \\\nDETAIL=SOURCE=471- \"${TARGET}:${REMOTE_PREFIX}.json\"\nDETAIL=SOURCE=472-\nDETAIL=SOURCE=--\nDETAIL=SOURCE=512-\nDETAIL=SOURCE=513- sleep 2\nDETAIL=SOURCE=514-done\nDETAIL=SOURCE=515-\nDETAIL=SOURCE=516-if [ \"$PUBLIC_VISIBLE\" != true ]; then\nDETAIL=SOURCE=517- echo 'RESULT=FAIL'\nDETAIL=SOURCE=518- echo 'REASON=PUBLIC_RUNTIME_RESULT_NOT_VISIBLE'\nDETAIL=SOURCE=519- echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE=520- echo \"LOCAL_RAW_FILE=$RAW_FILE\"\nDETAIL=SOURCE=521- exit 75\nDETAIL=SOURCE=522-fi\nDETAIL=SOURCE=523-\nDETAIL=SOURCE=524-printf '%s\\t%s\\t%s\\t%s\\t%s\\t%s\\n' \\\nDETAIL=SOURCE=525- \"$FINISHED_AT\" \\\nDETAIL=SOURCE=526- \"$COMMAND_ID\" \\\nDETAIL=SOURCE=527: \"$COMMAND_SHA256\" \\\nDETAIL=SOURCE=528- \"$RC\" \\\nDETAIL=SOURCE=529- \"$STATUS\" \\\nDETAIL=SOURCE=530- \"$COMPONENT\" >>\"$LEDGER\"\nDETAIL=SOURCE=531-\nDETAIL=SOURCE=532-echo\nDETAIL=SOURCE=533-echo '===== HOMELAB CHAT RUN COMPLETE ====='\nDETAIL=SOURCE=534-echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE=535-echo \"STATUS=$STATUS\"\nDETAIL=SOURCE=536-echo \"RC=$RC\"\nDETAIL=SOURCE=537-echo 'REFERENCE_REGISTER_CHECK=OK'\nDETAIL=SOURCE=538-echo 'ERROR_REGISTER_CHECK=OK'\nDETAIL=SOURCE=539:echo \"DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED\"\nDETAIL=SOURCE=540-echo 'GITEA_PUBLICATION=OK'\nDETAIL=SOURCE=541-echo \"PUBLIC_URL=$PUBLIC_URL\"\nDETAIL=SOURCE=542-echo \"LOCAL_RAW_FILE=$RAW_FILE\"\nDETAIL=SOURCE=543-echo 'SHELL_SESSION_PRESERVED=yes'\nDETAIL=SOURCE=544-\nDETAIL=SOURCE=545-exit \"$RC\"\nDETAIL=DUPLICATE_FINGERPRINT_AUDIT=PASS\nDETAIL=SECRET_VALUES_OUTPUT=NONE\nCHANGES_MADE=NO\n" + "output": "DETAIL=FILE=/usr/local/sbin/homelab-chat-run-linked\nDETAIL=SHA256=5e8725e129fd2055b36fe2fae13fc95fc4b3271074a0e0d4bb7347e7b2f270a1\nDETAIL=EXACT_LOGIC_BEGIN\nDETAIL=TOTAL_LINES=39\nDETAIL=EXACT_LOGIC_END\nDETAIL=FILE=/usr/local/sbin/homelab-chat-run\nDETAIL=SHA256=2a88defef9517f89bc60934dce82097f8e316b08af9417e95167ea5d759a10d9\nDETAIL=EXACT_LOGIC_BEGIN\nDETAIL=SOURCE_LINE=0048:esac\nDETAIL=SOURCE_LINE=0049:\nDETAIL=SOURCE_LINE=0050:case \"$MODE\" in\nDETAIL=SOURCE_LINE=0051: read-only|verify|change|transport-test)\nDETAIL=SOURCE_LINE=0052: ;;\nDETAIL=SOURCE_LINE=0053: *)\nDETAIL=SOURCE_LINE=0054: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0055: echo 'REASON=INVALID_MODE'\nDETAIL=SOURCE_LINE=0056: exit 67\nDETAIL=SOURCE_LINE=0057: ;;\nDETAIL=SOURCE_LINE=0058:esac\nDETAIL=SOURCE_LINE=0059:\nDETAIL=SOURCE_LINE=0060:for TOOL in \\\nDETAIL=SOURCE_LINE=0061: awk \\\nDETAIL=SOURCE_LINE=0062: curl \\\nDETAIL=SOURCE_LINE=0063: flock \\\nDETAIL=SOURCE_LINE=0064: python3 \\\nDETAIL=SOURCE_LINE=0065: scp \\\nDETAIL=SOURCE_LINE=0066: sha256sum \\\nDETAIL=SOURCE_LINE=0067: ssh\nDETAIL=SOURCE_LINE=0068:do\nDETAIL=SOURCE_LINE=0069: command -v \"$TOOL\" >/dev/null 2>&1 || {\nDETAIL=SOURCE_LINE=0070: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0071: echo \"REASON=REQUIRED_TOOL_MISSING:$TOOL\"\nDETAIL=SOURCE_LINE=0072: exit 68\nDETAIL=SOURCE_LINE=0073: }\nDETAIL=SOURCE_LINE=0074:done\nDETAIL=SOURCE_LINE=0075:\nDETAIL=SOURCE_LINE=0076:REFERENCE=/etc/pve/31_HOMELAB_REFERENCE.md\nDETAIL=SOURCE_LINE=0077:ERROR_REGISTER=/etc/pve/HOMELAB_ASSISTANT_ERROR_REGISTER.md\nDETAIL=SOURCE_LINE=0078:\nDETAIL=SOURCE_LINE=0079:[ -r \"$REFERENCE\" ] || {\nDETAIL=SOURCE_LINE=0080: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0081: echo 'REASON=REFERENCE_NOT_READABLE'\nDETAIL=SOURCE_LINE=0082: exit 69\nDETAIL=SOURCE_LINE=0083:}\nDETAIL=SOURCE_LINE=0084:\nDETAIL=SOURCE_LINE=0085:[ -r \"$ERROR_REGISTER\" ] || {\nDETAIL=SOURCE_LINE=0086: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0087: echo 'REASON=ERROR_REGISTER_NOT_READABLE'\nDETAIL=SOURCE_LINE=0088: exit 70\nDETAIL=SOURCE_LINE=0089:}\nDETAIL=SOURCE_LINE=0090:\nDETAIL=SOURCE_LINE=0091:STATE_DIR=/var/lib/homelab-chat-run\nDETAIL=SOURCE_LINE=0092:RAW_DIR=\"$STATE_DIR/raw\"\nDETAIL=SOURCE_LINE=0093:PUBLIC_DIR=\"$STATE_DIR/public\"\nDETAIL=SOURCE_LINE=0094:LEDGER=\"$STATE_DIR/state/command-ledger.tsv\"\nDETAIL=SOURCE_LINE=0095:LOCK=\"$STATE_DIR/state/runner.lock\"\nDETAIL=SOURCE_LINE=0096:\nDETAIL=SOURCE_LINE=0097:mkdir -p \"$RAW_DIR\" \"$PUBLIC_DIR\" \"$(dirname \"$LEDGER\")\"\nDETAIL=SOURCE_LINE=0098:chmod 0700 \"$STATE_DIR\" \"$RAW_DIR\" \"$PUBLIC_DIR\" \"$(dirname \"$LEDGER\")\"\nDETAIL=SOURCE_LINE=0099:touch \"$LEDGER\"\nDETAIL=SOURCE_LINE=0100:chmod 0600 \"$LEDGER\"\nDETAIL=SOURCE_LINE=0101:\nDETAIL=SOURCE_LINE=0102:exec 9>\"$LOCK\"\nDETAIL=SOURCE_LINE=0103:\nDETAIL=SOURCE_LINE=0104:flock -w 60 9 || {\nDETAIL=SOURCE_LINE=0105: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0106: echo 'REASON=RUNNER_LOCK_TIMEOUT'\nDETAIL=SOURCE_LINE=0107: exit 71\nDETAIL=SOURCE_LINE=0108:}\nDETAIL=SOURCE_LINE=0109:\nDETAIL=SOURCE_LINE=0110:STARTED_AT=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\nDETAIL=SOURCE_LINE=0111:STAMP=\"$(date -u +%Y%m%dT%H%M%SZ)\"\nDETAIL=SOURCE_LINE=0112:HOST_SHORT=\"$(hostname -s 2>/dev/null || hostname)\"\nDETAIL=SOURCE_LINE=0113:\nDETAIL=SOURCE_LINE=0114:RAW_FILE=\"$RAW_DIR/${COMMAND_ID}-${STAMP}.log\"\nDETAIL=SOURCE_LINE=0115:SANITIZED_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.txt\"\nDETAIL=SOURCE_LINE=0116:JSON_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.json\"\nDETAIL=SOURCE_LINE=0117:TXT_FILE=\"$PUBLIC_DIR/${COMMAND_ID}-${STAMP}-latest.txt\"\nDETAIL=SOURCE_LINE=0118:\nDETAIL=SOURCE_LINE=0119:REFERENCE_SHA256=\"$(sha256sum \"$REFERENCE\" | awk '{print $1}')\"\nDETAIL=SOURCE_LINE=0120:ERROR_REGISTER_SHA256=\"$(sha256sum \"$ERROR_REGISTER\" | awk '{print $1}')\"\nDETAIL=SOURCE_LINE=0121:\nDETAIL=SOURCE_LINE=0122:COMMAND_SHA256=\"$(\nDETAIL=SOURCE_LINE=0123: {\nDETAIL=SOURCE_LINE=0124: printf '%s\\0' \"$MODE\"\nDETAIL=SOURCE_LINE=0125: printf '%s\\0' \"$COMPONENT\"\nDETAIL=SOURCE_LINE=0126: printf '%s\\0' \"$@\"\nDETAIL=SOURCE_LINE=0127: } |\nDETAIL=SOURCE_LINE=0128: sha256sum |\nDETAIL=SOURCE_LINE=0129: awk '{print $1}'\nDETAIL=SOURCE_LINE=0130:)\"\nDETAIL=SOURCE_LINE=0131:\nDETAIL=SOURCE_LINE=0132:PREVIOUS_FAILED_RC=\"$(\nDETAIL=SOURCE_LINE=0133: awk -F '\\t' -v hash=\"$COMMAND_SHA256\" '\nDETAIL=SOURCE_LINE=0134: $3 == hash && $4 != \"0\" {\nDETAIL=SOURCE_LINE=0135: value=$4\nDETAIL=SOURCE_LINE=0136: }\nDETAIL=SOURCE_LINE=0137:\nDETAIL=SOURCE_LINE=0138: END {\nDETAIL=SOURCE_LINE=0139: print value\nDETAIL=SOURCE_LINE=0140: }\nDETAIL=SOURCE_LINE=0141: ' \"$LEDGER\"\nDETAIL=SOURCE_LINE=0142:)\"\nDETAIL=SOURCE_LINE=0143:\nDETAIL=SOURCE_LINE=0144:RUN_STARTED=true\nDETAIL=SOURCE_LINE=0145:REPEAT_BLOCKED=false\nDETAIL=SOURCE_LINE=0146:BLOCK_REASON=''\nDETAIL=SOURCE_LINE=0147:CHANGES_MADE=false\nDETAIL=SOURCE_LINE=0148:\nDETAIL=SOURCE_LINE=0149:case \"$MODE\" in\nDETAIL=SOURCE_LINE=0150: change)\nDETAIL=SOURCE_LINE=0151: CHANGES_MADE=true\nDETAIL=SOURCE_LINE=0152: ;;\nDETAIL=SOURCE_LINE=0153:esac\nDETAIL=SOURCE_LINE=0154:\nDETAIL=SOURCE_LINE=0155:if [ -n \"$PREVIOUS_FAILED_RC\" ] &&\nDETAIL=SOURCE_LINE=0156: [ \"${HOMELAB_ALLOW_REPEAT:-0}\" != 1 ]; then\nDETAIL=SOURCE_LINE=0157:\nDETAIL=SOURCE_LINE=0158: RUN_STARTED=false\nDETAIL=SOURCE_LINE=0159: REPEAT_BLOCKED=true\nDETAIL=SOURCE_LINE=0160: BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT'\nDETAIL=SOURCE_LINE=0161: RC=73\nDETAIL=SOURCE_LINE=0162: STATUS='BLOCKED'\nDETAIL=SOURCE_LINE=0163:\nDETAIL=SOURCE_LINE=0164: {\nDETAIL=SOURCE_LINE=0165: echo 'COMMAND_EXECUTION_BLOCKED=yes'\nDETAIL=SOURCE_LINE=0166: echo 'REASON=EXACT_FAILED_COMMAND_REPEAT'\nDETAIL=SOURCE_LINE=0167: echo \"PREVIOUS_RC=$PREVIOUS_FAILED_RC\"\nDETAIL=SOURCE_LINE=0168: echo \"COMMAND_SHA256=$COMMAND_SHA256\"\nDETAIL=SOURCE_LINE=0169: echo\nDETAIL=SOURCE_LINE=0170: echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.'\nDETAIL=SOURCE_LINE=0171: } >\"$RAW_FILE\"\nDETAIL=SOURCE_LINE=0172:else\nDETAIL=SOURCE_LINE=0173: set +e\nDETAIL=SOURCE_LINE=0174:\nDETAIL=SOURCE_LINE=0175: if [ -n \"${HOMELAB_TIMEOUT:-}\" ]; then\nDETAIL=SOURCE_LINE=0176: case \"$HOMELAB_TIMEOUT\" in\nDETAIL=SOURCE_LINE=0177: *[!0-9]*|'')\nDETAIL=SOURCE_LINE=0178: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0179: echo 'REASON=INVALID_HOMELAB_TIMEOUT'\nDETAIL=SOURCE_LINE=0180: exit 74\nDETAIL=SOURCE_LINE=0181: ;;\nDETAIL=SOURCE_LINE=0182: esac\nDETAIL=SOURCE_LINE=0183:\nDETAIL=SOURCE_LINE=0184: timeout \\\nDETAIL=SOURCE_LINE=0185: --foreground \\\nDETAIL=SOURCE_LINE=0186: --preserve-status \\\nDETAIL=SOURCE_LINE=0187: \"$HOMELAB_TIMEOUT\" \\\nDETAIL=SOURCE_LINE=0188: \"$@\" >\"$RAW_FILE\" 2>&1\nDETAIL=SOURCE_LINE=0189: RC=$?\nDETAIL=SOURCE_LINE=0190: else\nDETAIL=SOURCE_LINE=0191: \"$@\" >\"$RAW_FILE\" 2>&1\nDETAIL=SOURCE_LINE=0192: RC=$?\nDETAIL=SOURCE_LINE=0193: fi\nDETAIL=SOURCE_LINE=0194:\nDETAIL=SOURCE_LINE=0195: set -e\nDETAIL=SOURCE_LINE=0196:\nDETAIL=SOURCE_LINE=0197: if [ \"$RC\" -eq 0 ]; then\nDETAIL=SOURCE_LINE=0198: STATUS='OK'\nDETAIL=SOURCE_LINE=0199: else\nDETAIL=SOURCE_LINE=0200: STATUS='FAIL'\nDETAIL=SOURCE_LINE=0201: fi\nDETAIL=SOURCE_LINE=0202:fi\nDETAIL=SOURCE_LINE=0203:\nDETAIL=SOURCE_LINE=0204:FINISHED_AT=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\nDETAIL=SOURCE_LINE=0205:RAW_SHA256=\"$(sha256sum \"$RAW_FILE\" | awk '{print $1}')\"\nDETAIL=SOURCE_LINE=0206:\nDETAIL=SOURCE_LINE=0207:python3 - \"$RAW_FILE\" \"$SANITIZED_FILE\" <<'PY'\nDETAIL=SOURCE_LINE=0208:import re\nDETAIL=SOURCE_LINE=0209:import sys\nDETAIL=SOURCE_LINE=0210:from pathlib import Path\nDETAIL=SOURCE_LINE=0211:\nDETAIL=SOURCE_LINE=0212:source = Path(sys.argv[1])\nDETAIL=SOURCE_LINE=0213:target = Path(sys.argv[2])\nDETAIL=SOURCE_LINE=0214:\nDETAIL=SOURCE_LINE=0215:text = source.read_bytes().decode(\"utf-8\", errors=\"replace\")\nDETAIL=SOURCE_LINE=0216:\nDETAIL=SOURCE_LINE=0217:patterns = [\nDETAIL=SOURCE_LINE=0218: (\nDETAIL=SOURCE_LINE=0219: re.compile(\nDETAIL=SOURCE_LINE=0220: r\"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\"\nDETAIL=SOURCE_LINE=0221: r\".*?\"\nDETAIL=SOURCE_LINE=0222: r\"-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\",\nDETAIL=SOURCE_LINE=0223: re.IGNORECASE | re.DOTALL,\nDETAIL=SOURCE_LINE=0224: ),\nDETAIL=SOURCE_LINE=0225: \"[PRIVATE_KEY_REDACTED]\",\nDETAIL=SOURCE_LINE=0226: ),\nDETAIL=SOURCE_LINE=0227: (\nDETAIL=SOURCE_LINE=0228: re.compile(\nDETAIL=SOURCE_LINE=0229: r\"(?im)^(\\s*(?:password|passwd|passphrase|authorization|\"\nDETAIL=SOURCE_LINE=...\nDETAIL=SOURCE_LINE=0292:maximum = 900_000\nDETAIL=SOURCE_LINE=0293:\nDETAIL=SOURCE_LINE=0294:if len(encoded) > maximum:\nDETAIL=SOURCE_LINE=0295: first = encoded[:440_000].decode(\"utf-8\", errors=\"ignore\")\nDETAIL=SOURCE_LINE=0296: last = encoded[-440_000:].decode(\"utf-8\", errors=\"ignore\")\nDETAIL=SOURCE_LINE=0297:\nDETAIL=SOURCE_LINE=0298: text = (\nDETAIL=SOURCE_LINE=0299: first\nDETAIL=SOURCE_LINE=0300: + \"\\n\\n\"\nDETAIL=SOURCE_LINE=0301: + \"===== PUBLIC OUTPUT TRUNCATED; FULL RAW LOG RETAINED LOCALLY =====\"\nDETAIL=SOURCE_LINE=0302: + \"\\n\\n\"\nDETAIL=SOURCE_LINE=0303: + last\nDETAIL=SOURCE_LINE=0304: )\nDETAIL=SOURCE_LINE=0305:\nDETAIL=SOURCE_LINE=0306:target.write_text(text, encoding=\"utf-8\")\nDETAIL=SOURCE_LINE=0307:PY\nDETAIL=SOURCE_LINE=0308:\nDETAIL=SOURCE_LINE=0309:SANITIZED_SHA256=\"$(\nDETAIL=SOURCE_LINE=0310: sha256sum \"$SANITIZED_FILE\" |\nDETAIL=SOURCE_LINE=0311: awk '{print $1}'\nDETAIL=SOURCE_LINE=0312:)\"\nDETAIL=SOURCE_LINE=0313:\nDETAIL=SOURCE_LINE=0314:python3 - \\\nDETAIL=SOURCE_LINE=0315: \"$JSON_FILE\" \\\nDETAIL=SOURCE_LINE=0316: \"$SANITIZED_FILE\" \\\nDETAIL=SOURCE_LINE=0317: \"$COMMAND_ID\" \\\nDETAIL=SOURCE_LINE=0318: \"$STATUS\" \\\nDETAIL=SOURCE_LINE=0319: \"$RC\" \\\nDETAIL=SOURCE_LINE=0320: \"$HOST_SHORT\" \\\nDETAIL=SOURCE_LINE=0321: \"$MODE\" \\\nDETAIL=SOURCE_LINE=0322: \"$COMPONENT\" \\\nDETAIL=SOURCE_LINE=0323: \"$STARTED_AT\" \\\nDETAIL=SOURCE_LINE=0324: \"$FINISHED_AT\" \\\nDETAIL=SOURCE_LINE=0325: \"$REFERENCE_SHA256\" \\\nDETAIL=SOURCE_LINE=0326: \"$ERROR_REGISTER_SHA256\" \\\nDETAIL=SOURCE_LINE=0327: \"$COMMAND_SHA256\" \\\nDETAIL=SOURCE_LINE=0328: \"$RAW_SHA256\" \\\nDETAIL=SOURCE_LINE=0329: \"$SANITIZED_SHA256\" \\\nDETAIL=SOURCE_LINE=0330: \"$RUN_STARTED\" \\\nDETAIL=SOURCE_LINE=0331: \"$REPEAT_BLOCKED\" \\\nDETAIL=SOURCE_LINE=0332: \"$BLOCK_REASON\" \\\nDETAIL=SOURCE_LINE=0333: \"$CHANGES_MADE\" <<'PY'\nDETAIL=SOURCE_LINE=0334:import json\nDETAIL=SOURCE_LINE=0335:import sys\nDETAIL=SOURCE_LINE=0336:from pathlib import Path\nDETAIL=SOURCE_LINE=0337:\nDETAIL=SOURCE_LINE=0338:(\nDETAIL=SOURCE_LINE=0339: json_path,\nDETAIL=SOURCE_LINE=0340: output_path,\nDETAIL=SOURCE_LINE=0341: command_id,\nDETAIL=SOURCE_LINE=0342: status,\nDETAIL=SOURCE_LINE=0343: rc,\nDETAIL=SOURCE_LINE=0344: host,\nDETAIL=SOURCE_LINE=0345: mode,\nDETAIL=SOURCE_LINE=0346: component,\nDETAIL=SOURCE_LINE=0347: started,\nDETAIL=SOURCE_LINE=0348: finished,\nDETAIL=SOURCE_LINE=0349: reference_sha,\nDETAIL=SOURCE_LINE=0350: error_sha,\nDETAIL=SOURCE_LINE=0351: command_sha,\nDETAIL=SOURCE_LINE=0352: raw_sha,\nDETAIL=SOURCE_LINE=0353: sanitized_sha,\nDETAIL=SOURCE_LINE=0354: run_started,\nDETAIL=SOURCE_LINE=0355: repeat_blocked,\nDETAIL=SOURCE_LINE=...\nDETAIL=SOURCE_LINE=0416: )\nDETAIL=SOURCE_LINE=0417: + \"\\n\",\nDETAIL=SOURCE_LINE=0418: encoding=\"utf-8\",\nDETAIL=SOURCE_LINE=0419:)\nDETAIL=SOURCE_LINE=0420:PY\nDETAIL=SOURCE_LINE=0421:\nDETAIL=SOURCE_LINE=0422:{\nDETAIL=SOURCE_LINE=0423: echo 'CHAT_OUTPUT_BEGIN'\nDETAIL=SOURCE_LINE=0424: echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE_LINE=0425: echo \"STATUS=$STATUS\"\nDETAIL=SOURCE_LINE=0426: echo \"RC=$RC\"\nDETAIL=SOURCE_LINE=0427: echo \"HOST=$HOST_SHORT\"\nDETAIL=SOURCE_LINE=0428: echo \"MODE=$MODE\"\nDETAIL=SOURCE_LINE=0429: echo \"COMPONENT=$COMPONENT\"\nDETAIL=SOURCE_LINE=0430: echo 'REFERENCE_REGISTER_CHECK=OK'\nDETAIL=SOURCE_LINE=0431: echo \"REFERENCE_SHA256=$REFERENCE_SHA256\"\nDETAIL=SOURCE_LINE=0432: echo 'ERROR_REGISTER_CHECK=OK'\nDETAIL=SOURCE_LINE=0433: echo \"ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256\"\nDETAIL=SOURCE_LINE=0434: echo \"COMMAND_SHA256=$COMMAND_SHA256\"\nDETAIL=SOURCE_LINE=0435: echo \"DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED\"\nDETAIL=SOURCE_LINE=0436: echo \"EXECUTION_STARTED=$RUN_STARTED\"\nDETAIL=SOURCE_LINE=0437: echo \"CHANGES_MADE=$CHANGES_MADE\"\nDETAIL=SOURCE_LINE=0438: echo 'SANITIZED=yes'\nDETAIL=SOURCE_LINE=0439: echo 'SECRETS_INCLUDED=no'\nDETAIL=SOURCE_LINE=0440: echo 'PRIVATE_ADDRESSES_INCLUDED=no'\nDETAIL=SOURCE_LINE=0441: echo \"RAW_EVIDENCE_SHA256=$RAW_SHA256\"\nDETAIL=SOURCE_LINE=0442: echo \"SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256\"\nDETAIL=SOURCE_LINE=0443: echo 'OUTPUT_BEGIN'\nDETAIL=SOURCE_LINE=0444: cat \"$SANITIZED_FILE\"\nDETAIL=SOURCE_LINE=0445: echo\nDETAIL=SOURCE_LINE=0446: echo 'OUTPUT_END'\nDETAIL=SOURCE_LINE=0447: echo 'CHAT_OUTPUT_END'\nDETAIL=SOURCE_LINE=0448:} >\"$TXT_FILE\"\nDETAIL=SOURCE_LINE=0449:\nDETAIL=SOURCE_LINE=0450:chmod 0600 \\\nDETAIL=SOURCE_LINE=0451: \"$RAW_FILE\" \\\nDETAIL=SOURCE_LINE=0452: \"$SANITIZED_FILE\" \\\nDETAIL=SOURCE_LINE=0453: \"$JSON_FILE\" \\\nDETAIL=SOURCE_LINE=0454: \"$TXT_FILE\"\nDETAIL=SOURCE_LINE=0455:\nDETAIL=SOURCE_LINE=0456:TARGET=debian@[PRIVATE_IP]\nDETAIL=SOURCE_LINE=0457:REMOTE_PREFIX=\"/tmp/homelab-runtime-${COMMAND_ID}-$$\"\nDETAIL=SOURCE_LINE=0458:\nDETAIL=SOURCE_LINE=0459:SSH_OPTS=(\nDETAIL=SOURCE_LINE=...\nDETAIL=SOURCE_LINE=0509: PUBLIC_VISIBLE=true\nDETAIL=SOURCE_LINE=0510: break\nDETAIL=SOURCE_LINE=0511: fi\nDETAIL=SOURCE_LINE=0512:\nDETAIL=SOURCE_LINE=0513: sleep 2\nDETAIL=SOURCE_LINE=0514:done\nDETAIL=SOURCE_LINE=0515:\nDETAIL=SOURCE_LINE=0516:if [ \"$PUBLIC_VISIBLE\" != true ]; then\nDETAIL=SOURCE_LINE=0517: echo 'RESULT=FAIL'\nDETAIL=SOURCE_LINE=0518: echo 'REASON=PUBLIC_RUNTIME_RESULT_NOT_VISIBLE'\nDETAIL=SOURCE_LINE=0519: echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE_LINE=0520: echo \"LOCAL_RAW_FILE=$RAW_FILE\"\nDETAIL=SOURCE_LINE=0521: exit 75\nDETAIL=SOURCE_LINE=0522:fi\nDETAIL=SOURCE_LINE=0523:\nDETAIL=SOURCE_LINE=0524:printf '%s\\t%s\\t%s\\t%s\\t%s\\t%s\\n' \\\nDETAIL=SOURCE_LINE=0525: \"$FINISHED_AT\" \\\nDETAIL=SOURCE_LINE=0526: \"$COMMAND_ID\" \\\nDETAIL=SOURCE_LINE=0527: \"$COMMAND_SHA256\" \\\nDETAIL=SOURCE_LINE=0528: \"$RC\" \\\nDETAIL=SOURCE_LINE=0529: \"$STATUS\" \\\nDETAIL=SOURCE_LINE=0530: \"$COMPONENT\" >>\"$LEDGER\"\nDETAIL=SOURCE_LINE=0531:\nDETAIL=SOURCE_LINE=0532:echo\nDETAIL=SOURCE_LINE=0533:echo '===== HOMELAB CHAT RUN COMPLETE ====='\nDETAIL=SOURCE_LINE=0534:echo \"COMMAND_ID=$COMMAND_ID\"\nDETAIL=SOURCE_LINE=0535:echo \"STATUS=$STATUS\"\nDETAIL=SOURCE_LINE=0536:echo \"RC=$RC\"\nDETAIL=SOURCE_LINE=0537:echo 'REFERENCE_REGISTER_CHECK=OK'\nDETAIL=SOURCE_LINE=0538:echo 'ERROR_REGISTER_CHECK=OK'\nDETAIL=SOURCE_LINE=0539:echo \"DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED\"\nDETAIL=SOURCE_LINE=0540:echo 'GITEA_PUBLICATION=OK'\nDETAIL=SOURCE_LINE=0541:echo \"PUBLIC_URL=$PUBLIC_URL\"\nDETAIL=SOURCE_LINE=0542:echo \"LOCAL_RAW_FILE=$RAW_FILE\"\nDETAIL=SOURCE_LINE=0543:echo 'SHELL_SESSION_PRESERVED=yes'\nDETAIL=SOURCE_LINE=0544:\nDETAIL=SOURCE_LINE=0545:exit \"$RC\"\nDETAIL=TOTAL_LINES=545\nDETAIL=EXACT_LOGIC_END\nDETAIL=DUPLICATE_EXACT_LOGIC_AUDIT=PASS\nDETAIL=SECRET_VALUES_OUTPUT=NONE\nCHANGES_MADE=NO\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index 3f436a9..ee624d2 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,5 +1,5 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=HOMELAB-DUPLICATE-FINGERPRINT-AUDIT-426 +COMMAND_ID=HOMELAB-DUPLICATE-EXACT-LOGIC-427 STATUS=OK RC=0 HOST=pve01 @@ -9,423 +9,357 @@ REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752 -COMMAND_SHA256=d95e5a9d8480b33605c127ce6ebdc688d05087f3c0afbdda7c3af1a5129a3d3c +COMMAND_SHA256=7e4f72d9877110d6d6d4ef926a611b1bd8ad15fa4b2ad3ef17e9027ba49bc111 DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGES_MADE=false SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=db73d9a0e67a6c8cdbb9fcb6ae3ee47c92879dc079fe115a8412abd39ef39ca4 -SANITIZED_OUTPUT_SHA256=b1ad62957baf7f8680f85ae10f1db94077a48c98e438dda3987b551f7a15cb13 +RAW_EVIDENCE_SHA256=8480bb49baedd9fdebe212ee204d07d772e707d3c09045de0c3334fde723f6e9 +SANITIZED_OUTPUT_SHA256=5e8f3e2de086ae3c1d1bf84dcffbcb8dc8770ebefb00aa959db1ff15db3468b9 OUTPUT_BEGIN DETAIL=FILE=/usr/local/sbin/homelab-chat-run-linked DETAIL=SHA256=5e8725e129fd2055b36fe2fae13fc95fc4b3271074a0e0d4bb7347e7b2f270a1 +DETAIL=EXACT_LOGIC_BEGIN +DETAIL=TOTAL_LINES=39 +DETAIL=EXACT_LOGIC_END DETAIL=FILE=/usr/local/sbin/homelab-chat-run DETAIL=SHA256=2a88defef9517f89bc60934dce82097f8e316b08af9417e95167ea5d759a10d9 -DETAIL=SOURCE=51- read-only|verify|change|transport-test) -DETAIL=SOURCE=52- ;; -DETAIL=SOURCE=53- *) -DETAIL=SOURCE=54- echo 'RESULT=FAIL' -DETAIL=SOURCE=55- echo 'REASON=INVALID_MODE' -DETAIL=SOURCE=56- exit 67 -DETAIL=SOURCE=57- ;; -DETAIL=SOURCE=58-esac -DETAIL=SOURCE=59- -DETAIL=SOURCE=60-for TOOL in \ -DETAIL=SOURCE=61- awk \ -DETAIL=SOURCE=62- curl \ -DETAIL=SOURCE=63- flock \ -DETAIL=SOURCE=64- python3 \ -DETAIL=SOURCE=65- scp \ -DETAIL=SOURCE=66: sha256sum \ -DETAIL=SOURCE=67- ssh -DETAIL=SOURCE=68-do -DETAIL=SOURCE=69- command -v "$TOOL" >/dev/null 2>&1 || { -DETAIL=SOURCE=70- echo 'RESULT=FAIL' -DETAIL=SOURCE=71- echo "REASON=REQUIRED_TOOL_MISSING:$TOOL" -DETAIL=SOURCE=72- exit 68 -DETAIL=SOURCE=73- } -DETAIL=SOURCE=74-done -DETAIL=SOURCE=75- -DETAIL=SOURCE=76-REFERENCE=/etc/pve/31_HOMELAB_REFERENCE.md -DETAIL=SOURCE=77-ERROR_REGISTER=/etc/pve/HOMELAB_ASSISTANT_ERROR_REGISTER.md -DETAIL=SOURCE=78- -DETAIL=SOURCE=79-[ -r "$REFERENCE" ] || { -DETAIL=SOURCE=80- echo 'RESULT=FAIL' -DETAIL=SOURCE=81- echo 'REASON=REFERENCE_NOT_READABLE' -DETAIL=SOURCE=82- exit 69 -DETAIL=SOURCE=83-} -DETAIL=SOURCE=84- -DETAIL=SOURCE=85-[ -r "$ERROR_REGISTER" ] || { -DETAIL=SOURCE=86- echo 'RESULT=FAIL' -DETAIL=SOURCE=87- echo 'REASON=ERROR_REGISTER_NOT_READABLE' -DETAIL=SOURCE=88- exit 70 -DETAIL=SOURCE=89-} -DETAIL=SOURCE=90- -DETAIL=SOURCE=91-STATE_DIR=/var/lib/homelab-chat-run -DETAIL=SOURCE=92-RAW_DIR="$STATE_DIR/raw" -DETAIL=SOURCE=93-PUBLIC_DIR="$STATE_DIR/public" -DETAIL=SOURCE=94-LEDGER="$STATE_DIR/state/command-ledger.tsv" -DETAIL=SOURCE=95-LOCK="$STATE_DIR/state/runner.lock" -DETAIL=SOURCE=96- -DETAIL=SOURCE=-- -DETAIL=SOURCE=104-flock -w 60 9 || { -DETAIL=SOURCE=105- echo 'RESULT=FAIL' -DETAIL=SOURCE=106- echo 'REASON=RUNNER_LOCK_TIMEOUT' -DETAIL=SOURCE=107- exit 71 -DETAIL=SOURCE=108-} -DETAIL=SOURCE=109- -DETAIL=SOURCE=110-STARTED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" -DETAIL=SOURCE=111-STAMP="$(date -u +%Y%m%dT%H%M%SZ)" -DETAIL=SOURCE=112-HOST_SHORT="$(hostname -s 2>/dev/null || hostname)" -DETAIL=SOURCE=113- -DETAIL=SOURCE=114-RAW_FILE="$RAW_DIR/${COMMAND_ID}-${STAMP}.log" -DETAIL=SOURCE=115-SANITIZED_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.txt" -DETAIL=SOURCE=116-JSON_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.json" -DETAIL=SOURCE=117-TXT_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}-latest.txt" -DETAIL=SOURCE=118- -DETAIL=SOURCE=119:REFERENCE_SHA256="$(sha256sum "$REFERENCE" | awk '{print $1}')" -DETAIL=SOURCE=120:ERROR_REGISTER_SHA256="$(sha256sum "$ERROR_REGISTER" | awk '{print $1}')" -DETAIL=SOURCE=121- -DETAIL=SOURCE=122:COMMAND_SHA256="$( -DETAIL=SOURCE=123- { -DETAIL=SOURCE=124- printf '%s\0' "$MODE" -DETAIL=SOURCE=125- printf '%s\0' "$COMPONENT" -DETAIL=SOURCE=126- printf '%s\0' "$@" -DETAIL=SOURCE=127- } | -DETAIL=SOURCE=128: sha256sum | -DETAIL=SOURCE=129- awk '{print $1}' -DETAIL=SOURCE=130-)" -DETAIL=SOURCE=131- -DETAIL=SOURCE=132-PREVIOUS_FAILED_RC="$( -DETAIL=SOURCE=133: awk -F '\t' -v hash="$COMMAND_SHA256" ' -DETAIL=SOURCE=134- $3 == hash && $4 != "0" { -DETAIL=SOURCE=135- value=$4 -DETAIL=SOURCE=136- } -DETAIL=SOURCE=137- -DETAIL=SOURCE=138- END { -DETAIL=SOURCE=139- print value -DETAIL=SOURCE=140- } -DETAIL=SOURCE=141- ' "$LEDGER" -DETAIL=SOURCE=142-)" -DETAIL=SOURCE=143- -DETAIL=SOURCE=144-RUN_STARTED=true -DETAIL=SOURCE=145-REPEAT_BLOCKED=false -DETAIL=SOURCE=146-BLOCK_REASON='' -DETAIL=SOURCE=147-CHANGES_MADE=false -DETAIL=SOURCE=148- -DETAIL=SOURCE=149-case "$MODE" in -DETAIL=SOURCE=150- change) -DETAIL=SOURCE=151- CHANGES_MADE=true -DETAIL=SOURCE=152- ;; -DETAIL=SOURCE=153-esac -DETAIL=SOURCE=154- -DETAIL=SOURCE=155-if [ -n "$PREVIOUS_FAILED_RC" ] && -DETAIL=SOURCE=156- [ "${HOMELAB_ALLOW_REPEAT:-0}" != 1 ]; then -DETAIL=SOURCE=157- -DETAIL=SOURCE=158- RUN_STARTED=false -DETAIL=SOURCE=159- REPEAT_BLOCKED=true -DETAIL=SOURCE=160: BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT' -DETAIL=SOURCE=161- RC=73 -DETAIL=SOURCE=162- STATUS='BLOCKED' -DETAIL=SOURCE=163- -DETAIL=SOURCE=164- { -DETAIL=SOURCE=165- echo 'COMMAND_EXECUTION_BLOCKED=yes' -DETAIL=SOURCE=166: echo 'REASON=EXACT_FAILED_COMMAND_REPEAT' -DETAIL=SOURCE=167- echo "PREVIOUS_RC=$PREVIOUS_FAILED_RC" -DETAIL=SOURCE=168: echo "COMMAND_SHA256=$COMMAND_SHA256" -DETAIL=SOURCE=169- echo -DETAIL=SOURCE=170- echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.' -DETAIL=SOURCE=171- } >"$RAW_FILE" -DETAIL=SOURCE=172-else -DETAIL=SOURCE=173- set +e -DETAIL=SOURCE=174- -DETAIL=SOURCE=175- if [ -n "${HOMELAB_TIMEOUT:-}" ]; then -DETAIL=SOURCE=176- case "$HOMELAB_TIMEOUT" in -DETAIL=SOURCE=177- *[!0-9]*|'') -DETAIL=SOURCE=178- echo 'RESULT=FAIL' -DETAIL=SOURCE=179- echo 'REASON=INVALID_HOMELAB_TIMEOUT' -DETAIL=SOURCE=180- exit 74 -DETAIL=SOURCE=181- ;; -DETAIL=SOURCE=182- esac -DETAIL=SOURCE=183- -DETAIL=SOURCE=184- timeout \ -DETAIL=SOURCE=185- --foreground \ -DETAIL=SOURCE=186- --preserve-status \ -DETAIL=SOURCE=187- "$HOMELAB_TIMEOUT" \ -DETAIL=SOURCE=188- "$@" >"$RAW_FILE" 2>&1 -DETAIL=SOURCE=189- RC=$? -DETAIL=SOURCE=190- else -DETAIL=SOURCE=191- "$@" >"$RAW_FILE" 2>&1 -DETAIL=SOURCE=192- RC=$? -DETAIL=SOURCE=193- fi -DETAIL=SOURCE=194- -DETAIL=SOURCE=195- set -e -DETAIL=SOURCE=196- -DETAIL=SOURCE=197- if [ "$RC" -eq 0 ]; then -DETAIL=SOURCE=198- STATUS='OK' -DETAIL=SOURCE=199- else -DETAIL=SOURCE=200- STATUS='FAIL' -DETAIL=SOURCE=201- fi -DETAIL=SOURCE=202-fi -DETAIL=SOURCE=203- -DETAIL=SOURCE=204-FINISHED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" -DETAIL=SOURCE=205:RAW_SHA256="$(sha256sum "$RAW_FILE" | awk '{print $1}')" -DETAIL=SOURCE=206- -DETAIL=SOURCE=207-python3 - "$RAW_FILE" "$SANITIZED_FILE" <<'PY' -DETAIL=SOURCE=208-import re -DETAIL=SOURCE=209-import sys -DETAIL=SOURCE=210-from pathlib import Path -DETAIL=SOURCE=211- -DETAIL=SOURCE=212:source = Path(sys.argv[1]) -DETAIL=SOURCE=213:target = Path(sys.argv[2]) -DETAIL=SOURCE=214- -DETAIL=SOURCE=215-text = source.read_bytes().decode("utf-8", errors="replace") -DETAIL=SOURCE=216- -DETAIL=SOURCE=217-patterns = [ -DETAIL=SOURCE=218- ( -DETAIL=SOURCE=219- re.compile( -DETAIL=SOURCE=220- r"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----" -DETAIL=SOURCE=221- r".*?" -DETAIL=SOURCE=222- r"-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----", -DETAIL=SOURCE=223- re.IGNORECASE | re.DOTALL, -DETAIL=SOURCE=224- ), -DETAIL=SOURCE=225- "[PRIVATE_KEY_REDACTED]", -DETAIL=SOURCE=226- ), -DETAIL=SOURCE=227- ( -DETAIL=SOURCE=228- re.compile( -DETAIL=SOURCE=229- r"(?im)^(\s*(?:password|passwd|passphrase|authorization|" -DETAIL=SOURCE=230- r"api[_-]?key|access[_-]?token|refresh[_-]?token|" -DETAIL=SOURCE=231- r"private[_-]?key|secret)\s*[:=]\s*).*$" -DETAIL=SOURCE=232- ), -DETAIL=SOURCE=233- r"\1[REDACTED]", -DETAIL=SOURCE=234- ), -DETAIL=SOURCE=235- ( -DETAIL=SOURCE=236- re.compile(r"(?i)(Bearer\s+)[A-Za-z0-9._~+/=-]+"), -DETAIL=SOURCE=237- r"\1[REDACTED]", -DETAIL=SOURCE=238- ), -DETAIL=SOURCE=239- ( -DETAIL=SOURCE=240- re.compile(r"\b10(?:\.\d{1,3}){3}\b"), -DETAIL=SOURCE=241- "[PRIVATE_IP]", -DETAIL=SOURCE=242- ), -DETAIL=SOURCE=243- ( -DETAIL=SOURCE=-- -DETAIL=SOURCE=294-if len(encoded) > maximum: -DETAIL=SOURCE=295- first = encoded[:440_000].decode("utf-8", errors="ignore") -DETAIL=SOURCE=296- last = encoded[-440_000:].decode("utf-8", errors="ignore") -DETAIL=SOURCE=297- -DETAIL=SOURCE=298- text = ( -DETAIL=SOURCE=299- first -DETAIL=SOURCE=300- + "\n\n" -DETAIL=SOURCE=301- + "===== PUBLIC OUTPUT TRUNCATED; FULL RAW LOG RETAINED LOCALLY =====" -DETAIL=SOURCE=302- + "\n\n" -DETAIL=SOURCE=303- + last -DETAIL=SOURCE=304- ) -DETAIL=SOURCE=305- -DETAIL=SOURCE=306-target.write_text(text, encoding="utf-8") -DETAIL=SOURCE=307-PY -DETAIL=SOURCE=308- -DETAIL=SOURCE=309:SANITIZED_SHA256="$( -DETAIL=SOURCE=310: sha256sum "$SANITIZED_FILE" | -DETAIL=SOURCE=311- awk '{print $1}' -DETAIL=SOURCE=312-)" -DETAIL=SOURCE=313- -DETAIL=SOURCE=314-python3 - \ -DETAIL=SOURCE=315- "$JSON_FILE" \ -DETAIL=SOURCE=316- "$SANITIZED_FILE" \ -DETAIL=SOURCE=317- "$COMMAND_ID" \ -DETAIL=SOURCE=318- "$STATUS" \ -DETAIL=SOURCE=319- "$RC" \ -DETAIL=SOURCE=320- "$HOST_SHORT" \ -DETAIL=SOURCE=321- "$MODE" \ -DETAIL=SOURCE=322- "$COMPONENT" \ -DETAIL=SOURCE=323- "$STARTED_AT" \ -DETAIL=SOURCE=324- "$FINISHED_AT" \ -DETAIL=SOURCE=325: "$REFERENCE_SHA256" \ -DETAIL=SOURCE=326: "$ERROR_REGISTER_SHA256" \ -DETAIL=SOURCE=327: "$COMMAND_SHA256" \ -DETAIL=SOURCE=328: "$RAW_SHA256" \ -DETAIL=SOURCE=329: "$SANITIZED_SHA256" \ -DETAIL=SOURCE=330- "$RUN_STARTED" \ -DETAIL=SOURCE=331- "$REPEAT_BLOCKED" \ -DETAIL=SOURCE=332- "$BLOCK_REASON" \ -DETAIL=SOURCE=333- "$CHANGES_MADE" <<'PY' -DETAIL=SOURCE=334-import json -DETAIL=SOURCE=335-import sys -DETAIL=SOURCE=336-from pathlib import Path -DETAIL=SOURCE=337- -DETAIL=SOURCE=338-( -DETAIL=SOURCE=339- json_path, -DETAIL=SOURCE=340- output_path, -DETAIL=SOURCE=341- command_id, -DETAIL=SOURCE=342- status, -DETAIL=SOURCE=343- rc, -DETAIL=SOURCE=344- host, -DETAIL=SOURCE=345- mode, -DETAIL=SOURCE=346- component, -DETAIL=SOURCE=347- started, -DETAIL=SOURCE=348- finished, -DETAIL=SOURCE=349- reference_sha, -DETAIL=SOURCE=350- error_sha, -DETAIL=SOURCE=351- command_sha, -DETAIL=SOURCE=352- raw_sha, -DETAIL=SOURCE=353- sanitized_sha, -DETAIL=SOURCE=354- run_started, -DETAIL=SOURCE=355- repeat_blocked, -DETAIL=SOURCE=356- block_reason, -DETAIL=SOURCE=357- changes_made, -DETAIL=SOURCE=358:) = sys.argv[1:] -DETAIL=SOURCE=359- -DETAIL=SOURCE=360-output = Path(output_path).read_text( -DETAIL=SOURCE=361- encoding="utf-8", -DETAIL=SOURCE=362- errors="replace", -DETAIL=SOURCE=363-) -DETAIL=SOURCE=364- -DETAIL=SOURCE=365-encoded = output.encode("utf-8") -DETAIL=SOURCE=366-json_limit = 300_000 -DETAIL=SOURCE=367-output_truncated = len(encoded) > json_limit -DETAIL=SOURCE=368- -DETAIL=SOURCE=369-if output_truncated: -DETAIL=SOURCE=370- output_preview = encoded[:json_limit].decode( -DETAIL=SOURCE=371- "utf-8", -DETAIL=SOURCE=372- errors="ignore", -DETAIL=SOURCE=373- ) -DETAIL=SOURCE=374-else: -DETAIL=SOURCE=375- output_preview = output -DETAIL=SOURCE=376- -DETAIL=SOURCE=377-document = { -DETAIL=SOURCE=378- "schema_version": 1, -DETAIL=SOURCE=379- "channel": "homelab-runtime", -DETAIL=SOURCE=380- "command_id": command_id, -DETAIL=SOURCE=381- "status": status, -DETAIL=SOURCE=382- "rc": int(rc), -DETAIL=SOURCE=383- "host": host, -DETAIL=SOURCE=384- "mode": mode, -DETAIL=SOURCE=385- "component": component, -DETAIL=SOURCE=386- "started_at_utc": started, -DETAIL=SOURCE=387- "finished_at_utc": finished, -DETAIL=SOURCE=388- "reference_register_checked": True, -DETAIL=SOURCE=389: "reference_sha256": reference_sha, -DETAIL=SOURCE=390- "error_register_checked": True, -DETAIL=SOURCE=391: "error_register_sha256": error_sha, -DETAIL=SOURCE=392: "command_sha256": command_sha, -DETAIL=SOURCE=393: "duplicate_failed_command_blocked": repeat_blocked == "true", -DETAIL=SOURCE=394- "block_reason": block_reason or None, -DETAIL=SOURCE=395- "execution_started": run_started == "true", -DETAIL=SOURCE=396- "changes_made": changes_made == "true", -DETAIL=SOURCE=397- "sanitized": True, -DETAIL=SOURCE=398- "secrets_included": False, -DETAIL=SOURCE=399- "private_addresses_included": False, -DETAIL=SOURCE=400- "raw_evidence_retained_locally": True, -DETAIL=SOURCE=401: "raw_evidence_sha256": raw_sha, -DETAIL=SOURCE=402: "sanitized_output_sha256": sanitized_sha, -DETAIL=SOURCE=403- "output_truncated_in_json": output_truncated, -DETAIL=SOURCE=404- "full_sanitized_output_url": ( -DETAIL=SOURCE=405- "https://git.gram1.ru/.well-known/" -DETAIL=SOURCE=406- "homelab-runtime/latest.txt" -DETAIL=SOURCE=407- ), -DETAIL=SOURCE=408- "output": output_preview, -DETAIL=SOURCE=409-} -DETAIL=SOURCE=410- -DETAIL=SOURCE=411-Path(json_path).write_text( -DETAIL=SOURCE=412- json.dumps( -DETAIL=SOURCE=413- document, -DETAIL=SOURCE=414- ensure_ascii=False, -DETAIL=SOURCE=415- indent=2, -DETAIL=SOURCE=416- ) -DETAIL=SOURCE=417- + "\n", -DETAIL=SOURCE=418- encoding="utf-8", -DETAIL=SOURCE=419-) -DETAIL=SOURCE=420-PY -DETAIL=SOURCE=421- -DETAIL=SOURCE=422-{ -DETAIL=SOURCE=423- echo 'CHAT_OUTPUT_BEGIN' -DETAIL=SOURCE=424- echo "COMMAND_ID=$COMMAND_ID" -DETAIL=SOURCE=425- echo "STATUS=$STATUS" -DETAIL=SOURCE=426- echo "RC=$RC" -DETAIL=SOURCE=427- echo "HOST=$HOST_SHORT" -DETAIL=SOURCE=428- echo "MODE=$MODE" -DETAIL=SOURCE=429- echo "COMPONENT=$COMPONENT" -DETAIL=SOURCE=430- echo 'REFERENCE_REGISTER_CHECK=OK' -DETAIL=SOURCE=431: echo "REFERENCE_SHA256=$REFERENCE_SHA256" -DETAIL=SOURCE=432- echo 'ERROR_REGISTER_CHECK=OK' -DETAIL=SOURCE=433: echo "ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256" -DETAIL=SOURCE=434: echo "COMMAND_SHA256=$COMMAND_SHA256" -DETAIL=SOURCE=435: echo "DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED" -DETAIL=SOURCE=436- echo "EXECUTION_STARTED=$RUN_STARTED" -DETAIL=SOURCE=437- echo "CHANGES_MADE=$CHANGES_MADE" -DETAIL=SOURCE=438- echo 'SANITIZED=yes' -DETAIL=SOURCE=439- echo 'SECRETS_INCLUDED=no' -DETAIL=SOURCE=440- echo 'PRIVATE_ADDRESSES_INCLUDED=no' -DETAIL=SOURCE=441: echo "RAW_EVIDENCE_SHA256=$RAW_SHA256" -DETAIL=SOURCE=442: echo "SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256" -DETAIL=SOURCE=443- echo 'OUTPUT_BEGIN' -DETAIL=SOURCE=444- cat "$SANITIZED_FILE" -DETAIL=SOURCE=445- echo -DETAIL=SOURCE=446- echo 'OUTPUT_END' -DETAIL=SOURCE=447- echo 'CHAT_OUTPUT_END' -DETAIL=SOURCE=448-} >"$TXT_FILE" -DETAIL=SOURCE=449- -DETAIL=SOURCE=450-chmod 0600 \ -DETAIL=SOURCE=451- "$RAW_FILE" \ -DETAIL=SOURCE=452- "$SANITIZED_FILE" \ -DETAIL=SOURCE=453- "$JSON_FILE" \ -DETAIL=SOURCE=454- "$TXT_FILE" -DETAIL=SOURCE=455- -DETAIL=SOURCE=456-TARGET=debian@[PRIVATE_IP] -DETAIL=SOURCE=457-REMOTE_PREFIX="/tmp/homelab-runtime-${COMMAND_ID}-$$" -DETAIL=SOURCE=458- -DETAIL=SOURCE=459-SSH_OPTS=( -DETAIL=SOURCE=460- -o BatchMode=yes -DETAIL=SOURCE=461- -o ConnectTimeout=10 -DETAIL=SOURCE=462- -o ConnectionAttempts=1 -DETAIL=SOURCE=463- -o StrictHostKeyChecking=yes -DETAIL=SOURCE=464- -o UserKnownHostsFile=[SENSITIVE_PATH] -DETAIL=SOURCE=465-) -DETAIL=SOURCE=466- -DETAIL=SOURCE=467-scp \ -DETAIL=SOURCE=468- -q \ -DETAIL=SOURCE=469- "${SSH_OPTS[@]}" \ -DETAIL=SOURCE=470- "$JSON_FILE" \ -DETAIL=SOURCE=471- "${TARGET}:${REMOTE_PREFIX}.json" -DETAIL=SOURCE=472- -DETAIL=SOURCE=-- -DETAIL=SOURCE=512- -DETAIL=SOURCE=513- sleep 2 -DETAIL=SOURCE=514-done -DETAIL=SOURCE=515- -DETAIL=SOURCE=516-if [ "$PUBLIC_VISIBLE" != true ]; then -DETAIL=SOURCE=517- echo 'RESULT=FAIL' -DETAIL=SOURCE=518- echo 'REASON=PUBLIC_RUNTIME_RESULT_NOT_VISIBLE' -DETAIL=SOURCE=519- echo "COMMAND_ID=$COMMAND_ID" -DETAIL=SOURCE=520- echo "LOCAL_RAW_FILE=$RAW_FILE" -DETAIL=SOURCE=521- exit 75 -DETAIL=SOURCE=522-fi -DETAIL=SOURCE=523- -DETAIL=SOURCE=524-printf '%s\t%s\t%s\t%s\t%s\t%s\n' \ -DETAIL=SOURCE=525- "$FINISHED_AT" \ -DETAIL=SOURCE=526- "$COMMAND_ID" \ -DETAIL=SOURCE=527: "$COMMAND_SHA256" \ -DETAIL=SOURCE=528- "$RC" \ -DETAIL=SOURCE=529- "$STATUS" \ -DETAIL=SOURCE=530- "$COMPONENT" >>"$LEDGER" -DETAIL=SOURCE=531- -DETAIL=SOURCE=532-echo -DETAIL=SOURCE=533-echo '===== HOMELAB CHAT RUN COMPLETE =====' -DETAIL=SOURCE=534-echo "COMMAND_ID=$COMMAND_ID" -DETAIL=SOURCE=535-echo "STATUS=$STATUS" -DETAIL=SOURCE=536-echo "RC=$RC" -DETAIL=SOURCE=537-echo 'REFERENCE_REGISTER_CHECK=OK' -DETAIL=SOURCE=538-echo 'ERROR_REGISTER_CHECK=OK' -DETAIL=SOURCE=539:echo "DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED" -DETAIL=SOURCE=540-echo 'GITEA_PUBLICATION=OK' -DETAIL=SOURCE=541-echo "PUBLIC_URL=$PUBLIC_URL" -DETAIL=SOURCE=542-echo "LOCAL_RAW_FILE=$RAW_FILE" -DETAIL=SOURCE=543-echo 'SHELL_SESSION_PRESERVED=yes' -DETAIL=SOURCE=544- -DETAIL=SOURCE=545-exit "$RC" -DETAIL=DUPLICATE_FINGERPRINT_AUDIT=PASS +DETAIL=EXACT_LOGIC_BEGIN +DETAIL=SOURCE_LINE=0048:esac +DETAIL=SOURCE_LINE=0049: +DETAIL=SOURCE_LINE=0050:case "$MODE" in +DETAIL=SOURCE_LINE=0051: read-only|verify|change|transport-test) +DETAIL=SOURCE_LINE=0052: ;; +DETAIL=SOURCE_LINE=0053: *) +DETAIL=SOURCE_LINE=0054: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0055: echo 'REASON=INVALID_MODE' +DETAIL=SOURCE_LINE=0056: exit 67 +DETAIL=SOURCE_LINE=0057: ;; +DETAIL=SOURCE_LINE=0058:esac +DETAIL=SOURCE_LINE=0059: +DETAIL=SOURCE_LINE=0060:for TOOL in \ +DETAIL=SOURCE_LINE=0061: awk \ +DETAIL=SOURCE_LINE=0062: curl \ +DETAIL=SOURCE_LINE=0063: flock \ +DETAIL=SOURCE_LINE=0064: python3 \ +DETAIL=SOURCE_LINE=0065: scp \ +DETAIL=SOURCE_LINE=0066: sha256sum \ +DETAIL=SOURCE_LINE=0067: ssh +DETAIL=SOURCE_LINE=0068:do +DETAIL=SOURCE_LINE=0069: command -v "$TOOL" >/dev/null 2>&1 || { +DETAIL=SOURCE_LINE=0070: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0071: echo "REASON=REQUIRED_TOOL_MISSING:$TOOL" +DETAIL=SOURCE_LINE=0072: exit 68 +DETAIL=SOURCE_LINE=0073: } +DETAIL=SOURCE_LINE=0074:done +DETAIL=SOURCE_LINE=0075: +DETAIL=SOURCE_LINE=0076:REFERENCE=/etc/pve/31_HOMELAB_REFERENCE.md +DETAIL=SOURCE_LINE=0077:ERROR_REGISTER=/etc/pve/HOMELAB_ASSISTANT_ERROR_REGISTER.md +DETAIL=SOURCE_LINE=0078: +DETAIL=SOURCE_LINE=0079:[ -r "$REFERENCE" ] || { +DETAIL=SOURCE_LINE=0080: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0081: echo 'REASON=REFERENCE_NOT_READABLE' +DETAIL=SOURCE_LINE=0082: exit 69 +DETAIL=SOURCE_LINE=0083:} +DETAIL=SOURCE_LINE=0084: +DETAIL=SOURCE_LINE=0085:[ -r "$ERROR_REGISTER" ] || { +DETAIL=SOURCE_LINE=0086: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0087: echo 'REASON=ERROR_REGISTER_NOT_READABLE' +DETAIL=SOURCE_LINE=0088: exit 70 +DETAIL=SOURCE_LINE=0089:} +DETAIL=SOURCE_LINE=0090: +DETAIL=SOURCE_LINE=0091:STATE_DIR=/var/lib/homelab-chat-run +DETAIL=SOURCE_LINE=0092:RAW_DIR="$STATE_DIR/raw" +DETAIL=SOURCE_LINE=0093:PUBLIC_DIR="$STATE_DIR/public" +DETAIL=SOURCE_LINE=0094:LEDGER="$STATE_DIR/state/command-ledger.tsv" +DETAIL=SOURCE_LINE=0095:LOCK="$STATE_DIR/state/runner.lock" +DETAIL=SOURCE_LINE=0096: +DETAIL=SOURCE_LINE=0097:mkdir -p "$RAW_DIR" "$PUBLIC_DIR" "$(dirname "$LEDGER")" +DETAIL=SOURCE_LINE=0098:chmod 0700 "$STATE_DIR" "$RAW_DIR" "$PUBLIC_DIR" "$(dirname "$LEDGER")" +DETAIL=SOURCE_LINE=0099:touch "$LEDGER" +DETAIL=SOURCE_LINE=0100:chmod 0600 "$LEDGER" +DETAIL=SOURCE_LINE=0101: +DETAIL=SOURCE_LINE=0102:exec 9>"$LOCK" +DETAIL=SOURCE_LINE=0103: +DETAIL=SOURCE_LINE=0104:flock -w 60 9 || { +DETAIL=SOURCE_LINE=0105: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0106: echo 'REASON=RUNNER_LOCK_TIMEOUT' +DETAIL=SOURCE_LINE=0107: exit 71 +DETAIL=SOURCE_LINE=0108:} +DETAIL=SOURCE_LINE=0109: +DETAIL=SOURCE_LINE=0110:STARTED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +DETAIL=SOURCE_LINE=0111:STAMP="$(date -u +%Y%m%dT%H%M%SZ)" +DETAIL=SOURCE_LINE=0112:HOST_SHORT="$(hostname -s 2>/dev/null || hostname)" +DETAIL=SOURCE_LINE=0113: +DETAIL=SOURCE_LINE=0114:RAW_FILE="$RAW_DIR/${COMMAND_ID}-${STAMP}.log" +DETAIL=SOURCE_LINE=0115:SANITIZED_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.txt" +DETAIL=SOURCE_LINE=0116:JSON_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}.json" +DETAIL=SOURCE_LINE=0117:TXT_FILE="$PUBLIC_DIR/${COMMAND_ID}-${STAMP}-latest.txt" +DETAIL=SOURCE_LINE=0118: +DETAIL=SOURCE_LINE=0119:REFERENCE_SHA256="$(sha256sum "$REFERENCE" | awk '{print $1}')" +DETAIL=SOURCE_LINE=0120:ERROR_REGISTER_SHA256="$(sha256sum "$ERROR_REGISTER" | awk '{print $1}')" +DETAIL=SOURCE_LINE=0121: +DETAIL=SOURCE_LINE=0122:COMMAND_SHA256="$( +DETAIL=SOURCE_LINE=0123: { +DETAIL=SOURCE_LINE=0124: printf '%s\0' "$MODE" +DETAIL=SOURCE_LINE=0125: printf '%s\0' "$COMPONENT" +DETAIL=SOURCE_LINE=0126: printf '%s\0' "$@" +DETAIL=SOURCE_LINE=0127: } | +DETAIL=SOURCE_LINE=0128: sha256sum | +DETAIL=SOURCE_LINE=0129: awk '{print $1}' +DETAIL=SOURCE_LINE=0130:)" +DETAIL=SOURCE_LINE=0131: +DETAIL=SOURCE_LINE=0132:PREVIOUS_FAILED_RC="$( +DETAIL=SOURCE_LINE=0133: awk -F '\t' -v hash="$COMMAND_SHA256" ' +DETAIL=SOURCE_LINE=0134: $3 == hash && $4 != "0" { +DETAIL=SOURCE_LINE=0135: value=$4 +DETAIL=SOURCE_LINE=0136: } +DETAIL=SOURCE_LINE=0137: +DETAIL=SOURCE_LINE=0138: END { +DETAIL=SOURCE_LINE=0139: print value +DETAIL=SOURCE_LINE=0140: } +DETAIL=SOURCE_LINE=0141: ' "$LEDGER" +DETAIL=SOURCE_LINE=0142:)" +DETAIL=SOURCE_LINE=0143: +DETAIL=SOURCE_LINE=0144:RUN_STARTED=true +DETAIL=SOURCE_LINE=0145:REPEAT_BLOCKED=false +DETAIL=SOURCE_LINE=0146:BLOCK_REASON='' +DETAIL=SOURCE_LINE=0147:CHANGES_MADE=false +DETAIL=SOURCE_LINE=0148: +DETAIL=SOURCE_LINE=0149:case "$MODE" in +DETAIL=SOURCE_LINE=0150: change) +DETAIL=SOURCE_LINE=0151: CHANGES_MADE=true +DETAIL=SOURCE_LINE=0152: ;; +DETAIL=SOURCE_LINE=0153:esac +DETAIL=SOURCE_LINE=0154: +DETAIL=SOURCE_LINE=0155:if [ -n "$PREVIOUS_FAILED_RC" ] && +DETAIL=SOURCE_LINE=0156: [ "${HOMELAB_ALLOW_REPEAT:-0}" != 1 ]; then +DETAIL=SOURCE_LINE=0157: +DETAIL=SOURCE_LINE=0158: RUN_STARTED=false +DETAIL=SOURCE_LINE=0159: REPEAT_BLOCKED=true +DETAIL=SOURCE_LINE=0160: BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT' +DETAIL=SOURCE_LINE=0161: RC=73 +DETAIL=SOURCE_LINE=0162: STATUS='BLOCKED' +DETAIL=SOURCE_LINE=0163: +DETAIL=SOURCE_LINE=0164: { +DETAIL=SOURCE_LINE=0165: echo 'COMMAND_EXECUTION_BLOCKED=yes' +DETAIL=SOURCE_LINE=0166: echo 'REASON=EXACT_FAILED_COMMAND_REPEAT' +DETAIL=SOURCE_LINE=0167: echo "PREVIOUS_RC=$PREVIOUS_FAILED_RC" +DETAIL=SOURCE_LINE=0168: echo "COMMAND_SHA256=$COMMAND_SHA256" +DETAIL=SOURCE_LINE=0169: echo +DETAIL=SOURCE_LINE=0170: echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.' +DETAIL=SOURCE_LINE=0171: } >"$RAW_FILE" +DETAIL=SOURCE_LINE=0172:else +DETAIL=SOURCE_LINE=0173: set +e +DETAIL=SOURCE_LINE=0174: +DETAIL=SOURCE_LINE=0175: if [ -n "${HOMELAB_TIMEOUT:-}" ]; then +DETAIL=SOURCE_LINE=0176: case "$HOMELAB_TIMEOUT" in +DETAIL=SOURCE_LINE=0177: *[!0-9]*|'') +DETAIL=SOURCE_LINE=0178: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0179: echo 'REASON=INVALID_HOMELAB_TIMEOUT' +DETAIL=SOURCE_LINE=0180: exit 74 +DETAIL=SOURCE_LINE=0181: ;; +DETAIL=SOURCE_LINE=0182: esac +DETAIL=SOURCE_LINE=0183: +DETAIL=SOURCE_LINE=0184: timeout \ +DETAIL=SOURCE_LINE=0185: --foreground \ +DETAIL=SOURCE_LINE=0186: --preserve-status \ +DETAIL=SOURCE_LINE=0187: "$HOMELAB_TIMEOUT" \ +DETAIL=SOURCE_LINE=0188: "$@" >"$RAW_FILE" 2>&1 +DETAIL=SOURCE_LINE=0189: RC=$? +DETAIL=SOURCE_LINE=0190: else +DETAIL=SOURCE_LINE=0191: "$@" >"$RAW_FILE" 2>&1 +DETAIL=SOURCE_LINE=0192: RC=$? +DETAIL=SOURCE_LINE=0193: fi +DETAIL=SOURCE_LINE=0194: +DETAIL=SOURCE_LINE=0195: set -e +DETAIL=SOURCE_LINE=0196: +DETAIL=SOURCE_LINE=0197: if [ "$RC" -eq 0 ]; then +DETAIL=SOURCE_LINE=0198: STATUS='OK' +DETAIL=SOURCE_LINE=0199: else +DETAIL=SOURCE_LINE=0200: STATUS='FAIL' +DETAIL=SOURCE_LINE=0201: fi +DETAIL=SOURCE_LINE=0202:fi +DETAIL=SOURCE_LINE=0203: +DETAIL=SOURCE_LINE=0204:FINISHED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +DETAIL=SOURCE_LINE=0205:RAW_SHA256="$(sha256sum "$RAW_FILE" | awk '{print $1}')" +DETAIL=SOURCE_LINE=0206: +DETAIL=SOURCE_LINE=0207:python3 - "$RAW_FILE" "$SANITIZED_FILE" <<'PY' +DETAIL=SOURCE_LINE=0208:import re +DETAIL=SOURCE_LINE=0209:import sys +DETAIL=SOURCE_LINE=0210:from pathlib import Path +DETAIL=SOURCE_LINE=0211: +DETAIL=SOURCE_LINE=0212:source = Path(sys.argv[1]) +DETAIL=SOURCE_LINE=0213:target = Path(sys.argv[2]) +DETAIL=SOURCE_LINE=0214: +DETAIL=SOURCE_LINE=0215:text = source.read_bytes().decode("utf-8", errors="replace") +DETAIL=SOURCE_LINE=0216: +DETAIL=SOURCE_LINE=0217:patterns = [ +DETAIL=SOURCE_LINE=0218: ( +DETAIL=SOURCE_LINE=0219: re.compile( +DETAIL=SOURCE_LINE=0220: r"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----" +DETAIL=SOURCE_LINE=0221: r".*?" +DETAIL=SOURCE_LINE=0222: r"-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----", +DETAIL=SOURCE_LINE=0223: re.IGNORECASE | re.DOTALL, +DETAIL=SOURCE_LINE=0224: ), +DETAIL=SOURCE_LINE=0225: "[PRIVATE_KEY_REDACTED]", +DETAIL=SOURCE_LINE=0226: ), +DETAIL=SOURCE_LINE=0227: ( +DETAIL=SOURCE_LINE=0228: re.compile( +DETAIL=SOURCE_LINE=0229: r"(?im)^(\s*(?:password|passwd|passphrase|authorization|" +DETAIL=SOURCE_LINE=... +DETAIL=SOURCE_LINE=0292:maximum = 900_000 +DETAIL=SOURCE_LINE=0293: +DETAIL=SOURCE_LINE=0294:if len(encoded) > maximum: +DETAIL=SOURCE_LINE=0295: first = encoded[:440_000].decode("utf-8", errors="ignore") +DETAIL=SOURCE_LINE=0296: last = encoded[-440_000:].decode("utf-8", errors="ignore") +DETAIL=SOURCE_LINE=0297: +DETAIL=SOURCE_LINE=0298: text = ( +DETAIL=SOURCE_LINE=0299: first +DETAIL=SOURCE_LINE=0300: + "\n\n" +DETAIL=SOURCE_LINE=0301: + "===== PUBLIC OUTPUT TRUNCATED; FULL RAW LOG RETAINED LOCALLY =====" +DETAIL=SOURCE_LINE=0302: + "\n\n" +DETAIL=SOURCE_LINE=0303: + last +DETAIL=SOURCE_LINE=0304: ) +DETAIL=SOURCE_LINE=0305: +DETAIL=SOURCE_LINE=0306:target.write_text(text, encoding="utf-8") +DETAIL=SOURCE_LINE=0307:PY +DETAIL=SOURCE_LINE=0308: +DETAIL=SOURCE_LINE=0309:SANITIZED_SHA256="$( +DETAIL=SOURCE_LINE=0310: sha256sum "$SANITIZED_FILE" | +DETAIL=SOURCE_LINE=0311: awk '{print $1}' +DETAIL=SOURCE_LINE=0312:)" +DETAIL=SOURCE_LINE=0313: +DETAIL=SOURCE_LINE=0314:python3 - \ +DETAIL=SOURCE_LINE=0315: "$JSON_FILE" \ +DETAIL=SOURCE_LINE=0316: "$SANITIZED_FILE" \ +DETAIL=SOURCE_LINE=0317: "$COMMAND_ID" \ +DETAIL=SOURCE_LINE=0318: "$STATUS" \ +DETAIL=SOURCE_LINE=0319: "$RC" \ +DETAIL=SOURCE_LINE=0320: "$HOST_SHORT" \ +DETAIL=SOURCE_LINE=0321: "$MODE" \ +DETAIL=SOURCE_LINE=0322: "$COMPONENT" \ +DETAIL=SOURCE_LINE=0323: "$STARTED_AT" \ +DETAIL=SOURCE_LINE=0324: "$FINISHED_AT" \ +DETAIL=SOURCE_LINE=0325: "$REFERENCE_SHA256" \ +DETAIL=SOURCE_LINE=0326: "$ERROR_REGISTER_SHA256" \ +DETAIL=SOURCE_LINE=0327: "$COMMAND_SHA256" \ +DETAIL=SOURCE_LINE=0328: "$RAW_SHA256" \ +DETAIL=SOURCE_LINE=0329: "$SANITIZED_SHA256" \ +DETAIL=SOURCE_LINE=0330: "$RUN_STARTED" \ +DETAIL=SOURCE_LINE=0331: "$REPEAT_BLOCKED" \ +DETAIL=SOURCE_LINE=0332: "$BLOCK_REASON" \ +DETAIL=SOURCE_LINE=0333: "$CHANGES_MADE" <<'PY' +DETAIL=SOURCE_LINE=0334:import json +DETAIL=SOURCE_LINE=0335:import sys +DETAIL=SOURCE_LINE=0336:from pathlib import Path +DETAIL=SOURCE_LINE=0337: +DETAIL=SOURCE_LINE=0338:( +DETAIL=SOURCE_LINE=0339: json_path, +DETAIL=SOURCE_LINE=0340: output_path, +DETAIL=SOURCE_LINE=0341: command_id, +DETAIL=SOURCE_LINE=0342: status, +DETAIL=SOURCE_LINE=0343: rc, +DETAIL=SOURCE_LINE=0344: host, +DETAIL=SOURCE_LINE=0345: mode, +DETAIL=SOURCE_LINE=0346: component, +DETAIL=SOURCE_LINE=0347: started, +DETAIL=SOURCE_LINE=0348: finished, +DETAIL=SOURCE_LINE=0349: reference_sha, +DETAIL=SOURCE_LINE=0350: error_sha, +DETAIL=SOURCE_LINE=0351: command_sha, +DETAIL=SOURCE_LINE=0352: raw_sha, +DETAIL=SOURCE_LINE=0353: sanitized_sha, +DETAIL=SOURCE_LINE=0354: run_started, +DETAIL=SOURCE_LINE=0355: repeat_blocked, +DETAIL=SOURCE_LINE=... +DETAIL=SOURCE_LINE=0416: ) +DETAIL=SOURCE_LINE=0417: + "\n", +DETAIL=SOURCE_LINE=0418: encoding="utf-8", +DETAIL=SOURCE_LINE=0419:) +DETAIL=SOURCE_LINE=0420:PY +DETAIL=SOURCE_LINE=0421: +DETAIL=SOURCE_LINE=0422:{ +DETAIL=SOURCE_LINE=0423: echo 'CHAT_OUTPUT_BEGIN' +DETAIL=SOURCE_LINE=0424: echo "COMMAND_ID=$COMMAND_ID" +DETAIL=SOURCE_LINE=0425: echo "STATUS=$STATUS" +DETAIL=SOURCE_LINE=0426: echo "RC=$RC" +DETAIL=SOURCE_LINE=0427: echo "HOST=$HOST_SHORT" +DETAIL=SOURCE_LINE=0428: echo "MODE=$MODE" +DETAIL=SOURCE_LINE=0429: echo "COMPONENT=$COMPONENT" +DETAIL=SOURCE_LINE=0430: echo 'REFERENCE_REGISTER_CHECK=OK' +DETAIL=SOURCE_LINE=0431: echo "REFERENCE_SHA256=$REFERENCE_SHA256" +DETAIL=SOURCE_LINE=0432: echo 'ERROR_REGISTER_CHECK=OK' +DETAIL=SOURCE_LINE=0433: echo "ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256" +DETAIL=SOURCE_LINE=0434: echo "COMMAND_SHA256=$COMMAND_SHA256" +DETAIL=SOURCE_LINE=0435: echo "DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED" +DETAIL=SOURCE_LINE=0436: echo "EXECUTION_STARTED=$RUN_STARTED" +DETAIL=SOURCE_LINE=0437: echo "CHANGES_MADE=$CHANGES_MADE" +DETAIL=SOURCE_LINE=0438: echo 'SANITIZED=yes' +DETAIL=SOURCE_LINE=0439: echo 'SECRETS_INCLUDED=no' +DETAIL=SOURCE_LINE=0440: echo 'PRIVATE_ADDRESSES_INCLUDED=no' +DETAIL=SOURCE_LINE=0441: echo "RAW_EVIDENCE_SHA256=$RAW_SHA256" +DETAIL=SOURCE_LINE=0442: echo "SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256" +DETAIL=SOURCE_LINE=0443: echo 'OUTPUT_BEGIN' +DETAIL=SOURCE_LINE=0444: cat "$SANITIZED_FILE" +DETAIL=SOURCE_LINE=0445: echo +DETAIL=SOURCE_LINE=0446: echo 'OUTPUT_END' +DETAIL=SOURCE_LINE=0447: echo 'CHAT_OUTPUT_END' +DETAIL=SOURCE_LINE=0448:} >"$TXT_FILE" +DETAIL=SOURCE_LINE=0449: +DETAIL=SOURCE_LINE=0450:chmod 0600 \ +DETAIL=SOURCE_LINE=0451: "$RAW_FILE" \ +DETAIL=SOURCE_LINE=0452: "$SANITIZED_FILE" \ +DETAIL=SOURCE_LINE=0453: "$JSON_FILE" \ +DETAIL=SOURCE_LINE=0454: "$TXT_FILE" +DETAIL=SOURCE_LINE=0455: +DETAIL=SOURCE_LINE=0456:TARGET=debian@[PRIVATE_IP] +DETAIL=SOURCE_LINE=0457:REMOTE_PREFIX="/tmp/homelab-runtime-${COMMAND_ID}-$$" +DETAIL=SOURCE_LINE=0458: +DETAIL=SOURCE_LINE=0459:SSH_OPTS=( +DETAIL=SOURCE_LINE=... +DETAIL=SOURCE_LINE=0509: PUBLIC_VISIBLE=true +DETAIL=SOURCE_LINE=0510: break +DETAIL=SOURCE_LINE=0511: fi +DETAIL=SOURCE_LINE=0512: +DETAIL=SOURCE_LINE=0513: sleep 2 +DETAIL=SOURCE_LINE=0514:done +DETAIL=SOURCE_LINE=0515: +DETAIL=SOURCE_LINE=0516:if [ "$PUBLIC_VISIBLE" != true ]; then +DETAIL=SOURCE_LINE=0517: echo 'RESULT=FAIL' +DETAIL=SOURCE_LINE=0518: echo 'REASON=PUBLIC_RUNTIME_RESULT_NOT_VISIBLE' +DETAIL=SOURCE_LINE=0519: echo "COMMAND_ID=$COMMAND_ID" +DETAIL=SOURCE_LINE=0520: echo "LOCAL_RAW_FILE=$RAW_FILE" +DETAIL=SOURCE_LINE=0521: exit 75 +DETAIL=SOURCE_LINE=0522:fi +DETAIL=SOURCE_LINE=0523: +DETAIL=SOURCE_LINE=0524:printf '%s\t%s\t%s\t%s\t%s\t%s\n' \ +DETAIL=SOURCE_LINE=0525: "$FINISHED_AT" \ +DETAIL=SOURCE_LINE=0526: "$COMMAND_ID" \ +DETAIL=SOURCE_LINE=0527: "$COMMAND_SHA256" \ +DETAIL=SOURCE_LINE=0528: "$RC" \ +DETAIL=SOURCE_LINE=0529: "$STATUS" \ +DETAIL=SOURCE_LINE=0530: "$COMPONENT" >>"$LEDGER" +DETAIL=SOURCE_LINE=0531: +DETAIL=SOURCE_LINE=0532:echo +DETAIL=SOURCE_LINE=0533:echo '===== HOMELAB CHAT RUN COMPLETE =====' +DETAIL=SOURCE_LINE=0534:echo "COMMAND_ID=$COMMAND_ID" +DETAIL=SOURCE_LINE=0535:echo "STATUS=$STATUS" +DETAIL=SOURCE_LINE=0536:echo "RC=$RC" +DETAIL=SOURCE_LINE=0537:echo 'REFERENCE_REGISTER_CHECK=OK' +DETAIL=SOURCE_LINE=0538:echo 'ERROR_REGISTER_CHECK=OK' +DETAIL=SOURCE_LINE=0539:echo "DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED" +DETAIL=SOURCE_LINE=0540:echo 'GITEA_PUBLICATION=OK' +DETAIL=SOURCE_LINE=0541:echo "PUBLIC_URL=$PUBLIC_URL" +DETAIL=SOURCE_LINE=0542:echo "LOCAL_RAW_FILE=$RAW_FILE" +DETAIL=SOURCE_LINE=0543:echo 'SHELL_SESSION_PRESERVED=yes' +DETAIL=SOURCE_LINE=0544: +DETAIL=SOURCE_LINE=0545:exit "$RC" +DETAIL=TOTAL_LINES=545 +DETAIL=EXACT_LOGIC_END +DETAIL=DUPLICATE_EXACT_LOGIC_AUDIT=PASS DETAIL=SECRET_VALUES_OUTPUT=NONE CHANGES_MADE=NO