From 7e530890ca8007b3cee9f1fd035fa1b7e2e11e04 Mon Sep 17 00:00:00 2001 From: homelab-runtime-publisher Date: Thu, 23 Jul 2026 05:00:01 +0000 Subject: [PATCH] runtime: publish READER-CHANGE-GATE-INTERFACE-AUDIT-330 --- ...EADER-CHANGE-GATE-INTERFACE-AUDIT-330.json | 30 +++++ ...READER-CHANGE-GATE-INTERFACE-AUDIT-330.txt | 111 ++++++++++++++++++ runtime/latest.json | 14 +-- runtime/latest.txt | 108 +++++++++++++---- 4 files changed, 236 insertions(+), 27 deletions(-) create mode 100644 runtime/history/READER-CHANGE-GATE-INTERFACE-AUDIT-330.json create mode 100644 runtime/history/READER-CHANGE-GATE-INTERFACE-AUDIT-330.txt diff --git a/runtime/history/READER-CHANGE-GATE-INTERFACE-AUDIT-330.json b/runtime/history/READER-CHANGE-GATE-INTERFACE-AUDIT-330.json new file mode 100644 index 0000000..edc466c --- /dev/null +++ b/runtime/history/READER-CHANGE-GATE-INTERFACE-AUDIT-330.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "READER-CHANGE-GATE-INTERFACE-AUDIT-330", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "read-only", + "component": "cluster-audit", + "started_at_utc": "2026-07-23T05:00:00Z", + "finished_at_utc": "2026-07-23T05:00:00Z", + "reference_register_checked": true, + "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", + "error_register_checked": true, + "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752", + "command_sha256": "0c6a6c62888e384581527e16d35802a1835bef622617b27a301d9077cc33f923", + "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": "cccc50fe97b2ddc7711107f77a40cbebc700089145145f641d4ae62f19876fdd", + "sanitized_output_sha256": "1c4864ae4d0b36b1d2cf7d1376c7ffa5415174750f0eda9b0201fbb4bb84c1ac", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/test\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sha256sum\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/awk\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sed\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/bash\nDETAIL=CHANGE_GATE_SHA256=90470653345baac426d1ff6d3e3b1109a611ef7ba8d98b7453be0f732ced3597\nDETAIL=CHANGE_GATE_INTEGRITY=PASS\nDETAIL=CHANGE_GATE_SYNTAX=PASS\nDETAIL=CHANGE_GATE_LINE_COUNT=74\nDETAIL=CHANGE_GATE_SOURCE_BEGIN\n#!/usr/bin/bash\nset -Eeuo pipefail\n\nVM=/usr/local/sbin/homelab-vm130-exec\nNG=/usr/local/sbin/homelab-edge-nginx-exec\nVM_SHA=1959773393723b013af7c93cd29a7b833fd607c903d044e2fcef6accaa29c275\nNG_SHA=f900b15bfdd19a1b543037cf8b9c1583e71dc8115bbb5812cf74d474e3e7859b\nTARGET=/opt/npmplus/custom_nginx/server_proxy.conf\nDIR=/opt/npmplus/custom_nginx\n\nfail() {\n printf 'CHANGE_GATE_ERROR=%s\\n' \"$1\" >&2\n exit \"${2:-1}\"\n}\n\n(( $# == 2 )) || fail USAGE 64\ncandidate=$1\nexpected_current=$2\n\n[[ \"$expected_current\" =~ ^[0-9a-f]{64}$ ]] || fail EXPECTED_SHA 65\n[[ -x \"$VM\" ]] || fail VM_MISSING 69\n[[ -x \"$NG\" ]] || fail NGINX_HELPER_MISSING 69\n[[ \"$(/usr/bin/sha256sum \"$VM\" | /usr/bin/awk '{print $1}')\" == \"$VM_SHA\" ]] || fail VM_INTEGRITY 70\n[[ \"$(/usr/bin/sha256sum \"$NG\" | /usr/bin/awk '{print $1}')\" == \"$NG_SHA\" ]] || fail NGINX_HELPER_INTEGRITY 70\n\n[[ -f \"$candidate\" && ! -L \"$candidate\" ]] || fail CANDIDATE_TYPE 66\nmeta=$(/usr/bin/stat -c '%U:%G|%a|%s' \"$candidate\")\nIFS='|' read -r owner mode size <<<\"$meta\"\n[[ \"$owner\" == root:root && \"$mode\" == 600 ]] || fail CANDIDATE_METADATA 66\n[[ \"$size\" =~ ^[0-9]+$ ]] && (( size > 0 && size <= 8192 )) || fail CANDIDATE_SIZE 66\n\ncap=$(/usr/bin/systemctl show homelab-reader-v3.service -p Environment --value |\n /usr/bin/sed -n 's/.*HOMELAB_READER_CAPABILITY=\\([^ ]*\\).*/\\1/p')\n[[ \"$cap\" =~ ^[0-9a-f]{64}$ ]] || fail CAPABILITY 67\n\ntmp=$(/usr/bin/mktemp)\ntrap '/usr/bin/rm -f -- \"$tmp\"' EXIT\n/usr/bin/printf '%s\\n' \\\n \"location ^~ /.well-known/homelab-reader/${cap}/ {\" \\\n \" proxy_pass http://[PRIVATE_IP]:18788/${cap}/;\" \\\n ' proxy_http_version 1.1;' \\\n ' proxy_set_header Host $host;' \\\n ' proxy_set_header Connection \"\";' \\\n ' proxy_buffering off;' \\\n ' proxy_cache off;' \\\n '}' >\"$tmp\"\n/usr/bin/cmp -s \"$candidate\" \"$tmp\" || fail CANDIDATE_CONTENT 66\ncandidate_sha=$(/usr/bin/sha256sum \"$candidate\" | /usr/bin/awk '{print $1}')\n\ntarget_meta=$(\"$VM\" /usr/bin/stat -c '%U:%G|%a|%F' \"$TARGET\")\nIFS='|' read -r target_owner target_mode target_type <<<\"$target_meta\"\n[[ \"$target_owner\" == root:root && \"$target_mode\" == 644 && \"$target_type\" == regular*file ]] || fail TARGET_METADATA 68\ncurrent_sha=$(\"$VM\" /usr/bin/sha256sum \"$TARGET\" | /usr/bin/awk '{print $1}')\n[[ \"$current_sha\" == \"$expected_current\" ]] || fail TARGET_CHANGED 68\n\ndir_meta=$(\"$VM\" /usr/bin/stat -c '%U:%G|%a|%F' \"$DIR\")\nIFS='|' read -r dir_owner dir_mode dir_type <<<\"$dir_meta\"\n[[ \"$dir_owner\" == root:root && \"$dir_mode\" == 755 && \"$dir_type\" == directory ]] || fail DIR_METADATA 68\n\"$VM\" /usr/bin/test -w \"$DIR\" || fail DIR_NOT_WRITABLE 68\n\n\"$NG\" /usr/local/bin/nginx -t >/dev/null 2>&1 || fail NGINX_CONFIG 69\n[[ \"$(/usr/bin/curl -fsS -m5 \"http://[PRIVATE_IP]:18788/${cap}/health\")\" == '{\"status\":\"ok\",\"version\":3}' ]] || fail LOCAL_READER 69\n[[ \"$(\"$VM\" /usr/bin/curl -fsS -m5 \"http://[PRIVATE_IP]:18788/${cap}/health\")\" == '{\"status\":\"ok\",\"version\":3}' ]] || fail EDGE_READER 69\n[[ \"$(/usr/bin/curl -sS -m8 --resolve git.gram1.ru:443:[PRIVATE_IP] -o /dev/null -w '%{http_code}' https://git.gram1.ru/)\" == 200 ]] || fail GITEA 69\n\nprintf 'CHANGE_GATE=READY\\n'\nprintf 'CANDIDATE_SHA256=%s\\n' \"$candidate_sha\"\nprintf 'CURRENT_SHA256=%s\\n' \"$current_sha\"\nprintf 'TARGET_METADATA=%s\\n' \"$target_meta\"\nprintf 'TARGET_DIRECTORY_METADATA=%s\\n' \"$dir_meta\"\nprintf 'NGINX_CURRENT_CONFIG=PASS\\n'\nprintf 'LOCAL_READER_CHECK=PASS\\n'\nprintf 'EDGE_READER_CHECK=PASS\\n'\nprintf 'GITEA_CHECK=PASS\\n'\nDETAIL=CHANGE_GATE_SOURCE_END\nDETAIL=CHANGE_GATE_SOURCE_TRUNCATED=NO\nCHANGES_MADE=NO\n" +} diff --git a/runtime/history/READER-CHANGE-GATE-INTERFACE-AUDIT-330.txt b/runtime/history/READER-CHANGE-GATE-INTERFACE-AUDIT-330.txt new file mode 100644 index 0000000..dbe9b51 --- /dev/null +++ b/runtime/history/READER-CHANGE-GATE-INTERFACE-AUDIT-330.txt @@ -0,0 +1,111 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=READER-CHANGE-GATE-INTERFACE-AUDIT-330 +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=0c6a6c62888e384581527e16d35802a1835bef622617b27a301d9077cc33f923 +DUPLICATE_FAILED_COMMAND_BLOCKED=false +EXECUTION_STARTED=true +CHANGES_MADE=false +SANITIZED=yes +SECRETS_INCLUDED=no +PRIVATE_ADDRESSES_INCLUDED=no +RAW_EVIDENCE_SHA256=cccc50fe97b2ddc7711107f77a40cbebc700089145145f641d4ae62f19876fdd +SANITIZED_OUTPUT_SHA256=1c4864ae4d0b36b1d2cf7d1376c7ffa5415174750f0eda9b0201fbb4bb84c1ac +OUTPUT_BEGIN +DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/test +DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sha256sum +DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/awk +DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sed +DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/bash +DETAIL=CHANGE_GATE_SHA256=90470653345baac426d1ff6d3e3b1109a611ef7ba8d98b7453be0f732ced3597 +DETAIL=CHANGE_GATE_INTEGRITY=PASS +DETAIL=CHANGE_GATE_SYNTAX=PASS +DETAIL=CHANGE_GATE_LINE_COUNT=74 +DETAIL=CHANGE_GATE_SOURCE_BEGIN +#!/usr/bin/bash +set -Eeuo pipefail + +VM=/usr/local/sbin/homelab-vm130-exec +NG=/usr/local/sbin/homelab-edge-nginx-exec +VM_SHA=1959773393723b013af7c93cd29a7b833fd607c903d044e2fcef6accaa29c275 +NG_SHA=f900b15bfdd19a1b543037cf8b9c1583e71dc8115bbb5812cf74d474e3e7859b +TARGET=/opt/npmplus/custom_nginx/server_proxy.conf +DIR=/opt/npmplus/custom_nginx + +fail() { + printf 'CHANGE_GATE_ERROR=%s\n' "$1" >&2 + exit "${2:-1}" +} + +(( $# == 2 )) || fail USAGE 64 +candidate=$1 +expected_current=$2 + +[[ "$expected_current" =~ ^[0-9a-f]{64}$ ]] || fail EXPECTED_SHA 65 +[[ -x "$VM" ]] || fail VM_MISSING 69 +[[ -x "$NG" ]] || fail NGINX_HELPER_MISSING 69 +[[ "$(/usr/bin/sha256sum "$VM" | /usr/bin/awk '{print $1}')" == "$VM_SHA" ]] || fail VM_INTEGRITY 70 +[[ "$(/usr/bin/sha256sum "$NG" | /usr/bin/awk '{print $1}')" == "$NG_SHA" ]] || fail NGINX_HELPER_INTEGRITY 70 + +[[ -f "$candidate" && ! -L "$candidate" ]] || fail CANDIDATE_TYPE 66 +meta=$(/usr/bin/stat -c '%U:%G|%a|%s' "$candidate") +IFS='|' read -r owner mode size <<<"$meta" +[[ "$owner" == root:root && "$mode" == 600 ]] || fail CANDIDATE_METADATA 66 +[[ "$size" =~ ^[0-9]+$ ]] && (( size > 0 && size <= 8192 )) || fail CANDIDATE_SIZE 66 + +cap=$(/usr/bin/systemctl show homelab-reader-v3.service -p Environment --value | + /usr/bin/sed -n 's/.*HOMELAB_READER_CAPABILITY=\([^ ]*\).*/\1/p') +[[ "$cap" =~ ^[0-9a-f]{64}$ ]] || fail CAPABILITY 67 + +tmp=$(/usr/bin/mktemp) +trap '/usr/bin/rm -f -- "$tmp"' EXIT +/usr/bin/printf '%s\n' \ + "location ^~ /.well-known/homelab-reader/${cap}/ {" \ + " proxy_pass http://[PRIVATE_IP]:18788/${cap}/;" \ + ' proxy_http_version 1.1;' \ + ' proxy_set_header Host $host;' \ + ' proxy_set_header Connection "";' \ + ' proxy_buffering off;' \ + ' proxy_cache off;' \ + '}' >"$tmp" +/usr/bin/cmp -s "$candidate" "$tmp" || fail CANDIDATE_CONTENT 66 +candidate_sha=$(/usr/bin/sha256sum "$candidate" | /usr/bin/awk '{print $1}') + +target_meta=$("$VM" /usr/bin/stat -c '%U:%G|%a|%F' "$TARGET") +IFS='|' read -r target_owner target_mode target_type <<<"$target_meta" +[[ "$target_owner" == root:root && "$target_mode" == 644 && "$target_type" == regular*file ]] || fail TARGET_METADATA 68 +current_sha=$("$VM" /usr/bin/sha256sum "$TARGET" | /usr/bin/awk '{print $1}') +[[ "$current_sha" == "$expected_current" ]] || fail TARGET_CHANGED 68 + +dir_meta=$("$VM" /usr/bin/stat -c '%U:%G|%a|%F' "$DIR") +IFS='|' read -r dir_owner dir_mode dir_type <<<"$dir_meta" +[[ "$dir_owner" == root:root && "$dir_mode" == 755 && "$dir_type" == directory ]] || fail DIR_METADATA 68 +"$VM" /usr/bin/test -w "$DIR" || fail DIR_NOT_WRITABLE 68 + +"$NG" /usr/local/bin/nginx -t >/dev/null 2>&1 || fail NGINX_CONFIG 69 +[[ "$(/usr/bin/curl -fsS -m5 "http://[PRIVATE_IP]:18788/${cap}/health")" == '{"status":"ok","version":3}' ]] || fail LOCAL_READER 69 +[[ "$("$VM" /usr/bin/curl -fsS -m5 "http://[PRIVATE_IP]:18788/${cap}/health")" == '{"status":"ok","version":3}' ]] || fail EDGE_READER 69 +[[ "$(/usr/bin/curl -sS -m8 --resolve git.gram1.ru:443:[PRIVATE_IP] -o /dev/null -w '%{http_code}' https://git.gram1.ru/)" == 200 ]] || fail GITEA 69 + +printf 'CHANGE_GATE=READY\n' +printf 'CANDIDATE_SHA256=%s\n' "$candidate_sha" +printf 'CURRENT_SHA256=%s\n' "$current_sha" +printf 'TARGET_METADATA=%s\n' "$target_meta" +printf 'TARGET_DIRECTORY_METADATA=%s\n' "$dir_meta" +printf 'NGINX_CURRENT_CONFIG=PASS\n' +printf 'LOCAL_READER_CHECK=PASS\n' +printf 'EDGE_READER_CHECK=PASS\n' +printf 'GITEA_CHECK=PASS\n' +DETAIL=CHANGE_GATE_SOURCE_END +DETAIL=CHANGE_GATE_SOURCE_TRUNCATED=NO +CHANGES_MADE=NO + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index 23d77ce..edc466c 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,19 +1,19 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "READER-APPLY-SOURCE-RECOVERY-DISCOVERY-329", + "command_id": "READER-CHANGE-GATE-INTERFACE-AUDIT-330", "status": "OK", "rc": 0, "host": "pve01", "mode": "read-only", "component": "cluster-audit", - "started_at_utc": "2026-07-23T04:56:34Z", - "finished_at_utc": "2026-07-23T04:56:35Z", + "started_at_utc": "2026-07-23T05:00:00Z", + "finished_at_utc": "2026-07-23T05:00:00Z", "reference_register_checked": true, "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", "error_register_checked": true, "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752", - "command_sha256": "9c4c3254aa732a482e3f75ca8a71d148634fca28840edefff5f6488e672009dd", + "command_sha256": "0c6a6c62888e384581527e16d35802a1835bef622617b27a301d9077cc33f923", "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": "997a8467350ddc4c850296ba5ac10a780c55dd28e280e79a4fe866812467f58a", - "sanitized_output_sha256": "997a8467350ddc4c850296ba5ac10a780c55dd28e280e79a4fe866812467f58a", + "raw_evidence_sha256": "cccc50fe97b2ddc7711107f77a40cbebc700089145145f641d4ae62f19876fdd", + "sanitized_output_sha256": "1c4864ae4d0b36b1d2cf7d1376c7ffa5415174750f0eda9b0201fbb4bb84c1ac", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/test\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/grep\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sort\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/stat\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sha256sum\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/wc\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-INSTALL-323-20260723T041653Z.json|SIZE=2582|LINES=30|SHA256=150a40b8eb69027cb7ff284da4bfc87ea781f7f30ba640b0b5b775c48cbfbbaa|HIT_ID=1|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=1\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-INSTALL-323-20260723T041653Z-latest.txt|SIZE=2108|LINES=49|SHA256=0829491ccc35448dbce4d9d6c832d4ad29455b7e25b2f21dd1a905847572469e|HIT_ID=1|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=1\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-INSTALL-323-20260723T041653Z.txt|SIZE=1323|LINES=25|SHA256=03d0e2cdb20b56190a10bf48316312fa5718af54196df0a16b29f1674fa976ba|HIT_ID=0|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=1\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-LOCAL-ROLLBACK-VERIFY-326-20260723T044355Z.json|SIZE=1543|LINES=30|SHA256=938462f09f07702707298d1ba815ce896bc81c52ad62a0ebb8b0dc242f2de5f5|HIT_ID=0|HIT_TARGET=1|HIT_EXPECTED=0|HIT_ACTUAL=0\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-LOCAL-ROLLBACK-VERIFY-326-20260723T044355Z-latest.txt|SIZE=1087|LINES=31|SHA256=bbf9b685dc2c0d5444d4b10bf3179a729b5ba1220fc2efffc277edf57e102fe4|HIT_ID=0|HIT_TARGET=1|HIT_EXPECTED=0|HIT_ACTUAL=0\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-LOCAL-ROLLBACK-VERIFY-326-20260723T044355Z.txt|SIZE=286|LINES=7|SHA256=4540f8243046e3f1695561ac2ae15bade5a048973e5584a56fa0d6ad24067940|HIT_ID=0|HIT_TARGET=1|HIT_EXPECTED=0|HIT_ACTUAL=0\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/raw/READER-APPLY-HELPER-INSTALL-323-20260723T041653Z.log|SIZE=1323|LINES=25|SHA256=03d0e2cdb20b56190a10bf48316312fa5718af54196df0a16b29f1674fa976ba|HIT_ID=0|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=1\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/raw/READER-APPLY-HELPER-LOCAL-ROLLBACK-VERIFY-326-20260723T044355Z.log|SIZE=286|LINES=7|SHA256=4540f8243046e3f1695561ac2ae15bade5a048973e5584a56fa0d6ad24067940|HIT_ID=0|HIT_TARGET=1|HIT_EXPECTED=0|HIT_ACTUAL=0\nDETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/state/command-ledger.tsv|SIZE=41494|LINES=299|SHA256=1145008db20e1584020d31652467ea7e1b987bc433fc3dcea07792a234347425|HIT_ID=1|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=0\nDETAIL=RECOVERY_CANDIDATE_COUNT=9\nDETAIL=STRONG_SOURCE_CANDIDATE_COUNT=0\nDETAIL=SOURCE_RECOVERY_DISCOVERY=NOT_FOUND\nCHANGES_MADE=NO\n" + "output": "DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/test\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sha256sum\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/awk\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sed\nDETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/bash\nDETAIL=CHANGE_GATE_SHA256=90470653345baac426d1ff6d3e3b1109a611ef7ba8d98b7453be0f732ced3597\nDETAIL=CHANGE_GATE_INTEGRITY=PASS\nDETAIL=CHANGE_GATE_SYNTAX=PASS\nDETAIL=CHANGE_GATE_LINE_COUNT=74\nDETAIL=CHANGE_GATE_SOURCE_BEGIN\n#!/usr/bin/bash\nset -Eeuo pipefail\n\nVM=/usr/local/sbin/homelab-vm130-exec\nNG=/usr/local/sbin/homelab-edge-nginx-exec\nVM_SHA=1959773393723b013af7c93cd29a7b833fd607c903d044e2fcef6accaa29c275\nNG_SHA=f900b15bfdd19a1b543037cf8b9c1583e71dc8115bbb5812cf74d474e3e7859b\nTARGET=/opt/npmplus/custom_nginx/server_proxy.conf\nDIR=/opt/npmplus/custom_nginx\n\nfail() {\n printf 'CHANGE_GATE_ERROR=%s\\n' \"$1\" >&2\n exit \"${2:-1}\"\n}\n\n(( $# == 2 )) || fail USAGE 64\ncandidate=$1\nexpected_current=$2\n\n[[ \"$expected_current\" =~ ^[0-9a-f]{64}$ ]] || fail EXPECTED_SHA 65\n[[ -x \"$VM\" ]] || fail VM_MISSING 69\n[[ -x \"$NG\" ]] || fail NGINX_HELPER_MISSING 69\n[[ \"$(/usr/bin/sha256sum \"$VM\" | /usr/bin/awk '{print $1}')\" == \"$VM_SHA\" ]] || fail VM_INTEGRITY 70\n[[ \"$(/usr/bin/sha256sum \"$NG\" | /usr/bin/awk '{print $1}')\" == \"$NG_SHA\" ]] || fail NGINX_HELPER_INTEGRITY 70\n\n[[ -f \"$candidate\" && ! -L \"$candidate\" ]] || fail CANDIDATE_TYPE 66\nmeta=$(/usr/bin/stat -c '%U:%G|%a|%s' \"$candidate\")\nIFS='|' read -r owner mode size <<<\"$meta\"\n[[ \"$owner\" == root:root && \"$mode\" == 600 ]] || fail CANDIDATE_METADATA 66\n[[ \"$size\" =~ ^[0-9]+$ ]] && (( size > 0 && size <= 8192 )) || fail CANDIDATE_SIZE 66\n\ncap=$(/usr/bin/systemctl show homelab-reader-v3.service -p Environment --value |\n /usr/bin/sed -n 's/.*HOMELAB_READER_CAPABILITY=\\([^ ]*\\).*/\\1/p')\n[[ \"$cap\" =~ ^[0-9a-f]{64}$ ]] || fail CAPABILITY 67\n\ntmp=$(/usr/bin/mktemp)\ntrap '/usr/bin/rm -f -- \"$tmp\"' EXIT\n/usr/bin/printf '%s\\n' \\\n \"location ^~ /.well-known/homelab-reader/${cap}/ {\" \\\n \" proxy_pass http://[PRIVATE_IP]:18788/${cap}/;\" \\\n ' proxy_http_version 1.1;' \\\n ' proxy_set_header Host $host;' \\\n ' proxy_set_header Connection \"\";' \\\n ' proxy_buffering off;' \\\n ' proxy_cache off;' \\\n '}' >\"$tmp\"\n/usr/bin/cmp -s \"$candidate\" \"$tmp\" || fail CANDIDATE_CONTENT 66\ncandidate_sha=$(/usr/bin/sha256sum \"$candidate\" | /usr/bin/awk '{print $1}')\n\ntarget_meta=$(\"$VM\" /usr/bin/stat -c '%U:%G|%a|%F' \"$TARGET\")\nIFS='|' read -r target_owner target_mode target_type <<<\"$target_meta\"\n[[ \"$target_owner\" == root:root && \"$target_mode\" == 644 && \"$target_type\" == regular*file ]] || fail TARGET_METADATA 68\ncurrent_sha=$(\"$VM\" /usr/bin/sha256sum \"$TARGET\" | /usr/bin/awk '{print $1}')\n[[ \"$current_sha\" == \"$expected_current\" ]] || fail TARGET_CHANGED 68\n\ndir_meta=$(\"$VM\" /usr/bin/stat -c '%U:%G|%a|%F' \"$DIR\")\nIFS='|' read -r dir_owner dir_mode dir_type <<<\"$dir_meta\"\n[[ \"$dir_owner\" == root:root && \"$dir_mode\" == 755 && \"$dir_type\" == directory ]] || fail DIR_METADATA 68\n\"$VM\" /usr/bin/test -w \"$DIR\" || fail DIR_NOT_WRITABLE 68\n\n\"$NG\" /usr/local/bin/nginx -t >/dev/null 2>&1 || fail NGINX_CONFIG 69\n[[ \"$(/usr/bin/curl -fsS -m5 \"http://[PRIVATE_IP]:18788/${cap}/health\")\" == '{\"status\":\"ok\",\"version\":3}' ]] || fail LOCAL_READER 69\n[[ \"$(\"$VM\" /usr/bin/curl -fsS -m5 \"http://[PRIVATE_IP]:18788/${cap}/health\")\" == '{\"status\":\"ok\",\"version\":3}' ]] || fail EDGE_READER 69\n[[ \"$(/usr/bin/curl -sS -m8 --resolve git.gram1.ru:443:[PRIVATE_IP] -o /dev/null -w '%{http_code}' https://git.gram1.ru/)\" == 200 ]] || fail GITEA 69\n\nprintf 'CHANGE_GATE=READY\\n'\nprintf 'CANDIDATE_SHA256=%s\\n' \"$candidate_sha\"\nprintf 'CURRENT_SHA256=%s\\n' \"$current_sha\"\nprintf 'TARGET_METADATA=%s\\n' \"$target_meta\"\nprintf 'TARGET_DIRECTORY_METADATA=%s\\n' \"$dir_meta\"\nprintf 'NGINX_CURRENT_CONFIG=PASS\\n'\nprintf 'LOCAL_READER_CHECK=PASS\\n'\nprintf 'EDGE_READER_CHECK=PASS\\n'\nprintf 'GITEA_CHECK=PASS\\n'\nDETAIL=CHANGE_GATE_SOURCE_END\nDETAIL=CHANGE_GATE_SOURCE_TRUNCATED=NO\nCHANGES_MADE=NO\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index 6361900..dbe9b51 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,5 +1,5 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=READER-APPLY-SOURCE-RECOVERY-DISCOVERY-329 +COMMAND_ID=READER-CHANGE-GATE-INTERFACE-AUDIT-330 STATUS=OK RC=0 HOST=pve01 @@ -9,34 +9,102 @@ REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752 -COMMAND_SHA256=9c4c3254aa732a482e3f75ca8a71d148634fca28840edefff5f6488e672009dd +COMMAND_SHA256=0c6a6c62888e384581527e16d35802a1835bef622617b27a301d9077cc33f923 DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGES_MADE=false SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=997a8467350ddc4c850296ba5ac10a780c55dd28e280e79a4fe866812467f58a -SANITIZED_OUTPUT_SHA256=997a8467350ddc4c850296ba5ac10a780c55dd28e280e79a4fe866812467f58a +RAW_EVIDENCE_SHA256=cccc50fe97b2ddc7711107f77a40cbebc700089145145f641d4ae62f19876fdd +SANITIZED_OUTPUT_SHA256=1c4864ae4d0b36b1d2cf7d1376c7ffa5415174750f0eda9b0201fbb4bb84c1ac OUTPUT_BEGIN DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/test -DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/grep -DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sort -DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/stat DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sha256sum -DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/wc -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-INSTALL-323-20260723T041653Z.json|SIZE=2582|LINES=30|SHA256=150a40b8eb69027cb7ff284da4bfc87ea781f7f30ba640b0b5b775c48cbfbbaa|HIT_ID=1|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=1 -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-INSTALL-323-20260723T041653Z-latest.txt|SIZE=2108|LINES=49|SHA256=0829491ccc35448dbce4d9d6c832d4ad29455b7e25b2f21dd1a905847572469e|HIT_ID=1|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=1 -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-INSTALL-323-20260723T041653Z.txt|SIZE=1323|LINES=25|SHA256=03d0e2cdb20b56190a10bf48316312fa5718af54196df0a16b29f1674fa976ba|HIT_ID=0|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=1 -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-LOCAL-ROLLBACK-VERIFY-326-20260723T044355Z.json|SIZE=1543|LINES=30|SHA256=938462f09f07702707298d1ba815ce896bc81c52ad62a0ebb8b0dc242f2de5f5|HIT_ID=0|HIT_TARGET=1|HIT_EXPECTED=0|HIT_ACTUAL=0 -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-LOCAL-ROLLBACK-VERIFY-326-20260723T044355Z-latest.txt|SIZE=1087|LINES=31|SHA256=bbf9b685dc2c0d5444d4b10bf3179a729b5ba1220fc2efffc277edf57e102fe4|HIT_ID=0|HIT_TARGET=1|HIT_EXPECTED=0|HIT_ACTUAL=0 -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/public/READER-APPLY-HELPER-LOCAL-ROLLBACK-VERIFY-326-20260723T044355Z.txt|SIZE=286|LINES=7|SHA256=4540f8243046e3f1695561ac2ae15bade5a048973e5584a56fa0d6ad24067940|HIT_ID=0|HIT_TARGET=1|HIT_EXPECTED=0|HIT_ACTUAL=0 -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/raw/READER-APPLY-HELPER-INSTALL-323-20260723T041653Z.log|SIZE=1323|LINES=25|SHA256=03d0e2cdb20b56190a10bf48316312fa5718af54196df0a16b29f1674fa976ba|HIT_ID=0|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=1 -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/raw/READER-APPLY-HELPER-LOCAL-ROLLBACK-VERIFY-326-20260723T044355Z.log|SIZE=286|LINES=7|SHA256=4540f8243046e3f1695561ac2ae15bade5a048973e5584a56fa0d6ad24067940|HIT_ID=0|HIT_TARGET=1|HIT_EXPECTED=0|HIT_ACTUAL=0 -DETAIL=RECOVERY_CANDIDATE=/var/lib/homelab-chat-run/state/command-ledger.tsv|SIZE=41494|LINES=299|SHA256=1145008db20e1584020d31652467ea7e1b987bc433fc3dcea07792a234347425|HIT_ID=1|HIT_TARGET=0|HIT_EXPECTED=0|HIT_ACTUAL=0 -DETAIL=RECOVERY_CANDIDATE_COUNT=9 -DETAIL=STRONG_SOURCE_CANDIDATE_COUNT=0 -DETAIL=SOURCE_RECOVERY_DISCOVERY=NOT_FOUND +DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/awk +DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/sed +DETAIL=LOCAL_DEPENDENCY=PASS:/usr/bin/bash +DETAIL=CHANGE_GATE_SHA256=90470653345baac426d1ff6d3e3b1109a611ef7ba8d98b7453be0f732ced3597 +DETAIL=CHANGE_GATE_INTEGRITY=PASS +DETAIL=CHANGE_GATE_SYNTAX=PASS +DETAIL=CHANGE_GATE_LINE_COUNT=74 +DETAIL=CHANGE_GATE_SOURCE_BEGIN +#!/usr/bin/bash +set -Eeuo pipefail + +VM=/usr/local/sbin/homelab-vm130-exec +NG=/usr/local/sbin/homelab-edge-nginx-exec +VM_SHA=1959773393723b013af7c93cd29a7b833fd607c903d044e2fcef6accaa29c275 +NG_SHA=f900b15bfdd19a1b543037cf8b9c1583e71dc8115bbb5812cf74d474e3e7859b +TARGET=/opt/npmplus/custom_nginx/server_proxy.conf +DIR=/opt/npmplus/custom_nginx + +fail() { + printf 'CHANGE_GATE_ERROR=%s\n' "$1" >&2 + exit "${2:-1}" +} + +(( $# == 2 )) || fail USAGE 64 +candidate=$1 +expected_current=$2 + +[[ "$expected_current" =~ ^[0-9a-f]{64}$ ]] || fail EXPECTED_SHA 65 +[[ -x "$VM" ]] || fail VM_MISSING 69 +[[ -x "$NG" ]] || fail NGINX_HELPER_MISSING 69 +[[ "$(/usr/bin/sha256sum "$VM" | /usr/bin/awk '{print $1}')" == "$VM_SHA" ]] || fail VM_INTEGRITY 70 +[[ "$(/usr/bin/sha256sum "$NG" | /usr/bin/awk '{print $1}')" == "$NG_SHA" ]] || fail NGINX_HELPER_INTEGRITY 70 + +[[ -f "$candidate" && ! -L "$candidate" ]] || fail CANDIDATE_TYPE 66 +meta=$(/usr/bin/stat -c '%U:%G|%a|%s' "$candidate") +IFS='|' read -r owner mode size <<<"$meta" +[[ "$owner" == root:root && "$mode" == 600 ]] || fail CANDIDATE_METADATA 66 +[[ "$size" =~ ^[0-9]+$ ]] && (( size > 0 && size <= 8192 )) || fail CANDIDATE_SIZE 66 + +cap=$(/usr/bin/systemctl show homelab-reader-v3.service -p Environment --value | + /usr/bin/sed -n 's/.*HOMELAB_READER_CAPABILITY=\([^ ]*\).*/\1/p') +[[ "$cap" =~ ^[0-9a-f]{64}$ ]] || fail CAPABILITY 67 + +tmp=$(/usr/bin/mktemp) +trap '/usr/bin/rm -f -- "$tmp"' EXIT +/usr/bin/printf '%s\n' \ + "location ^~ /.well-known/homelab-reader/${cap}/ {" \ + " proxy_pass http://[PRIVATE_IP]:18788/${cap}/;" \ + ' proxy_http_version 1.1;' \ + ' proxy_set_header Host $host;' \ + ' proxy_set_header Connection "";' \ + ' proxy_buffering off;' \ + ' proxy_cache off;' \ + '}' >"$tmp" +/usr/bin/cmp -s "$candidate" "$tmp" || fail CANDIDATE_CONTENT 66 +candidate_sha=$(/usr/bin/sha256sum "$candidate" | /usr/bin/awk '{print $1}') + +target_meta=$("$VM" /usr/bin/stat -c '%U:%G|%a|%F' "$TARGET") +IFS='|' read -r target_owner target_mode target_type <<<"$target_meta" +[[ "$target_owner" == root:root && "$target_mode" == 644 && "$target_type" == regular*file ]] || fail TARGET_METADATA 68 +current_sha=$("$VM" /usr/bin/sha256sum "$TARGET" | /usr/bin/awk '{print $1}') +[[ "$current_sha" == "$expected_current" ]] || fail TARGET_CHANGED 68 + +dir_meta=$("$VM" /usr/bin/stat -c '%U:%G|%a|%F' "$DIR") +IFS='|' read -r dir_owner dir_mode dir_type <<<"$dir_meta" +[[ "$dir_owner" == root:root && "$dir_mode" == 755 && "$dir_type" == directory ]] || fail DIR_METADATA 68 +"$VM" /usr/bin/test -w "$DIR" || fail DIR_NOT_WRITABLE 68 + +"$NG" /usr/local/bin/nginx -t >/dev/null 2>&1 || fail NGINX_CONFIG 69 +[[ "$(/usr/bin/curl -fsS -m5 "http://[PRIVATE_IP]:18788/${cap}/health")" == '{"status":"ok","version":3}' ]] || fail LOCAL_READER 69 +[[ "$("$VM" /usr/bin/curl -fsS -m5 "http://[PRIVATE_IP]:18788/${cap}/health")" == '{"status":"ok","version":3}' ]] || fail EDGE_READER 69 +[[ "$(/usr/bin/curl -sS -m8 --resolve git.gram1.ru:443:[PRIVATE_IP] -o /dev/null -w '%{http_code}' https://git.gram1.ru/)" == 200 ]] || fail GITEA 69 + +printf 'CHANGE_GATE=READY\n' +printf 'CANDIDATE_SHA256=%s\n' "$candidate_sha" +printf 'CURRENT_SHA256=%s\n' "$current_sha" +printf 'TARGET_METADATA=%s\n' "$target_meta" +printf 'TARGET_DIRECTORY_METADATA=%s\n' "$dir_meta" +printf 'NGINX_CURRENT_CONFIG=PASS\n' +printf 'LOCAL_READER_CHECK=PASS\n' +printf 'EDGE_READER_CHECK=PASS\n' +printf 'GITEA_CHECK=PASS\n' +DETAIL=CHANGE_GATE_SOURCE_END +DETAIL=CHANGE_GATE_SOURCE_TRUNCATED=NO CHANGES_MADE=NO OUTPUT_END