diff --git a/runtime/history/RUNTIME-RECEIVER-FULL-023.json b/runtime/history/RUNTIME-RECEIVER-FULL-023.json new file mode 100644 index 0000000..abade21 --- /dev/null +++ b/runtime/history/RUNTIME-RECEIVER-FULL-023.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "RUNTIME-RECEIVER-FULL-023", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "read-only", + "component": "gitea-runtime", + "started_at_utc": "2026-07-21T09:40:01Z", + "finished_at_utc": "2026-07-21T09:40:01Z", + "reference_register_checked": true, + "reference_sha256": "f6f7749fda946015116cdbbd754c7e7f20356b4a6cf4df330a1b0b8fdf59cbb2", + "error_register_checked": true, + "error_register_sha256": "ab8308549db90d235b591af0581580c3c7ba1b287b129cc6111c2eef0a0f9ecc", + "command_sha256": "d17752c0235202b5d9f1822d70680ea57dd4578bde6bbc906c7569c0d0463bb0", + "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": "2c183b9ced4334e5ff12c1ba35dceb1f7f6ef113298d44bf3fb80ca07305b8b3", + "sanitized_output_sha256": "cd4ccc98c3b9dff7bd1f5557b41fb60d073f889a31f3fd7d86900eecbe15dff4", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "#!/usr/bin/env bash\nset -Eeuo pipefail\numask 027\n\nHOST_DATA='/opt/stacks/gitea/data'\nBARE_CONTAINER='/data/git/repositories/homelab-admin/homelab-public-context.git'\n\nPUBLIC_DIR=\"${HOST_DATA}/gitea/public/.well-known/homelab-runtime\"\nSTAGE_DIR=\"${HOST_DATA}/gitea/runtime-stage\"\nWORK_ROOT=\"${HOST_DATA}/gitea/runtime-work\"\n\nLOCK='/run/lock/homelab-runtime-receive.lock'\n\n[ \"$#\" -eq 3 ] || {\n echo 'RESULT=FAIL'\n echo 'REASON=USAGE'\n exit 64\n}\n\nCOMMAND_ID=\"$1\"\nJSON_FILE=\"$2\"\nTXT_FILE=\"$3\"\n\ncase \"$COMMAND_ID\" in\n ''|*[!A-Za-z0-9._-]*)\n echo 'RESULT=FAIL'\n echo 'REASON=INVALID_COMMAND_ID'\n exit 65\n ;;\nesac\n\n[ -f \"$JSON_FILE\" ] || {\n echo 'RESULT=FAIL'\n echo 'REASON=JSON_FILE_MISSING'\n exit 66\n}\n\n[ -f \"$TXT_FILE\" ] || {\n echo 'RESULT=FAIL'\n echo 'REASON=TXT_FILE_MISSING'\n exit 67\n}\n\nexec 9>\"$LOCK\"\nflock -w 60 9 || {\n echo 'RESULT=FAIL'\n echo 'REASON=RECEIVER_LOCK_TIMEOUT'\n exit 68\n}\n\npython3 - \"$JSON_FILE\" \"$TXT_FILE\" \"$COMMAND_ID\" <<'PY'\nimport json\nimport re\nimport sys\nfrom pathlib import Path\n\njson_path = Path(sys.argv[1])\ntext_path = Path(sys.argv[2])\nexpected_id = sys.argv[3]\n\nif json_path.stat().st_size > 524_288:\n raise SystemExit(\"JSON_TOO_LARGE\")\n\nif text_path.stat().st_size > 1_048_576:\n raise SystemExit(\"TEXT_TOO_LARGE\")\n\njson_text = json_path.read_text(encoding=\"utf-8\")\ntext = text_path.read_text(encoding=\"utf-8\")\n\ndata = json.loads(json_text)\n\nif data.get(\"command_id\") != expected_id:\n raise SystemExit(\"COMMAND_ID_MISMATCH\")\n\nif data.get(\"sanitized\") is not True:\n raise SystemExit(\"SANITIZED_FLAG_REQUIRED\")\n\nif data.get(\"secrets_included\") is not False:\n raise SystemExit(\"SECRETS_FLAG_INVALID\")\n\nif data.get(\"private_addresses_included\") is not False:\n raise SystemExit(\"PRIVATE_ADDRESS_FLAG_INVALID\")\n\ncombined = json_text + \"\\n\" + text\n\npatterns = [\n r\"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\",\n r\"(?i)(password|passwd|passphrase|authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|private[_-]?key)\\s*[:=]\\s*\\S+\",\n r\"(?i)/root/\\.ssh\",\n r\"(?i)[SENSITIVE_PATH]\",\n r\"(?i)rclone\\.conf\",\n r\"\\b10(?:\\.\\d{1,3}){3}\\b\",\n r\"\\b192\\.168(?:\\.\\d{1,3}){2}\\b\",\n r\"\\b172\\.(?:1[6-9]|2\\d|3[01])(?:\\.\\d{1,3}){2}\\b\",\n]\n\nfor pattern in patterns:\n if re.search(pattern, combined):\n raise SystemExit(\"FORBIDDEN_PUBLIC_CONTENT\")\n\nprint(\"PAYLOAD_VALIDATION=OK\")\nPY\n\nGIT_UID=\"$(docker exec gitea id -u git)\"\nGIT_GID=\"$(docker exec gitea id -g git)\"\n\nmkdir -p \\\n \"$PUBLIC_DIR\" \\\n \"$STAGE_DIR\" \\\n \"$WORK_ROOT\"\n\nchown \"$GIT_UID:$GIT_GID\" \\\n \"$STAGE_DIR\" \\\n \"$WORK_ROOT\"\n\ninstall \\\n -o \"$GIT_UID\" \\\n -g \"$GIT_GID\" \\\n -m 0644 \\\n \"$JSON_FILE\" \\\n \"$STAGE_DIR/latest.json\"\n\ninstall \\\n -o \"$GIT_UID\" \\\n -g \"$GIT_GID\" \\\n -m 0644 \\\n \"$TXT_FILE\" \\\n \"$STAGE_DIR/latest.txt\"\n\ncat > \"$STAGE_DIR/README.md\" <<'DOC'\n# Homelab assistant runtime\n\nSanitized command results for read-only assistant inspection.\n\nCredentials, authentication data, private keys, private IP addresses and\nunfiltered configuration files are prohibited.\nDOC\n\nchown \"$GIT_UID:$GIT_GID\" \"$STAGE_DIR/README.md\"\nchmod 0644 \"$STAGE_DIR/README.md\"\n\nPUBLISHED_AT=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\nWORK_CONTAINER=\"/data/gitea/runtime-work/${COMMAND_ID}.$$\"\n\nCOMMIT_SHA=\"$(\n docker exec \\\n -u \"${GIT_UID}:${GIT_GID}\" \\\n -e COMMAND_ID=\"$COMMAND_ID\" \\\n -e PUBLISHED_AT=\"$PUBLISHED_AT\" \\\n -e WORK_CONTAINER=\"$WORK_CONTAINER\" \\\n gitea sh -lc '\nset -eu\n\nBARE=\"/data/git/repositories/homelab-admin/homelab-public-context.git\"\nSTAGE=\"/data/gitea/runtime-stage\"\nWORK=\"$WORK_CONTAINER\"\n\nrm -rf \"$WORK\"\n\ngit clone --quiet \"$BARE\" \"$WORK\"\n\ncd \"$WORK\"\n\ngit config user.name \"homelab-runtime-publisher\"\ngit config user.email \"homelab-runtime@localhost\"\n\nif git show-ref \\\n --verify \\\n --quiet \\\n refs/remotes/origin/assistant-runtime\nthen\n git checkout \\\n --quiet \\\n -B assistant-runtime \\\n origin/assistant-runtime\nelse\n git checkout \\\n --quiet \\\n --orphan assistant-runtime\n\n git rm -rf . >/dev/null 2>&1 || true\nfi\n\nmkdir -p runtime/history\n\ncp \"$STAGE/latest.json\" runtime/latest.json\ncp \"$STAGE/latest.txt\" runtime/latest.txt\ncp \"$STAGE/latest.json\" \"runtime/history/${COMMAND_ID}.json\"\ncp \"$STAGE/latest.txt\" \"runtime/history/${COMMAND_ID}.txt\"\ncp \"$STAGE/README.md\" README.md\n\ngit add \\\n README.md \\\n runtime/latest.json \\\n runtime/latest.txt \\\n \"runtime/history/${COMMAND_ID}.json\"\n\ngit add \"runtime/history/${COMMAND_ID}.txt\"\n\nif ! git diff --cached --quiet\nthen\n GIT_AUTHOR_DATE=\"$PUBLISHED_AT\" \\\n GIT_COMMITTER_DATE=\"$PUBLISHED_AT\" \\\n git commit \\\n --quiet \\\n -m \"runtime: publish ${COMMAND_ID}\"\nfi\n\nCOMMIT=\"$(git rev-parse HEAD)\"\n\ngit --git-dir=\"$BARE\" \\\n fetch \\\n --quiet \\\n \"$WORK\" \\\n refs/heads/assistant-runtime\n\nOLD=\"$(\n git --git-dir=\"$BARE\" \\\n rev-parse refs/heads/assistant-runtime \\\n 2>/dev/null ||\n true\n)\"\n\nif [ -n \"$OLD\" ]\nthen\n git --git-dir=\"$BARE\" \\\n update-ref \\\n refs/heads/assistant-runtime \\\n \"$COMMIT\" \\\n \"$OLD\"\nelse\n git --git-dir=\"$BARE\" \\\n update-ref \\\n refs/heads/assistant-runtime \\\n \"$COMMIT\"\nfi\n\nrm -rf \"$WORK\"\n\nprintf \"%s\\n\" \"$COMMIT\"\n'\n)\"\n\nJSON_TMP=\"$(mktemp \"${PUBLIC_DIR}/.latest.json.XXXXXX\")\"\nTXT_TMP=\"$(mktemp \"${PUBLIC_DIR}/.latest.txt.XXXXXX\")\"\nINDEX_TMP=\"$(mktemp \"${PUBLIC_DIR}/.index.json.XXXXXX\")\"\n\ninstall -m 0644 \"$JSON_FILE\" \"$JSON_TMP\"\ninstall -m 0644 \"$TXT_FILE\" \"$TXT_TMP\"\n\npython3 - \\\n \"$COMMAND_ID\" \\\n \"$PUBLISHED_AT\" \\\n \"$COMMIT_SHA\" >\"$INDEX_TMP\" <<'PY'\nimport json\nimport sys\n\ncommand_id, published_at, commit_sha = sys.argv[1:4]\n\nprint(json.dumps({\n \"schema_version\": 1,\n \"channel\": \"homelab-runtime\",\n \"branch\": \"assistant-runtime\",\n \"latest_command_id\": command_id,\n \"published_at_utc\": published_at,\n \"commit_sha\": commit_sha,\n \"latest_json_url\": (\n \"https://git.gram1.ru/.well-known/\"\n \"homelab-runtime/latest.json\"\n ),\n \"latest_text_url\": (\n \"https://git.gram1.ru/.well-known/\"\n \"homelab-runtime/latest.txt\"\n )\n}, ensure_ascii=False, indent=2))\nPY\n\nchmod 0644 \"$INDEX_TMP\"\n\nmv -f \"$JSON_TMP\" \"$PUBLIC_DIR/latest.json\"\nmv -f \"$TXT_TMP\" \"$PUBLIC_DIR/latest.txt\"\nmv -f \"$INDEX_TMP\" \"$PUBLIC_DIR/index.json\"\n\ncurl -fsS \\\n --max-time 10 \\\n http://127.0.0.1:3002/.well-known/homelab-runtime/latest.json |\ngrep -F \"$COMMAND_ID\" >/dev/null\n\ncurl -fsS \\\n --max-time 10 \\\n \"http://127.0.0.1:3002/homelab-admin/homelab-public-context/raw/branch/assistant-runtime/runtime/latest.json\" |\ngrep -F \"$COMMAND_ID\" >/dev/null\n\necho 'RESULT=OK'\necho \"COMMAND_ID=$COMMAND_ID\"\necho \"COMMIT_SHA=$COMMIT_SHA\"\necho 'STATIC_PUBLICATION=OK'\necho 'RAW_BRANCH_PUBLICATION=OK'\n" +} diff --git a/runtime/history/RUNTIME-RECEIVER-FULL-023.txt b/runtime/history/RUNTIME-RECEIVER-FULL-023.txt new file mode 100644 index 0000000..7df71a8 --- /dev/null +++ b/runtime/history/RUNTIME-RECEIVER-FULL-023.txt @@ -0,0 +1,322 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=RUNTIME-RECEIVER-FULL-023 +STATUS=OK +RC=0 +HOST=pve01 +MODE=read-only +COMPONENT=gitea-runtime +REFERENCE_REGISTER_CHECK=OK +REFERENCE_SHA256=f6f7749fda946015116cdbbd754c7e7f20356b4a6cf4df330a1b0b8fdf59cbb2 +ERROR_REGISTER_CHECK=OK +ERROR_REGISTER_SHA256=ab8308549db90d235b591af0581580c3c7ba1b287b129cc6111c2eef0a0f9ecc +COMMAND_SHA256=d17752c0235202b5d9f1822d70680ea57dd4578bde6bbc906c7569c0d0463bb0 +DUPLICATE_FAILED_COMMAND_BLOCKED=false +EXECUTION_STARTED=true +CHANGES_MADE=false +SANITIZED=yes +SECRETS_INCLUDED=no +PRIVATE_ADDRESSES_INCLUDED=no +RAW_EVIDENCE_SHA256=2c183b9ced4334e5ff12c1ba35dceb1f7f6ef113298d44bf3fb80ca07305b8b3 +SANITIZED_OUTPUT_SHA256=cd4ccc98c3b9dff7bd1f5557b41fb60d073f889a31f3fd7d86900eecbe15dff4 +OUTPUT_BEGIN +#!/usr/bin/env bash +set -Eeuo pipefail +umask 027 + +HOST_DATA='/opt/stacks/gitea/data' +BARE_CONTAINER='/data/git/repositories/homelab-admin/homelab-public-context.git' + +PUBLIC_DIR="${HOST_DATA}/gitea/public/.well-known/homelab-runtime" +STAGE_DIR="${HOST_DATA}/gitea/runtime-stage" +WORK_ROOT="${HOST_DATA}/gitea/runtime-work" + +LOCK='/run/lock/homelab-runtime-receive.lock' + +[ "$#" -eq 3 ] || { + echo 'RESULT=FAIL' + echo 'REASON=USAGE' + exit 64 +} + +COMMAND_ID="$1" +JSON_FILE="$2" +TXT_FILE="$3" + +case "$COMMAND_ID" in + ''|*[!A-Za-z0-9._-]*) + echo 'RESULT=FAIL' + echo 'REASON=INVALID_COMMAND_ID' + exit 65 + ;; +esac + +[ -f "$JSON_FILE" ] || { + echo 'RESULT=FAIL' + echo 'REASON=JSON_FILE_MISSING' + exit 66 +} + +[ -f "$TXT_FILE" ] || { + echo 'RESULT=FAIL' + echo 'REASON=TXT_FILE_MISSING' + exit 67 +} + +exec 9>"$LOCK" +flock -w 60 9 || { + echo 'RESULT=FAIL' + echo 'REASON=RECEIVER_LOCK_TIMEOUT' + exit 68 +} + +python3 - "$JSON_FILE" "$TXT_FILE" "$COMMAND_ID" <<'PY' +import json +import re +import sys +from pathlib import Path + +json_path = Path(sys.argv[1]) +text_path = Path(sys.argv[2]) +expected_id = sys.argv[3] + +if json_path.stat().st_size > 524_288: + raise SystemExit("JSON_TOO_LARGE") + +if text_path.stat().st_size > 1_048_576: + raise SystemExit("TEXT_TOO_LARGE") + +json_text = json_path.read_text(encoding="utf-8") +text = text_path.read_text(encoding="utf-8") + +data = json.loads(json_text) + +if data.get("command_id") != expected_id: + raise SystemExit("COMMAND_ID_MISMATCH") + +if data.get("sanitized") is not True: + raise SystemExit("SANITIZED_FLAG_REQUIRED") + +if data.get("secrets_included") is not False: + raise SystemExit("SECRETS_FLAG_INVALID") + +if data.get("private_addresses_included") is not False: + raise SystemExit("PRIVATE_ADDRESS_FLAG_INVALID") + +combined = json_text + "\n" + text + +patterns = [ + r"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----", + r"(?i)(password|passwd|passphrase|authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|private[_-]?key)\s*[:=]\s*\S+", + r"(?i)/root/\.ssh", + r"(?i)[SENSITIVE_PATH]", + r"(?i)rclone\.conf", + r"\b10(?:\.\d{1,3}){3}\b", + r"\b192\.168(?:\.\d{1,3}){2}\b", + r"\b172\.(?:1[6-9]|2\d|3[01])(?:\.\d{1,3}){2}\b", +] + +for pattern in patterns: + if re.search(pattern, combined): + raise SystemExit("FORBIDDEN_PUBLIC_CONTENT") + +print("PAYLOAD_VALIDATION=OK") +PY + +GIT_UID="$(docker exec gitea id -u git)" +GIT_GID="$(docker exec gitea id -g git)" + +mkdir -p \ + "$PUBLIC_DIR" \ + "$STAGE_DIR" \ + "$WORK_ROOT" + +chown "$GIT_UID:$GIT_GID" \ + "$STAGE_DIR" \ + "$WORK_ROOT" + +install \ + -o "$GIT_UID" \ + -g "$GIT_GID" \ + -m 0644 \ + "$JSON_FILE" \ + "$STAGE_DIR/latest.json" + +install \ + -o "$GIT_UID" \ + -g "$GIT_GID" \ + -m 0644 \ + "$TXT_FILE" \ + "$STAGE_DIR/latest.txt" + +cat > "$STAGE_DIR/README.md" <<'DOC' +# Homelab assistant runtime + +Sanitized command results for read-only assistant inspection. + +Credentials, authentication data, private keys, private IP addresses and +unfiltered configuration files are prohibited. +DOC + +chown "$GIT_UID:$GIT_GID" "$STAGE_DIR/README.md" +chmod 0644 "$STAGE_DIR/README.md" + +PUBLISHED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +WORK_CONTAINER="/data/gitea/runtime-work/${COMMAND_ID}.$$" + +COMMIT_SHA="$( + docker exec \ + -u "${GIT_UID}:${GIT_GID}" \ + -e COMMAND_ID="$COMMAND_ID" \ + -e PUBLISHED_AT="$PUBLISHED_AT" \ + -e WORK_CONTAINER="$WORK_CONTAINER" \ + gitea sh -lc ' +set -eu + +BARE="/data/git/repositories/homelab-admin/homelab-public-context.git" +STAGE="/data/gitea/runtime-stage" +WORK="$WORK_CONTAINER" + +rm -rf "$WORK" + +git clone --quiet "$BARE" "$WORK" + +cd "$WORK" + +git config user.name "homelab-runtime-publisher" +git config user.email "homelab-runtime@localhost" + +if git show-ref \ + --verify \ + --quiet \ + refs/remotes/origin/assistant-runtime +then + git checkout \ + --quiet \ + -B assistant-runtime \ + origin/assistant-runtime +else + git checkout \ + --quiet \ + --orphan assistant-runtime + + git rm -rf . >/dev/null 2>&1 || true +fi + +mkdir -p runtime/history + +cp "$STAGE/latest.json" runtime/latest.json +cp "$STAGE/latest.txt" runtime/latest.txt +cp "$STAGE/latest.json" "runtime/history/${COMMAND_ID}.json" +cp "$STAGE/latest.txt" "runtime/history/${COMMAND_ID}.txt" +cp "$STAGE/README.md" README.md + +git add \ + README.md \ + runtime/latest.json \ + runtime/latest.txt \ + "runtime/history/${COMMAND_ID}.json" + +git add "runtime/history/${COMMAND_ID}.txt" + +if ! git diff --cached --quiet +then + GIT_AUTHOR_DATE="$PUBLISHED_AT" \ + GIT_COMMITTER_DATE="$PUBLISHED_AT" \ + git commit \ + --quiet \ + -m "runtime: publish ${COMMAND_ID}" +fi + +COMMIT="$(git rev-parse HEAD)" + +git --git-dir="$BARE" \ + fetch \ + --quiet \ + "$WORK" \ + refs/heads/assistant-runtime + +OLD="$( + git --git-dir="$BARE" \ + rev-parse refs/heads/assistant-runtime \ + 2>/dev/null || + true +)" + +if [ -n "$OLD" ] +then + git --git-dir="$BARE" \ + update-ref \ + refs/heads/assistant-runtime \ + "$COMMIT" \ + "$OLD" +else + git --git-dir="$BARE" \ + update-ref \ + refs/heads/assistant-runtime \ + "$COMMIT" +fi + +rm -rf "$WORK" + +printf "%s\n" "$COMMIT" +' +)" + +JSON_TMP="$(mktemp "${PUBLIC_DIR}/.latest.json.XXXXXX")" +TXT_TMP="$(mktemp "${PUBLIC_DIR}/.latest.txt.XXXXXX")" +INDEX_TMP="$(mktemp "${PUBLIC_DIR}/.index.json.XXXXXX")" + +install -m 0644 "$JSON_FILE" "$JSON_TMP" +install -m 0644 "$TXT_FILE" "$TXT_TMP" + +python3 - \ + "$COMMAND_ID" \ + "$PUBLISHED_AT" \ + "$COMMIT_SHA" >"$INDEX_TMP" <<'PY' +import json +import sys + +command_id, published_at, commit_sha = sys.argv[1:4] + +print(json.dumps({ + "schema_version": 1, + "channel": "homelab-runtime", + "branch": "assistant-runtime", + "latest_command_id": command_id, + "published_at_utc": published_at, + "commit_sha": commit_sha, + "latest_json_url": ( + "https://git.gram1.ru/.well-known/" + "homelab-runtime/latest.json" + ), + "latest_text_url": ( + "https://git.gram1.ru/.well-known/" + "homelab-runtime/latest.txt" + ) +}, ensure_ascii=False, indent=2)) +PY + +chmod 0644 "$INDEX_TMP" + +mv -f "$JSON_TMP" "$PUBLIC_DIR/latest.json" +mv -f "$TXT_TMP" "$PUBLIC_DIR/latest.txt" +mv -f "$INDEX_TMP" "$PUBLIC_DIR/index.json" + +curl -fsS \ + --max-time 10 \ + http://127.0.0.1:3002/.well-known/homelab-runtime/latest.json | +grep -F "$COMMAND_ID" >/dev/null + +curl -fsS \ + --max-time 10 \ + "http://127.0.0.1:3002/homelab-admin/homelab-public-context/raw/branch/assistant-runtime/runtime/latest.json" | +grep -F "$COMMAND_ID" >/dev/null + +echo 'RESULT=OK' +echo "COMMAND_ID=$COMMAND_ID" +echo "COMMIT_SHA=$COMMIT_SHA" +echo 'STATIC_PUBLICATION=OK' +echo 'RAW_BRANCH_PUBLICATION=OK' + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index cd359cd..abade21 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,19 +1,19 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "BOOTSTRAP-FILE-DIAG-002", + "command_id": "RUNTIME-RECEIVER-FULL-023", "status": "OK", "rc": 0, "host": "pve01", "mode": "read-only", - "component": "gitea-bootstrap", - "started_at_utc": "2026-07-21T09:32:47Z", - "finished_at_utc": "2026-07-21T09:32:47Z", + "component": "gitea-runtime", + "started_at_utc": "2026-07-21T09:40:01Z", + "finished_at_utc": "2026-07-21T09:40:01Z", "reference_register_checked": true, "reference_sha256": "f6f7749fda946015116cdbbd754c7e7f20356b4a6cf4df330a1b0b8fdf59cbb2", "error_register_checked": true, "error_register_sha256": "ab8308549db90d235b591af0581580c3c7ba1b287b129cc6111c2eef0a0f9ecc", - "command_sha256": "ff7fad42e98aa003067d7496afc43ad2c9ad5fe91eb84b8eb79aeb41674bb1be", + "command_sha256": "d17752c0235202b5d9f1822d70680ea57dd4578bde6bbc906c7569c0d0463bb0", "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": "2c25590ae8d63b455ecfea329a8495fa57f04ba43113a348dace1265c58ce33e", - "sanitized_output_sha256": "2c25590ae8d63b455ecfea329a8495fa57f04ba43113a348dace1265c58ce33e", + "raw_evidence_sha256": "2c183b9ced4334e5ff12c1ba35dceb1f7f6ef113298d44bf3fb80ca07305b8b3", + "sanitized_output_sha256": "cd4ccc98c3b9dff7bd1f5557b41fb60d073f889a31f3fd7d86900eecbe15dff4", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "{\n \"schema_version\": 2,\n \"cluster_id\": \"homelab\",\n \"status\": \"READY\",\n \"generated_at_utc\": \"2026-07-21T07:02:17Z\",\n \"context\": {\n \"full_context_command_id\": \"CONTEXT-SOURCES-FULL-002\",\n \"full_context_commit\": \"e23caf794cc68ce5fa6f8922efa7f2a35c8aa6e0\",\n \"full_context_sha256\": \"621830f58b028a0116a42964d02bdca31c280d6ff358f518d0e8f24c2ba01366\",\n \"full_context_url\": \"https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/e23caf794cc68ce5fa6f8922efa7f2a35c8aa6e0/runtime/history/CONTEXT-SOURCES-FULL-002.txt\",\n \"context_index_command_id\": \"CONTEXT-INDEX-001\",\n \"context_index_commit\": \"055521f14fbb0780bdb501c7d7be755350d45091\",\n \"context_index_url\": \"https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/055521f14fbb0780bdb501c7d7be755350d45091/runtime/history/CONTEXT-INDEX-001.json\",\n \"reference_sha256\": \"f6f7749fda946015116cdbbd754c7e7f20356b4a6cf4df330a1b0b8fdf59cbb2\",\n \"error_register_sha256\": \"ab8308549db90d235b591af0581580c3c7ba1b287b129cc6111c2eef0a0f9ecc\",\n \"error_register_embedded_in_full_context\": true\n },\n \"runtime\": {\n \"history_url\": \"https://git.gram1.ru/homelab-admin/homelab-public-context/src/branch/assistant-runtime/runtime/history\",\n \"latest_branch_url\": \"https://git.gram1.ru/homelab-admin/homelab-public-context/raw/branch/assistant-runtime/runtime/latest.json\",\n \"result_confirmation\": \"immutable_history_by_command_id\",\n \"latest_json_is_authoritative\": false\n },\n \"operating_contract\": {\n \"load_bootstrap_before_commands\": true,\n \"load_error_register_before_commands\": true,\n \"check_previous_command_result\": true,\n \"reject_known_failed_exact_repeats\": true,\n \"one_command_per_step\": true,\n \"manual_terminal_output_required\": false,\n \"runner\": \"homelab-chat-run\",\n \"confirmation_tokens\": [\n \".\",\n \",\",\n \"\\\\\"\n ],\n \"immediate_next_command\": true,\n \"command_display\": \"collapsible_details\",\n \"double_pre_command_check\": true\n },\n \"privacy\": {\n \"sanitized\": true,\n \"secrets_included\": false,\n \"private_addresses_included\": false\n },\n \"entrypoints\": {\n \"full_context_url\": \"https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/e23caf794cc68ce5fa6f8922efa7f2a35c8aa6e0/runtime/history/CONTEXT-SOURCES-FULL-002.txt\",\n \"errors_index_url\": \"https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/a615069de3d32564fc4de29baff949bdaf811caf/runtime/history/ERRORS-INDEX-004.json\",\n \"workflow_contract_url\": \"https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/2f37a4eb600528d03f5c570af8c5aa0e463b1798/runtime/history/WORKFLOW-CONTRACT-003.json\",\n \"double_check_rule_url\": \"https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/d1061e47e7955dba9c73a2841d4eacf02ccc1bf5/runtime/policy/double-check-rule.json\"\n },\n \"freshness\": {\n \"max_age_seconds\": 86400,\n \"stale_requires_refresh\": true\n },\n \"coverage\": {\n \"status\": \"PARTIAL\",\n \"missing\": [\n \"automatic_refresh\",\n \"per_node_freshness\",\n \"structured_service_inventory\"\n ]\n }\n}\n" + "output": "#!/usr/bin/env bash\nset -Eeuo pipefail\numask 027\n\nHOST_DATA='/opt/stacks/gitea/data'\nBARE_CONTAINER='/data/git/repositories/homelab-admin/homelab-public-context.git'\n\nPUBLIC_DIR=\"${HOST_DATA}/gitea/public/.well-known/homelab-runtime\"\nSTAGE_DIR=\"${HOST_DATA}/gitea/runtime-stage\"\nWORK_ROOT=\"${HOST_DATA}/gitea/runtime-work\"\n\nLOCK='/run/lock/homelab-runtime-receive.lock'\n\n[ \"$#\" -eq 3 ] || {\n echo 'RESULT=FAIL'\n echo 'REASON=USAGE'\n exit 64\n}\n\nCOMMAND_ID=\"$1\"\nJSON_FILE=\"$2\"\nTXT_FILE=\"$3\"\n\ncase \"$COMMAND_ID\" in\n ''|*[!A-Za-z0-9._-]*)\n echo 'RESULT=FAIL'\n echo 'REASON=INVALID_COMMAND_ID'\n exit 65\n ;;\nesac\n\n[ -f \"$JSON_FILE\" ] || {\n echo 'RESULT=FAIL'\n echo 'REASON=JSON_FILE_MISSING'\n exit 66\n}\n\n[ -f \"$TXT_FILE\" ] || {\n echo 'RESULT=FAIL'\n echo 'REASON=TXT_FILE_MISSING'\n exit 67\n}\n\nexec 9>\"$LOCK\"\nflock -w 60 9 || {\n echo 'RESULT=FAIL'\n echo 'REASON=RECEIVER_LOCK_TIMEOUT'\n exit 68\n}\n\npython3 - \"$JSON_FILE\" \"$TXT_FILE\" \"$COMMAND_ID\" <<'PY'\nimport json\nimport re\nimport sys\nfrom pathlib import Path\n\njson_path = Path(sys.argv[1])\ntext_path = Path(sys.argv[2])\nexpected_id = sys.argv[3]\n\nif json_path.stat().st_size > 524_288:\n raise SystemExit(\"JSON_TOO_LARGE\")\n\nif text_path.stat().st_size > 1_048_576:\n raise SystemExit(\"TEXT_TOO_LARGE\")\n\njson_text = json_path.read_text(encoding=\"utf-8\")\ntext = text_path.read_text(encoding=\"utf-8\")\n\ndata = json.loads(json_text)\n\nif data.get(\"command_id\") != expected_id:\n raise SystemExit(\"COMMAND_ID_MISMATCH\")\n\nif data.get(\"sanitized\") is not True:\n raise SystemExit(\"SANITIZED_FLAG_REQUIRED\")\n\nif data.get(\"secrets_included\") is not False:\n raise SystemExit(\"SECRETS_FLAG_INVALID\")\n\nif data.get(\"private_addresses_included\") is not False:\n raise SystemExit(\"PRIVATE_ADDRESS_FLAG_INVALID\")\n\ncombined = json_text + \"\\n\" + text\n\npatterns = [\n r\"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\",\n r\"(?i)(password|passwd|passphrase|authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|private[_-]?key)\\s*[:=]\\s*\\S+\",\n r\"(?i)/root/\\.ssh\",\n r\"(?i)[SENSITIVE_PATH]\",\n r\"(?i)rclone\\.conf\",\n r\"\\b10(?:\\.\\d{1,3}){3}\\b\",\n r\"\\b192\\.168(?:\\.\\d{1,3}){2}\\b\",\n r\"\\b172\\.(?:1[6-9]|2\\d|3[01])(?:\\.\\d{1,3}){2}\\b\",\n]\n\nfor pattern in patterns:\n if re.search(pattern, combined):\n raise SystemExit(\"FORBIDDEN_PUBLIC_CONTENT\")\n\nprint(\"PAYLOAD_VALIDATION=OK\")\nPY\n\nGIT_UID=\"$(docker exec gitea id -u git)\"\nGIT_GID=\"$(docker exec gitea id -g git)\"\n\nmkdir -p \\\n \"$PUBLIC_DIR\" \\\n \"$STAGE_DIR\" \\\n \"$WORK_ROOT\"\n\nchown \"$GIT_UID:$GIT_GID\" \\\n \"$STAGE_DIR\" \\\n \"$WORK_ROOT\"\n\ninstall \\\n -o \"$GIT_UID\" \\\n -g \"$GIT_GID\" \\\n -m 0644 \\\n \"$JSON_FILE\" \\\n \"$STAGE_DIR/latest.json\"\n\ninstall \\\n -o \"$GIT_UID\" \\\n -g \"$GIT_GID\" \\\n -m 0644 \\\n \"$TXT_FILE\" \\\n \"$STAGE_DIR/latest.txt\"\n\ncat > \"$STAGE_DIR/README.md\" <<'DOC'\n# Homelab assistant runtime\n\nSanitized command results for read-only assistant inspection.\n\nCredentials, authentication data, private keys, private IP addresses and\nunfiltered configuration files are prohibited.\nDOC\n\nchown \"$GIT_UID:$GIT_GID\" \"$STAGE_DIR/README.md\"\nchmod 0644 \"$STAGE_DIR/README.md\"\n\nPUBLISHED_AT=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\nWORK_CONTAINER=\"/data/gitea/runtime-work/${COMMAND_ID}.$$\"\n\nCOMMIT_SHA=\"$(\n docker exec \\\n -u \"${GIT_UID}:${GIT_GID}\" \\\n -e COMMAND_ID=\"$COMMAND_ID\" \\\n -e PUBLISHED_AT=\"$PUBLISHED_AT\" \\\n -e WORK_CONTAINER=\"$WORK_CONTAINER\" \\\n gitea sh -lc '\nset -eu\n\nBARE=\"/data/git/repositories/homelab-admin/homelab-public-context.git\"\nSTAGE=\"/data/gitea/runtime-stage\"\nWORK=\"$WORK_CONTAINER\"\n\nrm -rf \"$WORK\"\n\ngit clone --quiet \"$BARE\" \"$WORK\"\n\ncd \"$WORK\"\n\ngit config user.name \"homelab-runtime-publisher\"\ngit config user.email \"homelab-runtime@localhost\"\n\nif git show-ref \\\n --verify \\\n --quiet \\\n refs/remotes/origin/assistant-runtime\nthen\n git checkout \\\n --quiet \\\n -B assistant-runtime \\\n origin/assistant-runtime\nelse\n git checkout \\\n --quiet \\\n --orphan assistant-runtime\n\n git rm -rf . >/dev/null 2>&1 || true\nfi\n\nmkdir -p runtime/history\n\ncp \"$STAGE/latest.json\" runtime/latest.json\ncp \"$STAGE/latest.txt\" runtime/latest.txt\ncp \"$STAGE/latest.json\" \"runtime/history/${COMMAND_ID}.json\"\ncp \"$STAGE/latest.txt\" \"runtime/history/${COMMAND_ID}.txt\"\ncp \"$STAGE/README.md\" README.md\n\ngit add \\\n README.md \\\n runtime/latest.json \\\n runtime/latest.txt \\\n \"runtime/history/${COMMAND_ID}.json\"\n\ngit add \"runtime/history/${COMMAND_ID}.txt\"\n\nif ! git diff --cached --quiet\nthen\n GIT_AUTHOR_DATE=\"$PUBLISHED_AT\" \\\n GIT_COMMITTER_DATE=\"$PUBLISHED_AT\" \\\n git commit \\\n --quiet \\\n -m \"runtime: publish ${COMMAND_ID}\"\nfi\n\nCOMMIT=\"$(git rev-parse HEAD)\"\n\ngit --git-dir=\"$BARE\" \\\n fetch \\\n --quiet \\\n \"$WORK\" \\\n refs/heads/assistant-runtime\n\nOLD=\"$(\n git --git-dir=\"$BARE\" \\\n rev-parse refs/heads/assistant-runtime \\\n 2>/dev/null ||\n true\n)\"\n\nif [ -n \"$OLD\" ]\nthen\n git --git-dir=\"$BARE\" \\\n update-ref \\\n refs/heads/assistant-runtime \\\n \"$COMMIT\" \\\n \"$OLD\"\nelse\n git --git-dir=\"$BARE\" \\\n update-ref \\\n refs/heads/assistant-runtime \\\n \"$COMMIT\"\nfi\n\nrm -rf \"$WORK\"\n\nprintf \"%s\\n\" \"$COMMIT\"\n'\n)\"\n\nJSON_TMP=\"$(mktemp \"${PUBLIC_DIR}/.latest.json.XXXXXX\")\"\nTXT_TMP=\"$(mktemp \"${PUBLIC_DIR}/.latest.txt.XXXXXX\")\"\nINDEX_TMP=\"$(mktemp \"${PUBLIC_DIR}/.index.json.XXXXXX\")\"\n\ninstall -m 0644 \"$JSON_FILE\" \"$JSON_TMP\"\ninstall -m 0644 \"$TXT_FILE\" \"$TXT_TMP\"\n\npython3 - \\\n \"$COMMAND_ID\" \\\n \"$PUBLISHED_AT\" \\\n \"$COMMIT_SHA\" >\"$INDEX_TMP\" <<'PY'\nimport json\nimport sys\n\ncommand_id, published_at, commit_sha = sys.argv[1:4]\n\nprint(json.dumps({\n \"schema_version\": 1,\n \"channel\": \"homelab-runtime\",\n \"branch\": \"assistant-runtime\",\n \"latest_command_id\": command_id,\n \"published_at_utc\": published_at,\n \"commit_sha\": commit_sha,\n \"latest_json_url\": (\n \"https://git.gram1.ru/.well-known/\"\n \"homelab-runtime/latest.json\"\n ),\n \"latest_text_url\": (\n \"https://git.gram1.ru/.well-known/\"\n \"homelab-runtime/latest.txt\"\n )\n}, ensure_ascii=False, indent=2))\nPY\n\nchmod 0644 \"$INDEX_TMP\"\n\nmv -f \"$JSON_TMP\" \"$PUBLIC_DIR/latest.json\"\nmv -f \"$TXT_TMP\" \"$PUBLIC_DIR/latest.txt\"\nmv -f \"$INDEX_TMP\" \"$PUBLIC_DIR/index.json\"\n\ncurl -fsS \\\n --max-time 10 \\\n http://127.0.0.1:3002/.well-known/homelab-runtime/latest.json |\ngrep -F \"$COMMAND_ID\" >/dev/null\n\ncurl -fsS \\\n --max-time 10 \\\n \"http://127.0.0.1:3002/homelab-admin/homelab-public-context/raw/branch/assistant-runtime/runtime/latest.json\" |\ngrep -F \"$COMMAND_ID\" >/dev/null\n\necho 'RESULT=OK'\necho \"COMMAND_ID=$COMMAND_ID\"\necho \"COMMIT_SHA=$COMMIT_SHA\"\necho 'STATIC_PUBLICATION=OK'\necho 'RAW_BRANCH_PUBLICATION=OK'\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index 7a11014..7df71a8 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,88 +1,322 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=BOOTSTRAP-FILE-DIAG-002 +COMMAND_ID=RUNTIME-RECEIVER-FULL-023 STATUS=OK RC=0 HOST=pve01 MODE=read-only -COMPONENT=gitea-bootstrap +COMPONENT=gitea-runtime REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=f6f7749fda946015116cdbbd754c7e7f20356b4a6cf4df330a1b0b8fdf59cbb2 ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=ab8308549db90d235b591af0581580c3c7ba1b287b129cc6111c2eef0a0f9ecc -COMMAND_SHA256=ff7fad42e98aa003067d7496afc43ad2c9ad5fe91eb84b8eb79aeb41674bb1be +COMMAND_SHA256=d17752c0235202b5d9f1822d70680ea57dd4578bde6bbc906c7569c0d0463bb0 DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGES_MADE=false SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=2c25590ae8d63b455ecfea329a8495fa57f04ba43113a348dace1265c58ce33e -SANITIZED_OUTPUT_SHA256=2c25590ae8d63b455ecfea329a8495fa57f04ba43113a348dace1265c58ce33e +RAW_EVIDENCE_SHA256=2c183b9ced4334e5ff12c1ba35dceb1f7f6ef113298d44bf3fb80ca07305b8b3 +SANITIZED_OUTPUT_SHA256=cd4ccc98c3b9dff7bd1f5557b41fb60d073f889a31f3fd7d86900eecbe15dff4 OUTPUT_BEGIN -{ - "schema_version": 2, - "cluster_id": "homelab", - "status": "READY", - "generated_at_utc": "2026-07-21T07:02:17Z", - "context": { - "full_context_command_id": "CONTEXT-SOURCES-FULL-002", - "full_context_commit": "e23caf794cc68ce5fa6f8922efa7f2a35c8aa6e0", - "full_context_sha256": "621830f58b028a0116a42964d02bdca31c280d6ff358f518d0e8f24c2ba01366", - "full_context_url": "https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/e23caf794cc68ce5fa6f8922efa7f2a35c8aa6e0/runtime/history/CONTEXT-SOURCES-FULL-002.txt", - "context_index_command_id": "CONTEXT-INDEX-001", - "context_index_commit": "055521f14fbb0780bdb501c7d7be755350d45091", - "context_index_url": "https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/055521f14fbb0780bdb501c7d7be755350d45091/runtime/history/CONTEXT-INDEX-001.json", - "reference_sha256": "f6f7749fda946015116cdbbd754c7e7f20356b4a6cf4df330a1b0b8fdf59cbb2", - "error_register_sha256": "ab8308549db90d235b591af0581580c3c7ba1b287b129cc6111c2eef0a0f9ecc", - "error_register_embedded_in_full_context": true - }, - "runtime": { - "history_url": "https://git.gram1.ru/homelab-admin/homelab-public-context/src/branch/assistant-runtime/runtime/history", - "latest_branch_url": "https://git.gram1.ru/homelab-admin/homelab-public-context/raw/branch/assistant-runtime/runtime/latest.json", - "result_confirmation": "immutable_history_by_command_id", - "latest_json_is_authoritative": false - }, - "operating_contract": { - "load_bootstrap_before_commands": true, - "load_error_register_before_commands": true, - "check_previous_command_result": true, - "reject_known_failed_exact_repeats": true, - "one_command_per_step": true, - "manual_terminal_output_required": false, - "runner": "homelab-chat-run", - "confirmation_tokens": [ - ".", - ",", - "\\" - ], - "immediate_next_command": true, - "command_display": "collapsible_details", - "double_pre_command_check": true - }, - "privacy": { - "sanitized": true, - "secrets_included": false, - "private_addresses_included": false - }, - "entrypoints": { - "full_context_url": "https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/e23caf794cc68ce5fa6f8922efa7f2a35c8aa6e0/runtime/history/CONTEXT-SOURCES-FULL-002.txt", - "errors_index_url": "https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/a615069de3d32564fc4de29baff949bdaf811caf/runtime/history/ERRORS-INDEX-004.json", - "workflow_contract_url": "https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/2f37a4eb600528d03f5c570af8c5aa0e463b1798/runtime/history/WORKFLOW-CONTRACT-003.json", - "double_check_rule_url": "https://git.gram1.ru/homelab-admin/homelab-public-context/raw/commit/d1061e47e7955dba9c73a2841d4eacf02ccc1bf5/runtime/policy/double-check-rule.json" - }, - "freshness": { - "max_age_seconds": 86400, - "stale_requires_refresh": true - }, - "coverage": { - "status": "PARTIAL", - "missing": [ - "automatic_refresh", - "per_node_freshness", - "structured_service_inventory" - ] - } +#!/usr/bin/env bash +set -Eeuo pipefail +umask 027 + +HOST_DATA='/opt/stacks/gitea/data' +BARE_CONTAINER='/data/git/repositories/homelab-admin/homelab-public-context.git' + +PUBLIC_DIR="${HOST_DATA}/gitea/public/.well-known/homelab-runtime" +STAGE_DIR="${HOST_DATA}/gitea/runtime-stage" +WORK_ROOT="${HOST_DATA}/gitea/runtime-work" + +LOCK='/run/lock/homelab-runtime-receive.lock' + +[ "$#" -eq 3 ] || { + echo 'RESULT=FAIL' + echo 'REASON=USAGE' + exit 64 } +COMMAND_ID="$1" +JSON_FILE="$2" +TXT_FILE="$3" + +case "$COMMAND_ID" in + ''|*[!A-Za-z0-9._-]*) + echo 'RESULT=FAIL' + echo 'REASON=INVALID_COMMAND_ID' + exit 65 + ;; +esac + +[ -f "$JSON_FILE" ] || { + echo 'RESULT=FAIL' + echo 'REASON=JSON_FILE_MISSING' + exit 66 +} + +[ -f "$TXT_FILE" ] || { + echo 'RESULT=FAIL' + echo 'REASON=TXT_FILE_MISSING' + exit 67 +} + +exec 9>"$LOCK" +flock -w 60 9 || { + echo 'RESULT=FAIL' + echo 'REASON=RECEIVER_LOCK_TIMEOUT' + exit 68 +} + +python3 - "$JSON_FILE" "$TXT_FILE" "$COMMAND_ID" <<'PY' +import json +import re +import sys +from pathlib import Path + +json_path = Path(sys.argv[1]) +text_path = Path(sys.argv[2]) +expected_id = sys.argv[3] + +if json_path.stat().st_size > 524_288: + raise SystemExit("JSON_TOO_LARGE") + +if text_path.stat().st_size > 1_048_576: + raise SystemExit("TEXT_TOO_LARGE") + +json_text = json_path.read_text(encoding="utf-8") +text = text_path.read_text(encoding="utf-8") + +data = json.loads(json_text) + +if data.get("command_id") != expected_id: + raise SystemExit("COMMAND_ID_MISMATCH") + +if data.get("sanitized") is not True: + raise SystemExit("SANITIZED_FLAG_REQUIRED") + +if data.get("secrets_included") is not False: + raise SystemExit("SECRETS_FLAG_INVALID") + +if data.get("private_addresses_included") is not False: + raise SystemExit("PRIVATE_ADDRESS_FLAG_INVALID") + +combined = json_text + "\n" + text + +patterns = [ + r"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----", + r"(?i)(password|passwd|passphrase|authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|private[_-]?key)\s*[:=]\s*\S+", + r"(?i)/root/\.ssh", + r"(?i)[SENSITIVE_PATH]", + r"(?i)rclone\.conf", + r"\b10(?:\.\d{1,3}){3}\b", + r"\b192\.168(?:\.\d{1,3}){2}\b", + r"\b172\.(?:1[6-9]|2\d|3[01])(?:\.\d{1,3}){2}\b", +] + +for pattern in patterns: + if re.search(pattern, combined): + raise SystemExit("FORBIDDEN_PUBLIC_CONTENT") + +print("PAYLOAD_VALIDATION=OK") +PY + +GIT_UID="$(docker exec gitea id -u git)" +GIT_GID="$(docker exec gitea id -g git)" + +mkdir -p \ + "$PUBLIC_DIR" \ + "$STAGE_DIR" \ + "$WORK_ROOT" + +chown "$GIT_UID:$GIT_GID" \ + "$STAGE_DIR" \ + "$WORK_ROOT" + +install \ + -o "$GIT_UID" \ + -g "$GIT_GID" \ + -m 0644 \ + "$JSON_FILE" \ + "$STAGE_DIR/latest.json" + +install \ + -o "$GIT_UID" \ + -g "$GIT_GID" \ + -m 0644 \ + "$TXT_FILE" \ + "$STAGE_DIR/latest.txt" + +cat > "$STAGE_DIR/README.md" <<'DOC' +# Homelab assistant runtime + +Sanitized command results for read-only assistant inspection. + +Credentials, authentication data, private keys, private IP addresses and +unfiltered configuration files are prohibited. +DOC + +chown "$GIT_UID:$GIT_GID" "$STAGE_DIR/README.md" +chmod 0644 "$STAGE_DIR/README.md" + +PUBLISHED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" +WORK_CONTAINER="/data/gitea/runtime-work/${COMMAND_ID}.$$" + +COMMIT_SHA="$( + docker exec \ + -u "${GIT_UID}:${GIT_GID}" \ + -e COMMAND_ID="$COMMAND_ID" \ + -e PUBLISHED_AT="$PUBLISHED_AT" \ + -e WORK_CONTAINER="$WORK_CONTAINER" \ + gitea sh -lc ' +set -eu + +BARE="/data/git/repositories/homelab-admin/homelab-public-context.git" +STAGE="/data/gitea/runtime-stage" +WORK="$WORK_CONTAINER" + +rm -rf "$WORK" + +git clone --quiet "$BARE" "$WORK" + +cd "$WORK" + +git config user.name "homelab-runtime-publisher" +git config user.email "homelab-runtime@localhost" + +if git show-ref \ + --verify \ + --quiet \ + refs/remotes/origin/assistant-runtime +then + git checkout \ + --quiet \ + -B assistant-runtime \ + origin/assistant-runtime +else + git checkout \ + --quiet \ + --orphan assistant-runtime + + git rm -rf . >/dev/null 2>&1 || true +fi + +mkdir -p runtime/history + +cp "$STAGE/latest.json" runtime/latest.json +cp "$STAGE/latest.txt" runtime/latest.txt +cp "$STAGE/latest.json" "runtime/history/${COMMAND_ID}.json" +cp "$STAGE/latest.txt" "runtime/history/${COMMAND_ID}.txt" +cp "$STAGE/README.md" README.md + +git add \ + README.md \ + runtime/latest.json \ + runtime/latest.txt \ + "runtime/history/${COMMAND_ID}.json" + +git add "runtime/history/${COMMAND_ID}.txt" + +if ! git diff --cached --quiet +then + GIT_AUTHOR_DATE="$PUBLISHED_AT" \ + GIT_COMMITTER_DATE="$PUBLISHED_AT" \ + git commit \ + --quiet \ + -m "runtime: publish ${COMMAND_ID}" +fi + +COMMIT="$(git rev-parse HEAD)" + +git --git-dir="$BARE" \ + fetch \ + --quiet \ + "$WORK" \ + refs/heads/assistant-runtime + +OLD="$( + git --git-dir="$BARE" \ + rev-parse refs/heads/assistant-runtime \ + 2>/dev/null || + true +)" + +if [ -n "$OLD" ] +then + git --git-dir="$BARE" \ + update-ref \ + refs/heads/assistant-runtime \ + "$COMMIT" \ + "$OLD" +else + git --git-dir="$BARE" \ + update-ref \ + refs/heads/assistant-runtime \ + "$COMMIT" +fi + +rm -rf "$WORK" + +printf "%s\n" "$COMMIT" +' +)" + +JSON_TMP="$(mktemp "${PUBLIC_DIR}/.latest.json.XXXXXX")" +TXT_TMP="$(mktemp "${PUBLIC_DIR}/.latest.txt.XXXXXX")" +INDEX_TMP="$(mktemp "${PUBLIC_DIR}/.index.json.XXXXXX")" + +install -m 0644 "$JSON_FILE" "$JSON_TMP" +install -m 0644 "$TXT_FILE" "$TXT_TMP" + +python3 - \ + "$COMMAND_ID" \ + "$PUBLISHED_AT" \ + "$COMMIT_SHA" >"$INDEX_TMP" <<'PY' +import json +import sys + +command_id, published_at, commit_sha = sys.argv[1:4] + +print(json.dumps({ + "schema_version": 1, + "channel": "homelab-runtime", + "branch": "assistant-runtime", + "latest_command_id": command_id, + "published_at_utc": published_at, + "commit_sha": commit_sha, + "latest_json_url": ( + "https://git.gram1.ru/.well-known/" + "homelab-runtime/latest.json" + ), + "latest_text_url": ( + "https://git.gram1.ru/.well-known/" + "homelab-runtime/latest.txt" + ) +}, ensure_ascii=False, indent=2)) +PY + +chmod 0644 "$INDEX_TMP" + +mv -f "$JSON_TMP" "$PUBLIC_DIR/latest.json" +mv -f "$TXT_TMP" "$PUBLIC_DIR/latest.txt" +mv -f "$INDEX_TMP" "$PUBLIC_DIR/index.json" + +curl -fsS \ + --max-time 10 \ + http://127.0.0.1:3002/.well-known/homelab-runtime/latest.json | +grep -F "$COMMAND_ID" >/dev/null + +curl -fsS \ + --max-time 10 \ + "http://127.0.0.1:3002/homelab-admin/homelab-public-context/raw/branch/assistant-runtime/runtime/latest.json" | +grep -F "$COMMAND_ID" >/dev/null + +echo 'RESULT=OK' +echo "COMMAND_ID=$COMMAND_ID" +echo "COMMIT_SHA=$COMMIT_SHA" +echo 'STATIC_PUBLICATION=OK' +echo 'RAW_BRANCH_PUBLICATION=OK' + OUTPUT_END CHAT_OUTPUT_END