From 904ca9b1d4ea3480e429e3e5fa8cfd4906727829 Mon Sep 17 00:00:00 2001 From: homelab-runtime-publisher Date: Wed, 5 Aug 2026 12:21:32 +0000 Subject: [PATCH] runtime: publish HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z --- ...ISK-SCHEMA-READ-ONLY-20260805T121700Z.json | 38 +++++++++++++++++++ ...RISK-SCHEMA-READ-ONLY-20260805T121700Z.txt | 34 +++++++++++++++++ runtime/latest.json | 16 ++++---- runtime/latest.txt | 14 +++---- 4 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 runtime/history/HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z.json create mode 100644 runtime/history/HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z.txt diff --git a/runtime/history/HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z.json b/runtime/history/HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z.json new file mode 100644 index 0000000..daad243 --- /dev/null +++ b/runtime/history/HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z.json @@ -0,0 +1,38 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "verify", + "component": "homelab-command-adapter-schema", + "started_at_utc": "2026-08-05T12:21:30Z", + "finished_at_utc": "2026-08-05T12:21:32Z", + "reference_register_checked": true, + "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", + "error_register_checked": true, + "error_register_sha256": "24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83", + "command_sha256": "8f5ea9cbbb504993bd994b501118c5e9eff048c652ee8819f91f9e1e372631f8", + "duplicate_failed_command_blocked": false, + "block_reason": null, + "execution_started": true, + "change_declared": false, + "result_contract_valid": true, + "result_contract_status": null, + "result_contract_error": null, + "command_rc": 0, + "changes_made": false, + "rollback_started": false, + "rollback_restored": null, + "mutation_outcome": "NO_MUTATION", + "sanitized": true, + "secrets_included": false, + "private_addresses_included": false, + "raw_evidence_retained_locally": true, + "raw_evidence_sha256": "d491cbc5d16aa000a95ff0b394d333365a4aca69b7dd8d831e7ec7dfdedbf068", + "sanitized_output_sha256": "d491cbc5d16aa000a95ff0b394d333365a4aca69b7dd8d831e7ec7dfdedbf068", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "HOMELAB_RESULT_CONTRACT={\"changes_made\":false,\"command_id\":\"HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z\",\"command_rc\":0,\"control_plane_error\":null,\"exact_invalid_risk_source_found\":true,\"matching_file_count\":2,\"matching_file_manifest_sha256\":\"af904aec1040e2968d87c5e61b6ced9f013d49a0c7f5e0a48f70b292df1a966c\",\"mutation_outcome\":\"NO_MUTATION\",\"rc\":0,\"report_bytes\":20215,\"report_sha256\":\"4b4749cedde3bcaed3f4b01824f2c5de02d90e6525a59e5fd4e8b1b545344a95\",\"risk_candidate_tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"],\"risk_enum_confirmed\":true,\"rollback_restored\":false,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\n{\"candidate_roots\":[\"/\",\"/etc/systemd/system\",\"/etc/systemd/system/homelab-command-adapter.service\",\"/opt\",\"/srv\",\"/usr/bin\",\"/usr/bin/python3.13\",\"/usr/local\",\"/usr/local/lib\",\"/usr/local/sbin\",\"/usr/local/sbin/homelab-command-adapter\"],\"changes_made\":false,\"command_id\":\"HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z\",\"mutation_outcome\":\"NO_MUTATION\",\"read_only\":true,\"risk_enum\":{\"candidate_tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"],\"exact_enum_confirmed\":true,\"proof\":[{\"context\":[{\"line\":380,\"text\":\" ):\"},{\"line\":381,\"text\":\" raise AdapterError(\\\"invalid timeout_seconds\\\")\"},{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"}],\"match_line\":383,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"REVERSIBLE\"]},{\"context\":[{\"line\":381,\"text\":\" raise AdapterError(\\\"invalid timeout_seconds\\\")\"},{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"}],\"match_line\":384,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"REVERSIBLE\"]},{\"context\":[{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"}],\"match_line\":385,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]},{\"context\":[{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"}],\"match_line\":386,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]},{\"context\":[{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"}],\"match_line\":387,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]},{\"context\":[{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"},{\"line\":391,\"text\":\" flags = document.get(\\\"change_flags\\\")\"}],\"match_line\":388,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]},{\"context\":[{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"},{\"line\":391,\"text\":\" flags = document.get(\\\"change_flags\\\")\"},{\"line\":392,\"text\":\" if not isinstance(flags, dict):\"}],\"match_line\":389,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]}]},\"rollback_restored\":false,\"rollback_started\":false,\"scan\":{\"exact_invalid_mode_matches\":1,\"exact_invalid_risk_matches\":1,\"files_scanned\":3,\"matching_file_manifest_sha256\":\"af904aec1040e2968d87c5e61b6ced9f013d49a0c7f5e0a48f70b292df1a966c\",\"matching_files\":2,\"uppercase_enum_tokens\":[\"FAIL\",\"HIGH\",\"NONE\",\"READ_ONLY\",\"REVERSIBLE\",\"UNKNOWN\",\"USAGE\"]},\"schema\":1,\"source_matches\":[{\"bytes\":21321,\"matches\":[{\"context\":[{\"line\":8,\"text\":\"import sys\"},{\"line\":9,\"text\":\"from pathlib import Path\"},{\"line\":10,\"text\":\"\"},{\"line\":11,\"text\":\"raw_path, command_id, mode, command_rc = sys.argv[1:]\"},{\"line\":12,\"text\":\"command_rc = int(command_rc)\"},{\"line\":13,\"text\":\"\"},{\"line\":14,\"text\":\"result = {\"}],\"match_line\":11},{\"context\":[{\"line\":21,\"text\":\" \\\"error\\\": \\\"NONE\\\",\"},{\"line\":22,\"text\":\"}\"},{\"line\":23,\"text\":\"\"},{\"line\":24,\"text\":\"if mode == \\\"change\\\":\"},{\"line\":25,\"text\":\" result = {\"},{\"line\":26,\"text\":\" \\\"valid\\\": False,\"},{\"line\":27,\"text\":\" \\\"status\\\": \\\"UNKNOWN\\\",\"}],\"match_line\":24},{\"context\":[{\"line\":188,\"text\":\"usage() {\"},{\"line\":189,\"text\":\" cat >&2 <<'USAGE'\"},{\"line\":190,\"text\":\"Usage:\"},{\"line\":191,\"text\":\" homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]\"},{\"line\":192,\"text\":\"\"},{\"line\":193,\"text\":\"MODE:\"},{\"line\":194,\"text\":\" read-only\"}],\"match_line\":191},{\"context\":[{\"line\":190,\"text\":\"Usage:\"},{\"line\":191,\"text\":\" homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]\"},{\"line\":192,\"text\":\"\"},{\"line\":193,\"text\":\"MODE:\"},{\"line\":194,\"text\":\" read-only\"},{\"line\":195,\"text\":\" verify\"},{\"line\":196,\"text\":\" change\"}],\"match_line\":193},{\"context\":[{\"line\":206,\"text\":\"[ \\\"$#\\\" -ge 5 ] || usage\"},{\"line\":207,\"text\":\"\"},{\"line\":208,\"text\":\"COMMAND_ID=\\\"$1\\\"\"},{\"line\":209,\"text\":\"MODE=\\\"$2\\\"\"},{\"line\":210,\"text\":\"COMPONENT=\\\"$3\\\"\"},{\"line\":211,\"text\":\"shift 3\"},{\"line\":212,\"text\":\"\"}],\"match_line\":209},{\"context\":[{\"line\":230,\"text\":\" ;;\"},{\"line\":231,\"text\":\"esac\"},{\"line\":232,\"text\":\"\"},{\"line\":233,\"text\":\"case \\\"$MODE\\\" in\"},{\"line\":234,\"text\":\" read-only|verify|change|transport-test)\"},{\"line\":235,\"text\":\" ;;\"},{\"line\":236,\"text\":\" *)\"}],\"match_line\":233},{\"context\":[{\"line\":304,\"text\":\"\"},{\"line\":305,\"text\":\"COMMAND_SHA256=\\\"$(\"},{\"line\":306,\"text\":\" {\"},{\"line\":307,\"text\":\" printf '%s\\\\0' \\\"$MODE\\\"\"},{\"line\":308,\"text\":\" printf '%s\\\\0' \\\"$COMPONENT\\\"\"},{\"line\":309,\"text\":\" printf '%s\\\\0' \\\"$@\\\"\"},{\"line\":310,\"text\":\" } |\"}],\"match_line\":307},{\"context\":[{\"line\":337,\"text\":\"RESULT_CONTRACT_ERROR='NONE'\"},{\"line\":338,\"text\":\"COMMAND_RC=''\"},{\"line\":339,\"text\":\"\"},{\"line\":340,\"text\":\"if [ \\\"$MODE\\\" = change ]; then\"},{\"line\":341,\"text\":\" CHANGE_DECLARED=true\"},{\"line\":342,\"text\":\" RESULT_CONTRACT_VALID=false\"},{\"line\":343,\"text\":\" CONTRACT_STATUS='UNKNOWN'\"}],\"match_line\":340},{\"context\":[{\"line\":416,\"text\":\" read_mutation_contract \\\\\"},{\"line\":417,\"text\":\" \\\"$RAW_FILE\\\" \\\\\"},{\"line\":418,\"text\":\" \\\"$COMMAND_ID\\\" \\\\\"},{\"line\":419,\"text\":\" \\\"$MODE\\\" \\\\\"},{\"line\":420,\"text\":\" \\\"$COMMAND_RC\\\"\"},{\"line\":421,\"text\":\" )\"},{\"line\":422,\"text\":\"\"}],\"match_line\":419},{\"context\":[{\"line\":420,\"text\":\" \\\"$COMMAND_RC\\\"\"},{\"line\":421,\"text\":\" )\"},{\"line\":422,\"text\":\"\"},{\"line\":423,\"text\":\" if [ \\\"$MODE\\\" = change ]; then\"},{\"line\":424,\"text\":\" if [ \\\"$RESULT_CONTRACT_VALID\\\" != true ]; then\"},{\"line\":425,\"text\":\" RC=76\"},{\"line\":426,\"text\":\" STATUS='FAIL'\"}],\"match_line\":423},{\"context\":[{\"line\":547,\"text\":\" \\\"$STATUS\\\" \\\\\"},{\"line\":548,\"text\":\" \\\"$RC\\\" \\\\\"},{\"line\":549,\"text\":\" \\\"$HOST_SHORT\\\" \\\\\"},{\"line\":550,\"text\":\" \\\"$MODE\\\" \\\\\"},{\"line\":551,\"text\":\" \\\"$COMPONENT\\\" \\\\\"},{\"line\":552,\"text\":\" \\\"$STARTED_AT\\\" \\\\\"},{\"line\":553,\"text\":\" \\\"$FINISHED_AT\\\" \\\\\"}],\"match_line\":550},{\"context\":[{\"line\":579,\"text\":\" status,\"},{\"line\":580,\"text\":\" rc,\"},{\"line\":581,\"text\":\" host,\"},{\"line\":582,\"text\":\" mode,\"},{\"line\":583,\"text\":\" component,\"},{\"line\":584,\"text\":\" started,\"},{\"line\":585,\"text\":\" finished,\"}],\"match_line\":582},{\"context\":[{\"line\":634,\"text\":\" \\\"status\\\": status,\"},{\"line\":635,\"text\":\" \\\"rc\\\": int(rc),\"},{\"line\":636,\"text\":\" \\\"host\\\": host,\"},{\"line\":637,\"text\":\" \\\"mode\\\": mode,\"},{\"line\":638,\"text\":\" \\\"component\\\": component,\"},{\"line\":639,\"text\":\" \\\"started_at_utc\\\": started,\"},{\"line\":640,\"text\":\" \\\"finished_at_utc\\\": finished,\"}],\"match_line\":637},{\"context\":[{\"line\":694,\"text\":\" echo \\\"STATUS=$STATUS\\\"\"},{\"line\":695,\"text\":\" echo \\\"RC=$RC\\\"\"},{\"line\":696,\"text\":\" echo \\\"HOST=$HOST_SHORT\\\"\"},{\"line\":697,\"text\":\" echo \\\"MODE=$MODE\\\"\"},{\"line\":698,\"text\":\" echo \\\"COMPONENT=$COMPONENT\\\"\"},{\"line\":699,\"text\":\" echo 'REFERENCE_REGISTER_CHECK=OK'\"},{\"line\":700,\"text\":\" echo \\\"REFERENCE_SHA256=$REFERENCE_SHA256\\\"\"}],\"match_line\":697}],\"path\":\"/usr/local/sbin/homelab-chat-run\",\"sha256\":\"b248a4c32c9cc64e5747e7dce6c7fc0a23f5124a77c71ce72e27a81aceae9d2d\"},{\"bytes\":86019,\"matches\":[{\"context\":[{\"line\":119,\"text\":\" \\\"transport-test\\\",\"},{\"line\":120,\"text\":\"}\"},{\"line\":121,\"text\":\"ALLOWED_RISKS = {\"},{\"line\":122,\"text\":\" \\\"READ_ONLY\\\",\"},{\"line\":123,\"text\":\" \\\"REVERSIBLE\\\",\"},{\"line\":124,\"text\":\" \\\"HIGH\\\",\"},{\"line\":125,\"text\":\"}\"}],\"match_line\":122},{\"context\":[{\"line\":129,\"text\":\" \\\"command_id\\\",\"},{\"line\":130,\"text\":\" \\\"title\\\",\"},{\"line\":131,\"text\":\" \\\"summary\\\",\"},{\"line\":132,\"text\":\" \\\"mode\\\",\"},{\"line\":133,\"text\":\" \\\"component\\\",\"},{\"line\":134,\"text\":\" \\\"target\\\",\"},{\"line\":135,\"text\":\" \\\"timeout_seconds\\\",\"}],\"match_line\":132},{\"context\":[{\"line\":133,\"text\":\" \\\"component\\\",\"},{\"line\":134,\"text\":\" \\\"target\\\",\"},{\"line\":135,\"text\":\" \\\"timeout_seconds\\\",\"},{\"line\":136,\"text\":\" \\\"risk\\\",\"},{\"line\":137,\"text\":\" \\\"change_flags\\\",\"},{\"line\":138,\"text\":\" \\\"rollback\\\",\"},{\"line\":139,\"text\":\" \\\"argv\\\",\"}],\"match_line\":136},{\"context\":[{\"line\":143,\"text\":\"}\"},{\"line\":144,\"text\":\"ALLOWED_PAYLOAD_FIELDS = {\"},{\"line\":145,\"text\":\" \\\"path\\\",\"},{\"line\":146,\"text\":\" \\\"mode\\\",\"},{\"line\":147,\"text\":\" \\\"sha256\\\",\"},{\"line\":148,\"text\":\" \\\"content_b64\\\",\"},{\"line\":149,\"text\":\"}\"}],\"match_line\":146},{\"context\":[{\"line\":262,\"text\":\"\"},{\"line\":263,\"text\":\"def ensure_layout() -> None:\"},{\"line\":264,\"text\":\" portal = pwd.getpwnam(PORTAL_USER)\"},{\"line\":265,\"text\":\" for path, mode in (\"},{\"line\":266,\"text\":\" (ROOT, 0o750),\"},{\"line\":267,\"text\":\" (STATE_DIR, 0o750),\"},{\"line\":268,\"text\":\" (CAPSULE_DIR, 0o700),\"}],\"match_line\":265},{\"context\":[{\"line\":270,\"text\":\" ):\"},{\"line\":271,\"text\":\" path.mkdir(parents=True, exist_ok=True)\"},{\"line\":272,\"text\":\" os.chown(path, 0, portal.pw_gid)\"},{\"line\":273,\"text\":\" os.chmod(path, mode)\"},{\"line\":274,\"text\":\"\"},{\"line\":275,\"text\":\"\"},{\"line\":276,\"text\":\"def unique_json_loads(raw: bytes) -> dict[str, Any]:\"}],\"match_line\":273},{\"context\":[{\"line\":332,\"text\":\"\"},{\"line\":333,\"text\":\" if document.get(\\\"schema_version\\\") != 1:\"},{\"line\":334,\"text\":\" raise AdapterError(\\\"unsupported capsule schema\\\")\"},{\"line\":335,\"text\":\" if document.get(\\\"kind\\\") != \\\"homelab-command-capsule\\\":\"},{\"line\":336,\"text\":\" raise AdapterError(\\\"invalid capsule kind\\\")\"},{\"line\":337,\"text\":\"\"},{\"line\":338,\"text\":\" command_id = validate_text(\"}],\"match_line\":335},{\"context\":[{\"line\":366,\"text\":\" maximum=2000,\"},{\"line\":367,\"text\":\" )\"},{\"line\":368,\"text\":\"\"},{\"line\":369,\"text\":\" mode = document.get(\\\"mode\\\")\"},{\"line\":370,\"text\":\" if mode not in ALLOWED_MODES:\"},{\"line\":371,\"text\":\" raise AdapterError(\\\"invalid mode\\\")\"},{\"line\":372,\"text\":\" if document.get(\\\"target\\\") != \\\"pve01\\\":\"}],\"match_line\":369},{\"context\":[{\"line\":367,\"text\":\" )\"},{\"line\":368,\"text\":\"\"},{\"line\":369,\"text\":\" mode = document.get(\\\"mode\\\")\"},{\"line\":370,\"text\":\" if mode not in ALLOWED_MODES:\"},{\"line\":371,\"text\":\" raise AdapterError(\\\"invalid mode\\\")\"},{\"line\":372,\"text\":\" if document.get(\\\"target\\\") != \\\"pve01\\\":\"},{\"line\":373,\"text\":\" raise AdapterError(\\\"only pve01 target is supported\\\")\"}],\"match_line\":370},{\"context\":[{\"line\":368,\"text\":\"\"},{\"line\":369,\"text\":\" mode = document.get(\\\"mode\\\")\"},{\"line\":370,\"text\":\" if mode not in ALLOWED_MODES:\"},{\"line\":371,\"text\":\" raise AdapterError(\\\"invalid mode\\\")\"},{\"line\":372,\"text\":\" if document.get(\\\"target\\\") != \\\"pve01\\\":\"},{\"line\":373,\"text\":\" raise AdapterError(\\\"only pve01 target is supported\\\")\"},{\"line\":374,\"text\":\"\"}],\"match_line\":371},{\"context\":[{\"line\":380,\"text\":\" ):\"},{\"line\":381,\"text\":\" raise AdapterError(\\\"invalid timeout_seconds\\\")\"},{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"}],\"match_line\":383},{\"context\":[{\"line\":381,\"text\":\" raise AdapterError(\\\"invalid timeout_seconds\\\")\"},{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"}],\"match_line\":384},{\"context\":[{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"}],\"match_line\":385},{\"context\":[{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"}],\"match_line\":386},{\"context\":[{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"}],\"match_line\":387},{\"context\":[{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"},{\"line\":391,\"text\":\" flags = document.get(\\\"change_flags\\\")\"}],\"match_line\":388},{\"context\":[{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"},{\"line\":391,\"text\":\" flags = document.get(\\\"change_flags\\\")\"},{\"line\":392,\"text\":\" if not isinstance(flags, dict):\"}],\"match_line\":389},{\"context\":[{\"line\":396,\"text\":\" if any(type(value) is not bool for value in flags.values()):\"},{\"line\":397,\"text\":\" raise AdapterError(\\\"change_flags values must be boolean\\\")\"},{\"line\":398,\"text\":\"\"},{\"line\":399,\"text\":\" if mode != \\\"change\\\" and any(flags.values()):\"},{\"line\":400,\"text\":\" raise AdapterError(\"},{\"line\":401,\"text\":\" \\\"non-change capsule cannot declare changes\\\"\"},{\"line\":402,\"text\":\" )\"}],\"match_line\":399},{\"context\":[{\"line\":400,\"text\":\" raise AdapterError(\"},{\"line\":401,\"text\":\" \\\"non-change capsule cannot declare changes\\\"\"},{\"line\":402,\"text\":\" )\"},{\"line\":403,\"text\":\" if mode == \\\"change\\\" and not flags[\\\"production\\\"]:\"},{\"line\":404,\"text\":\" raise AdapterError(\"},{\"line\":405,\"text\":\" \\\"change capsule must declare production change\\\"\"},{\"line\":406,\"text\":\" )\"}],\"match_line\":403},{\"context\":[{\"line\":418,\"text\":\" minimum=1,\"},{\"line\":419,\"text\":\" maximum=2000,\"},{\"line\":420,\"text\":\" )\"},{\"line\":421,\"text\":\" if mode == \\\"change\\\" and rollback[\\\"available\\\"] is not True:\"},{\"line\":422,\"text\":\" raise AdapterError(\"},{\"line\":423,\"text\":\" \\\"change capsule requires available rollback\\\"\"},{\"line\":424,\"text\":\" )\"}],\"match_line\":421}],\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"sha256\":\"a1a7a615c99568bf915d084cc476f0ebf54ab0eedf3ecd578c4b0e072f58c43d\"}],\"status\":\"OK\",\"systemd_adapter\":[{\"cat_rc\":1,\"cat_stderr\":\"No files found for homelab-adapter.service.\\n\",\"show\":{\"ActiveState\":\"inactive\",\"DropInPaths\":\"\",\"FragmentPath\":\"\",\"LoadState\":\"not-found\",\"MainPID\":\"0\",\"SubState\":\"dead\",\"WorkingDirectory\":\"\"},\"show_rc\":0,\"show_stderr\":\"\",\"unit\":\"homelab-adapter.service\",\"unit_text\":\"\"},{\"cat_rc\":0,\"cat_stderr\":\"\",\"process\":{\"cmdline\":[\"/usr/bin/python3\",\"-B\",\"/usr/local/sbin/homelab-command-adapter\",\"--serve\"],\"cwd\":\"/\",\"exe\":\"/usr/bin/python3.13\",\"pid\":1131444},\"show\":{\"ActiveState\":\"active\",\"DropInPaths\":\"\",\"ExecStart\":\"{ path=/usr/bin/python3 ; argv[]=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }\",\"FragmentPath\":\"/etc/systemd/system/homelab-command-adapter.service\",\"LoadState\":\"loaded\",\"MainPID\":\"1131444\",\"SubState\":\"running\",\"WorkingDirectory\":\"\"},\"show_rc\":0,\"show_stderr\":\"\",\"unit\":\"homelab-command-adapter.service\",\"unit_text\":\"# /etc/systemd/system/homelab-command-adapter.service\\n[Unit]\\nDescription=Homelab command adapter\\nAfter=network-online.target\\nWants=network-online.target\\n\\n[Service]\\nType=simple\\nExecStart=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve\\nUser=root\\nGroup=homelab-command-portal\\nUMask=0027\\nRuntimeDirectory=homelab-command-adapter\\nRuntimeDirectoryMode=0750\\nRestart=on-failure\\nRestartSec=2\\nNoNewPrivileges=false\\nPrivateTmp=true\\nProtectClock=true\\nProtectControlGroups=true\\nProtectKernelLogs=true\\nProtectKernelModules=true\\nProtectKernelTunables=true\\nRestrictRealtime=true\\nLockPersonality=true\\nMemoryDenyWriteExecute=true\\nSystemCallArchitectures=native\\nTimeoutStopSec=15\\n\\n[Install]\\nWantedBy=multi-user.target\"}]}\n" +} diff --git a/runtime/history/HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z.txt b/runtime/history/HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z.txt new file mode 100644 index 0000000..ec5c78d --- /dev/null +++ b/runtime/history/HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z.txt @@ -0,0 +1,34 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z +STATUS=OK +RC=0 +HOST=pve01 +MODE=verify +COMPONENT=homelab-command-adapter-schema +REFERENCE_REGISTER_CHECK=OK +REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e +ERROR_REGISTER_CHECK=OK +ERROR_REGISTER_SHA256=24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83 +COMMAND_SHA256=8f5ea9cbbb504993bd994b501118c5e9eff048c652ee8819f91f9e1e372631f8 +DUPLICATE_FAILED_COMMAND_BLOCKED=false +EXECUTION_STARTED=true +CHANGE_DECLARED=false +RESULT_CONTRACT_VALID=true +RESULT_CONTRACT_STATUS=NOT_APPLICABLE +RESULT_CONTRACT_ERROR=NONE +COMMAND_RC=0 +CHANGES_MADE=false +ROLLBACK_STARTED=false +ROLLBACK_RESTORED=null +MUTATION_OUTCOME=NO_MUTATION +SANITIZED=yes +SECRETS_INCLUDED=no +PRIVATE_ADDRESSES_INCLUDED=no +RAW_EVIDENCE_SHA256=d491cbc5d16aa000a95ff0b394d333365a4aca69b7dd8d831e7ec7dfdedbf068 +SANITIZED_OUTPUT_SHA256=d491cbc5d16aa000a95ff0b394d333365a4aca69b7dd8d831e7ec7dfdedbf068 +OUTPUT_BEGIN +HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z","command_rc":0,"control_plane_error":null,"exact_invalid_risk_source_found":true,"matching_file_count":2,"matching_file_manifest_sha256":"af904aec1040e2968d87c5e61b6ced9f013d49a0c7f5e0a48f70b292df1a966c","mutation_outcome":"NO_MUTATION","rc":0,"report_bytes":20215,"report_sha256":"4b4749cedde3bcaed3f4b01824f2c5de02d90e6525a59e5fd4e8b1b545344a95","risk_candidate_tokens":["HIGH","READ_ONLY","REVERSIBLE"],"risk_enum_confirmed":true,"rollback_restored":false,"rollback_started":false,"status":"OK","version":1} +{"candidate_roots":["/","/etc/systemd/system","/etc/systemd/system/homelab-command-adapter.service","/opt","/srv","/usr/bin","/usr/bin/python3.13","/usr/local","/usr/local/lib","/usr/local/sbin","/usr/local/sbin/homelab-command-adapter"],"changes_made":false,"command_id":"HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z","mutation_outcome":"NO_MUTATION","read_only":true,"risk_enum":{"candidate_tokens":["HIGH","READ_ONLY","REVERSIBLE"],"exact_enum_confirmed":true,"proof":[{"context":[{"line":380,"text":" ):"},{"line":381,"text":" raise AdapterError(\"invalid timeout_seconds\")"},{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"}],"match_line":383,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","REVERSIBLE"]},{"context":[{"line":381,"text":" raise AdapterError(\"invalid timeout_seconds\")"},{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"}],"match_line":384,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","REVERSIBLE"]},{"context":[{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"}],"match_line":385,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]},{"context":[{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"}],"match_line":386,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]},{"context":[{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""}],"match_line":387,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]},{"context":[{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""},{"line":391,"text":" flags = document.get(\"change_flags\")"}],"match_line":388,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]},{"context":[{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""},{"line":391,"text":" flags = document.get(\"change_flags\")"},{"line":392,"text":" if not isinstance(flags, dict):"}],"match_line":389,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]}]},"rollback_restored":false,"rollback_started":false,"scan":{"exact_invalid_mode_matches":1,"exact_invalid_risk_matches":1,"files_scanned":3,"matching_file_manifest_sha256":"af904aec1040e2968d87c5e61b6ced9f013d49a0c7f5e0a48f70b292df1a966c","matching_files":2,"uppercase_enum_tokens":["FAIL","HIGH","NONE","READ_ONLY","REVERSIBLE","UNKNOWN","USAGE"]},"schema":1,"source_matches":[{"bytes":21321,"matches":[{"context":[{"line":8,"text":"import sys"},{"line":9,"text":"from pathlib import Path"},{"line":10,"text":""},{"line":11,"text":"raw_path, command_id, mode, command_rc = sys.argv[1:]"},{"line":12,"text":"command_rc = int(command_rc)"},{"line":13,"text":""},{"line":14,"text":"result = {"}],"match_line":11},{"context":[{"line":21,"text":" \"error\": \"NONE\","},{"line":22,"text":"}"},{"line":23,"text":""},{"line":24,"text":"if mode == \"change\":"},{"line":25,"text":" result = {"},{"line":26,"text":" \"valid\": False,"},{"line":27,"text":" \"status\": \"UNKNOWN\","}],"match_line":24},{"context":[{"line":188,"text":"usage() {"},{"line":189,"text":" cat >&2 <<'USAGE'"},{"line":190,"text":"Usage:"},{"line":191,"text":" homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]"},{"line":192,"text":""},{"line":193,"text":"MODE:"},{"line":194,"text":" read-only"}],"match_line":191},{"context":[{"line":190,"text":"Usage:"},{"line":191,"text":" homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]"},{"line":192,"text":""},{"line":193,"text":"MODE:"},{"line":194,"text":" read-only"},{"line":195,"text":" verify"},{"line":196,"text":" change"}],"match_line":193},{"context":[{"line":206,"text":"[ \"$#\" -ge 5 ] || usage"},{"line":207,"text":""},{"line":208,"text":"COMMAND_ID=\"$1\""},{"line":209,"text":"MODE=\"$2\""},{"line":210,"text":"COMPONENT=\"$3\""},{"line":211,"text":"shift 3"},{"line":212,"text":""}],"match_line":209},{"context":[{"line":230,"text":" ;;"},{"line":231,"text":"esac"},{"line":232,"text":""},{"line":233,"text":"case \"$MODE\" in"},{"line":234,"text":" read-only|verify|change|transport-test)"},{"line":235,"text":" ;;"},{"line":236,"text":" *)"}],"match_line":233},{"context":[{"line":304,"text":""},{"line":305,"text":"COMMAND_SHA256=\"$("},{"line":306,"text":" {"},{"line":307,"text":" printf '%s\\0' \"$MODE\""},{"line":308,"text":" printf '%s\\0' \"$COMPONENT\""},{"line":309,"text":" printf '%s\\0' \"$@\""},{"line":310,"text":" } |"}],"match_line":307},{"context":[{"line":337,"text":"RESULT_CONTRACT_ERROR='NONE'"},{"line":338,"text":"COMMAND_RC=''"},{"line":339,"text":""},{"line":340,"text":"if [ \"$MODE\" = change ]; then"},{"line":341,"text":" CHANGE_DECLARED=true"},{"line":342,"text":" RESULT_CONTRACT_VALID=false"},{"line":343,"text":" CONTRACT_STATUS='UNKNOWN'"}],"match_line":340},{"context":[{"line":416,"text":" read_mutation_contract \\"},{"line":417,"text":" \"$RAW_FILE\" \\"},{"line":418,"text":" \"$COMMAND_ID\" \\"},{"line":419,"text":" \"$MODE\" \\"},{"line":420,"text":" \"$COMMAND_RC\""},{"line":421,"text":" )"},{"line":422,"text":""}],"match_line":419},{"context":[{"line":420,"text":" \"$COMMAND_RC\""},{"line":421,"text":" )"},{"line":422,"text":""},{"line":423,"text":" if [ \"$MODE\" = change ]; then"},{"line":424,"text":" if [ \"$RESULT_CONTRACT_VALID\" != true ]; then"},{"line":425,"text":" RC=76"},{"line":426,"text":" STATUS='FAIL'"}],"match_line":423},{"context":[{"line":547,"text":" \"$STATUS\" \\"},{"line":548,"text":" \"$RC\" \\"},{"line":549,"text":" \"$HOST_SHORT\" \\"},{"line":550,"text":" \"$MODE\" \\"},{"line":551,"text":" \"$COMPONENT\" \\"},{"line":552,"text":" \"$STARTED_AT\" \\"},{"line":553,"text":" \"$FINISHED_AT\" \\"}],"match_line":550},{"context":[{"line":579,"text":" status,"},{"line":580,"text":" rc,"},{"line":581,"text":" host,"},{"line":582,"text":" mode,"},{"line":583,"text":" component,"},{"line":584,"text":" started,"},{"line":585,"text":" finished,"}],"match_line":582},{"context":[{"line":634,"text":" \"status\": status,"},{"line":635,"text":" \"rc\": int(rc),"},{"line":636,"text":" \"host\": host,"},{"line":637,"text":" \"mode\": mode,"},{"line":638,"text":" \"component\": component,"},{"line":639,"text":" \"started_at_utc\": started,"},{"line":640,"text":" \"finished_at_utc\": finished,"}],"match_line":637},{"context":[{"line":694,"text":" echo \"STATUS=$STATUS\""},{"line":695,"text":" echo \"RC=$RC\""},{"line":696,"text":" echo \"HOST=$HOST_SHORT\""},{"line":697,"text":" echo \"MODE=$MODE\""},{"line":698,"text":" echo \"COMPONENT=$COMPONENT\""},{"line":699,"text":" echo 'REFERENCE_REGISTER_CHECK=OK'"},{"line":700,"text":" echo \"REFERENCE_SHA256=$REFERENCE_SHA256\""}],"match_line":697}],"path":"/usr/local/sbin/homelab-chat-run","sha256":"b248a4c32c9cc64e5747e7dce6c7fc0a23f5124a77c71ce72e27a81aceae9d2d"},{"bytes":86019,"matches":[{"context":[{"line":119,"text":" \"transport-test\","},{"line":120,"text":"}"},{"line":121,"text":"ALLOWED_RISKS = {"},{"line":122,"text":" \"READ_ONLY\","},{"line":123,"text":" \"REVERSIBLE\","},{"line":124,"text":" \"HIGH\","},{"line":125,"text":"}"}],"match_line":122},{"context":[{"line":129,"text":" \"command_id\","},{"line":130,"text":" \"title\","},{"line":131,"text":" \"summary\","},{"line":132,"text":" \"mode\","},{"line":133,"text":" \"component\","},{"line":134,"text":" \"target\","},{"line":135,"text":" \"timeout_seconds\","}],"match_line":132},{"context":[{"line":133,"text":" \"component\","},{"line":134,"text":" \"target\","},{"line":135,"text":" \"timeout_seconds\","},{"line":136,"text":" \"risk\","},{"line":137,"text":" \"change_flags\","},{"line":138,"text":" \"rollback\","},{"line":139,"text":" \"argv\","}],"match_line":136},{"context":[{"line":143,"text":"}"},{"line":144,"text":"ALLOWED_PAYLOAD_FIELDS = {"},{"line":145,"text":" \"path\","},{"line":146,"text":" \"mode\","},{"line":147,"text":" \"sha256\","},{"line":148,"text":" \"content_b64\","},{"line":149,"text":"}"}],"match_line":146},{"context":[{"line":262,"text":""},{"line":263,"text":"def ensure_layout() -> None:"},{"line":264,"text":" portal = pwd.getpwnam(PORTAL_USER)"},{"line":265,"text":" for path, mode in ("},{"line":266,"text":" (ROOT, 0o750),"},{"line":267,"text":" (STATE_DIR, 0o750),"},{"line":268,"text":" (CAPSULE_DIR, 0o700),"}],"match_line":265},{"context":[{"line":270,"text":" ):"},{"line":271,"text":" path.mkdir(parents=True, exist_ok=True)"},{"line":272,"text":" os.chown(path, 0, portal.pw_gid)"},{"line":273,"text":" os.chmod(path, mode)"},{"line":274,"text":""},{"line":275,"text":""},{"line":276,"text":"def unique_json_loads(raw: bytes) -> dict[str, Any]:"}],"match_line":273},{"context":[{"line":332,"text":""},{"line":333,"text":" if document.get(\"schema_version\") != 1:"},{"line":334,"text":" raise AdapterError(\"unsupported capsule schema\")"},{"line":335,"text":" if document.get(\"kind\") != \"homelab-command-capsule\":"},{"line":336,"text":" raise AdapterError(\"invalid capsule kind\")"},{"line":337,"text":""},{"line":338,"text":" command_id = validate_text("}],"match_line":335},{"context":[{"line":366,"text":" maximum=2000,"},{"line":367,"text":" )"},{"line":368,"text":""},{"line":369,"text":" mode = document.get(\"mode\")"},{"line":370,"text":" if mode not in ALLOWED_MODES:"},{"line":371,"text":" raise AdapterError(\"invalid mode\")"},{"line":372,"text":" if document.get(\"target\") != \"pve01\":"}],"match_line":369},{"context":[{"line":367,"text":" )"},{"line":368,"text":""},{"line":369,"text":" mode = document.get(\"mode\")"},{"line":370,"text":" if mode not in ALLOWED_MODES:"},{"line":371,"text":" raise AdapterError(\"invalid mode\")"},{"line":372,"text":" if document.get(\"target\") != \"pve01\":"},{"line":373,"text":" raise AdapterError(\"only pve01 target is supported\")"}],"match_line":370},{"context":[{"line":368,"text":""},{"line":369,"text":" mode = document.get(\"mode\")"},{"line":370,"text":" if mode not in ALLOWED_MODES:"},{"line":371,"text":" raise AdapterError(\"invalid mode\")"},{"line":372,"text":" if document.get(\"target\") != \"pve01\":"},{"line":373,"text":" raise AdapterError(\"only pve01 target is supported\")"},{"line":374,"text":""}],"match_line":371},{"context":[{"line":380,"text":" ):"},{"line":381,"text":" raise AdapterError(\"invalid timeout_seconds\")"},{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"}],"match_line":383},{"context":[{"line":381,"text":" raise AdapterError(\"invalid timeout_seconds\")"},{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"}],"match_line":384},{"context":[{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"}],"match_line":385},{"context":[{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"}],"match_line":386},{"context":[{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""}],"match_line":387},{"context":[{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""},{"line":391,"text":" flags = document.get(\"change_flags\")"}],"match_line":388},{"context":[{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""},{"line":391,"text":" flags = document.get(\"change_flags\")"},{"line":392,"text":" if not isinstance(flags, dict):"}],"match_line":389},{"context":[{"line":396,"text":" if any(type(value) is not bool for value in flags.values()):"},{"line":397,"text":" raise AdapterError(\"change_flags values must be boolean\")"},{"line":398,"text":""},{"line":399,"text":" if mode != \"change\" and any(flags.values()):"},{"line":400,"text":" raise AdapterError("},{"line":401,"text":" \"non-change capsule cannot declare changes\""},{"line":402,"text":" )"}],"match_line":399},{"context":[{"line":400,"text":" raise AdapterError("},{"line":401,"text":" \"non-change capsule cannot declare changes\""},{"line":402,"text":" )"},{"line":403,"text":" if mode == \"change\" and not flags[\"production\"]:"},{"line":404,"text":" raise AdapterError("},{"line":405,"text":" \"change capsule must declare production change\""},{"line":406,"text":" )"}],"match_line":403},{"context":[{"line":418,"text":" minimum=1,"},{"line":419,"text":" maximum=2000,"},{"line":420,"text":" )"},{"line":421,"text":" if mode == \"change\" and rollback[\"available\"] is not True:"},{"line":422,"text":" raise AdapterError("},{"line":423,"text":" \"change capsule requires available rollback\""},{"line":424,"text":" )"}],"match_line":421}],"path":"/usr/local/sbin/homelab-command-adapter","sha256":"a1a7a615c99568bf915d084cc476f0ebf54ab0eedf3ecd578c4b0e072f58c43d"}],"status":"OK","systemd_adapter":[{"cat_rc":1,"cat_stderr":"No files found for homelab-adapter.service.\n","show":{"ActiveState":"inactive","DropInPaths":"","FragmentPath":"","LoadState":"not-found","MainPID":"0","SubState":"dead","WorkingDirectory":""},"show_rc":0,"show_stderr":"","unit":"homelab-adapter.service","unit_text":""},{"cat_rc":0,"cat_stderr":"","process":{"cmdline":["/usr/bin/python3","-B","/usr/local/sbin/homelab-command-adapter","--serve"],"cwd":"/","exe":"/usr/bin/python3.13","pid":1131444},"show":{"ActiveState":"active","DropInPaths":"","ExecStart":"{ path=/usr/bin/python3 ; argv[]=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }","FragmentPath":"/etc/systemd/system/homelab-command-adapter.service","LoadState":"loaded","MainPID":"1131444","SubState":"running","WorkingDirectory":""},"show_rc":0,"show_stderr":"","unit":"homelab-command-adapter.service","unit_text":"# /etc/systemd/system/homelab-command-adapter.service\n[Unit]\nDescription=Homelab command adapter\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve\nUser=root\nGroup=homelab-command-portal\nUMask=0027\nRuntimeDirectory=homelab-command-adapter\nRuntimeDirectoryMode=0750\nRestart=on-failure\nRestartSec=2\nNoNewPrivileges=false\nPrivateTmp=true\nProtectClock=true\nProtectControlGroups=true\nProtectKernelLogs=true\nProtectKernelModules=true\nProtectKernelTunables=true\nRestrictRealtime=true\nLockPersonality=true\nMemoryDenyWriteExecute=true\nSystemCallArchitectures=native\nTimeoutStopSec=15\n\n[Install]\nWantedBy=multi-user.target"}]} + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index 070a331..daad243 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,19 +1,19 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "HOMELAB-SKLADCHIK-BRIDGE-SECRET-HANDOFF-SOURCE-MAP-READ-ONLY-20260805T122000Z", + "command_id": "HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z", "status": "OK", "rc": 0, "host": "pve01", "mode": "verify", - "component": "skladchik-bridge-secret-handoff-source-map-read-only", - "started_at_utc": "2026-08-05T12:20:11Z", - "finished_at_utc": "2026-08-05T12:20:11Z", + "component": "homelab-command-adapter-schema", + "started_at_utc": "2026-08-05T12:21:30Z", + "finished_at_utc": "2026-08-05T12:21:32Z", "reference_register_checked": true, "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", "error_register_checked": true, "error_register_sha256": "24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83", - "command_sha256": "397518006b159203a533b4d5a7511d01374b37e290c4e3bf65029d55fdbbff08", + "command_sha256": "8f5ea9cbbb504993bd994b501118c5e9eff048c652ee8819f91f9e1e372631f8", "duplicate_failed_command_blocked": false, "block_reason": null, "execution_started": true, @@ -30,9 +30,9 @@ "secrets_included": false, "private_addresses_included": false, "raw_evidence_retained_locally": true, - "raw_evidence_sha256": "648a3c7a53af4486969a6a0861ab60c0417107b8079d1cff6fcaf9432962b102", - "sanitized_output_sha256": "648a3c7a53af4486969a6a0861ab60c0417107b8079d1cff6fcaf9432962b102", + "raw_evidence_sha256": "d491cbc5d16aa000a95ff0b394d333365a4aca69b7dd8d831e7ec7dfdedbf068", + "sanitized_output_sha256": "d491cbc5d16aa000a95ff0b394d333365a4aca69b7dd8d831e7ec7dfdedbf068", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "HOMELAB_RESULT_CONTRACT={\"changes_made\":false,\"command_id\":\"HOMELAB-SKLADCHIK-BRIDGE-SECRET-HANDOFF-SOURCE-MAP-READ-ONLY-20260805T122000Z\",\"command_rc\":0,\"mutation_outcome\":\"NO_MUTATION\",\"output_truncated_in_json\":false,\"rc\":0,\"rollback_restored\":null,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\n{\"aggregate\":{\"process_calls\":3,\"redaction_symbols\":[\"create_evidence_bundle\",\"evidence_url\",\"remote_evidence_presign\",\"sanitize_state\",\"sign_evidence\",\"upload_evidence\"],\"request_or_channel_fields\":[\"Cookie\",\"adapter\",\"argv\",\"content_b64\",\"evidence\",\"payload\",\"portal\",\"secret\"],\"routes\":0},\"analysis_ready\":false,\"changes_made\":false,\"command_id\":\"HOMELAB-SKLADCHIK-BRIDGE-SECRET-HANDOFF-SOURCE-MAP-READ-ONLY-20260805T122000Z\",\"command_rc\":0,\"exact_exec_sha_verified\":false,\"file_inventory\":[{\"bytes\":665,\"descriptor\":{\"basename\":\"homelab-command-adapter.service\",\"class\":\"etc\",\"path_sha256\":\"afe4d91c280ac4e6e9999498b5f5d8b8842a1f33e30fd45d984879a6392bc045\"},\"mode\":\"0o644\",\"sha256\":\"74d0f37878652ed9d46b53ae8556bbb30ebd683741f293c3f59b3527876ed2d7\",\"text\":true},{\"bytes\":86019,\"descriptor\":{\"basename\":\"homelab-command-adapter\",\"class\":\"usr_local\",\"path_sha256\":\"c2e3b43f1f858c6fa265dc276d6a6a29e0cd25e4a127fbc093b8c8d9512bb739\"},\"expected_sha256\":\"c2e3b43f1f858c6fa265dc276d6a6a29e0cd25e4a127fbc093b8c8d9512bb739\",\"mode\":\"0o755\",\"sha256\":\"a1a7a615c99568bf915d084cc476f0ebf54ab0eedf3ecd578c4b0e072f58c43d\",\"sha_verified\":false,\"text\":true},{\"bytes\":981,\"descriptor\":{\"basename\":\"homelab-command-portal.service\",\"class\":\"etc\",\"path_sha256\":\"adf87b0f1c821b17e3e2ff19cc024d783b55caf69460d01fa66f7d2579a71f5a\"},\"mode\":\"0o644\",\"sha256\":\"8453eab30f5c3ccd285fc9f70fff18f564809bb27f7bf84f51f2ba593aa85263\",\"text\":true},{\"bytes\":39936,\"descriptor\":{\"basename\":\"homelab-command-portal\",\"class\":\"usr_local\",\"path_sha256\":\"1132c3c355ed18cdc6406935cd26a128df298f71df7f48df690c72b202ddd7be\"},\"expected_sha256\":\"1132c3c355ed18cdc6406935cd26a128df298f71df7f48df690c72b202ddd7be\",\"mode\":\"0o755\",\"sha256\":\"97c69bd4fccf7272dadc911281c1503f411bae2dc11dac4b22b87f33d678ae52\",\"sha_verified\":false,\"text\":true},{\"bytes\":184,\"descriptor\":{\"basename\":\"homelab-alerting-health.service\",\"class\":\"etc\",\"path_sha256\":\"65f987c4639cfe41887d81a0ca4a9e69f5cd1ebbbf5bfead9c0a12abafd69f2a\"},\"mode\":\"0o644\",\"sha256\":\"2328f1042ac8f6b201603d86941afc87d62191ae12559bee0fd77709c76066f3\",\"text\":true},{\"bytes\":163,\"descriptor\":{\"basename\":\"homelab-alerting-health.timer\",\"class\":\"etc\",\"path_sha256\":\"16473c4f545d506963d3759a2cc76a875669eaa5ac14ee32e133fedcad97d519\"},\"mode\":\"0o644\",\"sha256\":\"28ceb1a533a392af460fc8a42886912fcd256ee6fe8da89460e6c8bdb6096ef1\",\"text\":true},{\"bytes\":209,\"descriptor\":{\"basename\":\"homelab-alertmanager-backup.service\",\"class\":\"etc\",\"path_sha256\":\"b99f6af7e407c69eb96b30eceab66cbf4d08ac38db146134e82c6136b75e7e6c\"},\"mode\":\"0o644\",\"sha256\":\"2544f81eb70d2f66ae85a3ff23108d18c392f33f368832ac363ce7199782e7dd\",\"text\":true},{\"bytes\":204,\"descriptor\":{\"basename\":\"homelab-alertmanager-backup.timer\",\"class\":\"etc\",\"path_sha256\":\"352c09c23c02e625106d7c435e8532a898ac2e74df7713fa13a5bd52c1f697e8\"},\"mode\":\"0o644\",\"sha256\":\"34f5fdf96d8def90035b365f92d877d411331c4d6147131153120e8b737ee0c9\",\"text\":true},{\"bytes\":207,\"descriptor\":{\"basename\":\"homelab-appbackup-dockge-stacks.service\",\"class\":\"etc\",\"path_sha256\":\"4cb18a52e5ef24294a52d41193954c3ff2ac1a46a1915cd9284e30acf548d735\"},\"mode\":\"0o644\",\"sha256\":\"a17ea8adc560454997b581f3f49d52dbcfd039b8883f0188a9ce440c8393cb26\",\"text\":true},{\"bytes\":182,\"descriptor\":{\"basename\":\"homelab-appbackup-dockge-stacks.timer\",\"class\":\"etc\",\"path_sha256\":\"174817f002aa6b61a1fc6c017599b84d68f4a6b8d1d0eced919ec75f51ce0d3d\"},\"mode\":\"0o644\",\"sha256\":\"008a8d2e3f83f15562539057d18893a5076ee66c04df1fdf22d7769bd5c52629\",\"text\":true},{\"bytes\":200,\"descriptor\":{\"basename\":\"homelab-appbackup-mariadb-batch.service\",\"class\":\"etc\",\"path_sha256\":\"d39b189375339d4eb355d8c2516fc2532ffde390526d4132ef3e0c5166639ac8\"},\"mode\":\"0o644\",\"sha256\":\"267aa3988e9fd65ba876d62791ecfd13c191cd069e5e1cf6d77a85220d8e6a0a\",\"text\":true},{\"bytes\":172,\"descriptor\":{\"basename\":\"homelab-appbackup-mariadb-batch.timer\",\"class\":\"etc\",\"path_sha256\":\"34df635a54b198c51587957ce4c3706e83399a67116516d6e2732d5ace77def8\"},\"mode\":\"0o644\",\"sha256\":\"0f977f4ef03cdf76c2dc6d144ce064a7c79c5d2651d69ace5dea632f39f2a76e\",\"text\":true},{\"bytes\":212,\"descriptor\":{\"basename\":\"homelab-appbackup-npmplus-edge.service\",\"class\":\"etc\",\"path_sha256\":\"aeabf93d062d8e555b02e5c09306fc120c6f11d7500ce465101a072c0f323c8c\"},\"mode\":\"0o644\",\"sha256\":\"238cf3867746ee914b9d79d4f8d8a24fd5352186ea0dda29ecbff52249c3a2b8\",\"text\":true},{\"bytes\":181,\"descriptor\":{\"basename\":\"homelab-appbackup-npmplus-edge.timer\",\"class\":\"etc\",\"path_sha256\":\"c50f8c4dc29032baa3d8f5d2ca57f7173b084a2e8b7762000073e0c39869c823\"},\"mode\":\"0o644\",\"sha256\":\"f78414ddbc85db4507b77a6970d8b1c4f39f930b5ca1c8383a13d2467885a2ae\",\"text\":true},{\"bytes\":418,\"descriptor\":{\"basename\":\"homelab-appbackup-postgres-batch.service\",\"class\":\"etc\",\"path_sha256\":\"baddc516879128cef3d08f274700389a19a0d80f2b50e56c23352faf9e4f3078\"},\"mode\":\"0o644\",\"sha256\":\"979991e9acc79b8034a37d94d539641c34c51d26cb4438c4a26a82cb430fe5b9\",\"text\":true},{\"bytes\":173,\"descriptor\":{\"basename\":\"homelab-appbackup-postgres-batch.timer\",\"class\":\"etc\",\"path_sha256\":\"6b0d177f5c4602de757ad64b33c418f15605c299c242c736049f5dfb88394472\"},\"mode\":\"0o644\",\"sha256\":\"665933e86019df10914612df67e56b088c9eaed2f1861b9ed56555ac0febd789\",\"text\":true},{\"bytes\":417,\"descriptor\":{\"basename\":\"homelab-appbackup-sqlite-batch.service\",\"class\":\"etc\",\"path_sha256\":\"37d66bf09f5b1b10a1fd8dc30ec5f271c77148e98ad58dc52a48c41959881b1e\"},\"mode\":\"0o644\",\"sha256\":\"0d18769b26baae048a68f85f403893b22c67fb2852cd3a14ff1cf909f5d34d76\",\"text\":true},{\"bytes\":171,\"descriptor\":{\"basename\":\"homelab-appbackup-sqlite-batch.timer\",\"class\":\"etc\",\"path_sha256\":\"3d73c398b6366337b550ac6209655912e9d3af21f04c2943e9cd347fdab96661\"},\"mode\":\"0o644\",\"sha256\":\"838a1ee3e034c0fef373efb6639e96b1fdc1b858eaafaca2f877fd26e463f9b8\",\"text\":true},{\"bytes\":181,\"descriptor\":{\"basename\":\"homelab-authentik-backup.service\",\"class\":\"etc\",\"path_sha256\":\"b76cd271e6dd863922b8a036e6cbf4c121eb2f4a3a740050f11b83d26e09bfc6\"},\"mode\":\"0o644\",\"sha256\":\"81a709901db99eaea51915af0b69d923d1b605ba7927b6fb95583f8b297b84e7\",\"text\":true},{\"bytes\":208,\"descriptor\":{\"basename\":\"homelab-authentik-backup.timer\",\"class\":\"etc\",\"path_sha256\":\"1927d108c1fd89d29bbcd8398fcd7922e61ca8f43cbe1d834ca22fe39fd6d67c\"},\"mode\":\"0o644\",\"sha256\":\"36aea53d4ff6d0b4cdb20925aa41a38db0485c2ba2bd632ebcec6f25a68ec54c\",\"text\":true},{\"bytes\":259,\"descriptor\":{\"basename\":\"homelab-auto-backup.service\",\"class\":\"etc\",\"path_sha256\":\"ce57706dafbf1b1c70c85e89878e68fdc3265f68223debf22a14b4a4c5a5fc9e\"},\"mode\":\"0o644\",\"sha256\":\"d8015c7137e58bada7519d60e0e35e803fca147078baf379ab439ee52295a018\",\"text\":true},{\"bytes\":205,\"descriptor\":{\"basename\":\"homelab-auto-backup.timer\",\"class\":\"etc\",\"path_sha256\":\"7496836d1c027328616a26ec045e8c3bd5a71175151f2acbe8a62e271021adc7\"},\"mode\":\"0o644\",\"sha256\":\"2e2b2b21ddc5884b3f54fa9158029f1450846b391815e6d1f2e0300825eddd58\",\"text\":true},{\"bytes\":131,\"descriptor\":{\"basename\":\"homelab-backup-coverage-matrix.service\",\"class\":\"etc\",\"path_sha256\":\"44024c71ae439561429d05233d33943b83399cdc1e15ae0ba2c9b5989355ddda\"},\"mode\":\"0o644\",\"sha256\":\"3903036cfc32a2f5e365549bf5bc7b3946f700fdddf96f2718ef2f53b4f1ab3c\",\"text\":true},{\"bytes\":164,\"descriptor\":{\"basename\":\"homelab-backup-coverage-matrix.timer\",\"class\":\"etc\",\"path_sha256\":\"5c1338128ec2f8c11bc7341b88c694d6c0eb421ff8e8965f81f32e8f6af55250\"},\"mode\":\"0o644\",\"sha256\":\"a193e47aa8524bdd00c9ae9947299767801a4faf49d2b0d2c0d83d3bc4ddf40f\",\"text\":true},{\"bytes\":246,\"descriptor\":{\"basename\":\"homelab-backup-freshness.service\",\"class\":\"etc\",\"path_sha256\":\"4ae520fa731e2cbc6402fce317e07b15b67f8a28da3fc12e603dd53ebef877a6\"},\"mode\":\"0o644\",\"sha256\":\"b8907cedd41c6a6640d2e7bbf80b0d340dbb629526786fd97d8fc85f950a1a5e\",\"text\":true},{\"bytes\":249,\"descriptor\":{\"basename\":\"homelab-backup-freshness.service.bak.20260703T091211Z\",\"class\":\"etc\",\"path_sha256\":\"11da50b99cb5130fff2ead01cef7fc81fed05d92d6d542492b55a97f63fe0eed\"},\"mode\":\"0o644\",\"sha256\":\"725db645150fae38980a40efe5e213f83fef5bdae1a89662da3caebc22fdf846\",\"text\":true},{\"bytes\":201,\"descriptor\":{\"basename\":\"homelab-backup-freshness.timer\",\"class\":\"etc\",\"path_sha256\":\"358102a7e8b92a01ce7cd7492af821b847a19015c75d68673b42039e11688582\"},\"mode\":\"0o644\",\"sha256\":\"c9b35236cdad23b18f968229bd67b66ef6e402daf01b44414754eca8d21b47b0\",\"text\":true},{\"bytes\":124,\"descriptor\":{\"basename\":\"homelab-backup-healthcheck.service\",\"class\":\"etc\",\"path_sha256\":\"72b8190b110b60a9c7f4a0a02a0862bb8a6d5a57f8e7909fe0fe7c2f406ec665\"},\"mode\":\"0o644\",\"sha256\":\"dbe8f6edfb60575f1df5b0b8bd96442e194ed8a126e3b47a28f7460de2969197\",\"text\":true},{\"bytes\":204,\"descriptor\":{\"basename\":\"homelab-backup-healthcheck.timer\",\"class\":\"etc\",\"path_sha256\":\"834f8b351870fda9dde70071076b07991ffcdf83a4ac0e50adf52f50bbd85b61\"},\"mode\":\"0o644\",\"sha256\":\"24e78312708659ad93068e3b7a9ae2af66658393abc406fd2c80d45584a801b0\",\"text\":true},{\"bytes\":187,\"descriptor\":{\"basename\":\"homelab-backup-matrix-refresh.service\",\"class\":\"etc\",\"path_sha256\":\"7d91611f3ad2182f7973122749a2eabf3767bf999b72266497171f52a10edadb\"},\"mode\":\"0o644\",\"sha256\":\"864cff5bd2dc6b748e2a9788d7b7908246619022ac4aaea70de5223864c7e84c\",\"text\":true},{\"bytes\":217,\"descriptor\":{\"basename\":\"homelab-backup-matrix-refresh.timer\",\"class\":\"etc\",\"path_sha256\":\"0aee495d48f892152de2bdf525eb33ba4c1a2169be9c7d26051d84b1508e8d75\"},\"mode\":\"0o644\",\"sha256\":\"708eb9721cf0bbe5ebf282a29dbb419372b1351789f720f6d554b1e608aea359\",\"text\":true},{\"bytes\":159,\"descriptor\":{\"basename\":\"homelab-backup-sla-health.service\",\"class\":\"etc\",\"path_sha256\":\"946184204f79931a710450cd3893a93b84b6135d330b47fd1899ad2ac86e9f1f\"},\"mode\":\"0o644\",\"sha256\":\"a97266ea9b01dbfe93e7217b489ae9b1fa8ab968581ec1b0a05a7ec7f376fac2\",\"text\":true},{\"bytes\":169,\"descriptor\":{\"basename\":\"homelab-backup-sla-health.timer\",\"class\":\"etc\",\"path_sha256\":\"81a01289fc98b279c7d2faa929b76e5c6c9fa0bc17cb479c18342149e2c1907e\"},\"mode\":\"0o644\",\"sha256\":\"913db5262172bf20f4213fcca892798a460b370f218ae23910ad31925e6270d5\",\"text\":true},{\"bytes\":197,\"descriptor\":{\"basename\":\"homelab-beszel-backup.service\",\"class\":\"etc\",\"path_sha256\":\"d4cbaad62a74d3518645ca98a306b5205f28d1b9e9b1a34de15f3afa082240a9\"},\"mode\":\"0o644\",\"sha256\":\"3ad161b2fc12b6003d3aed70d41009100b42b564c2f6d15406607ba1226c1309\",\"text\":true},{\"bytes\":202,\"descriptor\":{\"basename\":\"homelab-beszel-backup.timer\",\"class\":\"etc\",\"path_sha256\":\"57e5bc30ce6147263f14799092a51da572867f4efc203565af4f2bb2a44be875\"},\"mode\":\"0o644\",\"sha256\":\"ed86409337d0994e0e3abae3df19055d658b7138714515e6dbe6c685083af1dd\",\"text\":true},{\"bytes\":219,\"descriptor\":{\"basename\":\"homelab-blackbox-exporter-backup.service\",\"class\":\"etc\",\"path_sha256\":\"2d6858d54a3c3461df4d40f42e00fc9554aa72fa6be35f410a21fbbf6860a579\"},\"mode\":\"0o644\",\"sha256\":\"2fcd8c6a8b4c8168fcaeb3a5191351fdb8cd0925f76fe2be108ced5afe212fe5\",\"text\":true},{\"bytes\":224,\"descriptor\":{\"basename\":\"homelab-blackbox-exporter-backup.timer\",\"class\":\"etc\",\"path_sha256\":\"f5a77d2f8ceecfd144cf6dd6e8fd6845868b281590b45ea6c3704464817679af\"},\"mode\":\"0o644\",\"sha256\":\"840cb01e3acf221a2ae5b457e6ae4f12b49195c5ca055dfd1192847f6e78b895\",\"text\":true},{\"bytes\":147,\"descriptor\":{\"basename\":\"homelab-capacity-risk.service\",\"class\":\"etc\",\"path_sha256\":\"91368f3c372f5038c5ae38fe06eb8f96b2a1c269e2f6102f4528c46311d13b33\"},\"mode\":\"0o644\",\"sha256\":\"aa4302a6681da2726845444affbb68d1a97ade99a9aa2c138f48b35a0a8c0cd9\",\"text\":true},{\"bytes\":161,\"descriptor\":{\"basename\":\"homelab-capacity-risk.timer\",\"class\":\"etc\",\"path_sha256\":\"79c8ef12bf1233a4ac4ea26e4ba07e4c247402a20635818a1576dbc21fc09b77\"},\"mode\":\"0o644\",\"sha256\":\"6affbae63cc7be026318e8034c6bfcc2b1c877ee57c17f81dff9fa448f0befe9\",\"text\":true},{\"bytes\":231,\"descriptor\":{\"basename\":\"homelab-cluster-admin-incident-engine-backup.service\",\"class\":\"etc\",\"path_sha256\":\"dbe77771fe5d21100579e740fda3b915bfeafaad41727e9527d10e9e55e3d5c5\"},\"mode\":\"0o644\",\"sha256\":\"bc7f9010fd6e97dff3bbedd2fd2088d65836a1a842cbd6d465163251e2a7db31\",\"text\":true},{\"bytes\":238,\"descriptor\":{\"basename\":\"homelab-cluster-admin-incident-engine-backup.timer\",\"class\":\"etc\",\"path_sha256\":\"3bd1f133505c5728e6c1b221d517f927e5317d81be89c64389dd67cab4945cfd\"},\"mode\":\"0o644\",\"sha256\":\"7b34396b19b8d9139e3f59d7a03a5bbfe08440c95d6a1d85031057665a724d54\",\"text\":true},{\"bytes\":235,\"descriptor\":{\"basename\":\"homelab-cluster-admin-inventory-sync.service\",\"class\":\"etc\",\"path_sha256\":\"f09f06a23ceec401b2846dba087c234a271d36c0f8a64d700169963260ccc1ed\"},\"mode\":\"0o644\",\"sha256\":\"5237b68c736e77ff0108c77321bbe9b9cb7285e3a23d135361a43cd2fcb74264\",\"text\":true},{\"bytes\":235,\"descriptor\":{\"basename\":\"homelab-cluster-admin-inventory-sync.timer\",\"class\":\"etc\",\"path_sha256\":\"905fa93f675463931a73457f7b182241f09b0216e710148918d4465b58f8124c\"},\"mode\":\"0o644\",\"sha256\":\"4c9f51447b5d8f75fa05b494390e74089b6a2880ce899325643d47be4ce2180e\",\"text\":true},{\"bytes\":142,\"descriptor\":{\"basename\":\"homelab-cluster-admin-pull.service\",\"class\":\"etc\",\"path_sha256\":\"a125ccdf5af51e63b6487adb7b544fa854bb229a8a948aa50ae36aad7f8e3d6c\"},\"mode\":\"0o644\",\"sha256\":\"4a30f00113b7c68478f1cd2c8be959aed1931c55a0c7f7c99fda06cb742b914e\",\"text\":true},{\"bytes\":145,\"descriptor\":{\"basename\":\"homelab-cluster-admin-pull.timer\",\"class\":\"etc\",\"path_sha256\":\"d256eb912a67a960f60dbafc7e2ac722a2dfb8b291f31dbc1dcda55fb5c8d861\"},\"mode\":\"0o644\",\"sha256\":\"5e4936d1379c96088b17816a7aba42d77051009bd0938a253b3487bcb3b658a6\",\"text\":true},{\"bytes\":162,\"descriptor\":{\"basename\":\"homelab-cluster-admin-webpanel-sync.service\",\"class\":\"etc\",\"path_sha256\":\"fdf71842c5c7d93b8b0fd9fa504634867092161c8fcebc0b5fd3872e1b5e8696\"},\"mode\":\"0o644\",\"sha256\":\"d8091d4bb52513929cd7df742532977f70e08ee60ab8762a8f027e5863612c3b\",\"text\":true},{\"bytes\":169,\"descriptor\":{\"basename\":\"homelab-cluster-admin-webpanel-sync.timer\",\"class\":\"etc\",\"path_sha256\":\"2bfb342d31abcb9a979ad8d8c6abdd0f6924e4d491f87cf172ba8fe1300c723a\"},\"mode\":\"0o644\",\"sha256\":\"ef420cea1b506ff7ea6dbd02c1b19167e5771030f4f52eb850aa05b7e3eed094\",\"text\":true},{\"bytes\":314,\"descriptor\":{\"basename\":\"homelab-cluster-internal-ip.service\",\"class\":\"etc\",\"path_sha256\":\"7febe1024cc75fbd4a00668d5074f501f0adff874d3dbc0bade2ddea4455ef13\"},\"mode\":\"0o644\",\"sha256\":\"813fca6cacb2075a6dc7a6cead8d2fbf6234db47d86825725def2fa4b5095dcb\",\"text\":true},{\"bytes\":147,\"descriptor\":{\"basename\":\"homelab-cluster-passport.service\",\"class\":\"etc\",\"path_sha256\":\"e53262b977c5305b25d282c332ae6caf4a145111b9b97530a5335630be3ead8f\"},\"mode\":\"0o644\",\"sha256\":\"6add64848c301bfba276581c69d05ff854add9783e6d56d224a89624b775ea78\",\"text\":true},{\"bytes\":158,\"descriptor\":{\"basename\":\"homelab-cluster-passport.timer\",\"class\":\"etc\",\"path_sha256\":\"cd4a5110a0ba10e5cbc171421b3a2072e437f2669ec0e6a6d044dca22aa99a50\"},\"mode\":\"0o644\",\"sha256\":\"30c2f09882c3c19ef818c5e8059510500a0c789273627266b4421453c8a90ca8\",\"text\":true},{\"bytes\":164,\"descriptor\":{\"basename\":\"homelab-crypto-portfolio-backup.service\",\"class\":\"etc\",\"path_sha256\":\"ff2ccb6b70941c3a67e8dd46de18c54aa2957e394a1f77ce6e69eb81fbc18b1c\"},\"mode\":\"0o644\",\"sha256\":\"26893d40465a1d1072582d0e30c9ba59187b78a0969fdb638c2f413038675b7f\",\"text\":true},{\"bytes\":162,\"descriptor\":{\"basename\":\"homelab-crypto-portfolio-backup.timer\",\"class\":\"etc\",\"path_sha256\":\"dda278ff41c9115e2362619b71f23f0e17c1256fbd43c3a1a2190346a6f8f6d9\"},\"mode\":\"0o644\",\"sha256\":\"4c77b430d616e2da1f17a9a4ae602cb1a627911b87ce95be3ed7702aeb1e6641\",\"text\":true},{\"bytes\":197,\"descriptor\":{\"basename\":\"homelab-crypto-portfolio-chart-health.service\",\"class\":\"etc\",\"path_sha256\":\"2afd3cfb8fc1344f45b5d761a31234f9ff724aac9389826524948f3fd2f34ccd\"},\"mode\":\"0o644\",\"sha256\":\"265d173e16c3c6c3dded360d0bff1e96bd8fa38a07cb21c7bb89880a38bf1964\",\"text\":true},{\"bytes\":230,\"descriptor\":{\"basename\":\"homelab-crypto-portfolio-chart-health.timer\",\"class\":\"etc\",\"path_sha256\":\"5ff52b5a7e794bb77539fda37700faefb8c86f7f5b613eb783ad0b129d7333f8\"},\"mode\":\"0o644\",\"sha256\":\"173d663322fd8d4069d142a1c77a594735fe5b44cfe0cc0782d9dc40f428ac41\",\"text\":true},{\"bytes\":127,\"descriptor\":{\"basename\":\"homelab-dependency-map-check.service\",\"class\":\"etc\",\"path_sha256\":\"5b71a334eca77c0d514954f6d9be94d4f23d6cdcfbaf4c761f7867414b0e65cb\"},\"mode\":\"0o644\",\"sha256\":\"adec2fe651ed4870378aa6f07a0c50b81c82cd520a368dec91d27a11d4b85ca9\",\"text\":true},{\"bytes\":162,\"descriptor\":{\"basename\":\"homelab-dependency-map-check.timer\",\"class\":\"etc\",\"path_sha256\":\"a2c5b8bd341bd69b8e225554fc24890e2aa1e25c9e70b4d986c599847a827792\"},\"mode\":\"0o644\",\"sha256\":\"a1a8aa7ee0fd125768df19595c05372c4643e54bd80eab0a7a59f3a3d22db9fc\",\"text\":true},{\"bytes\":159,\"descriptor\":{\"basename\":\"homelab-desired-state-sync.service\",\"class\":\"etc\",\"path_sha256\":\"be9d39311482a58e018015da172c7573c785df96f882c8a4fe37135a9d8f58fd\"},\"mode\":\"0o644\",\"sha256\":\"98c71772e1af6b62459df2dc8d5c4b6c153933389dfe3c0dafef4c3ec1df3d1b\",\"text\":true},{\"bytes\":168,\"descriptor\":{\"basename\":\"homelab-desired-state-sync.timer\",\"class\":\"etc\",\"path_sha256\":\"c2efa39355780cb4c44a2d964f51966bb637dc0dba645c8e2654e899519ecfb0\"},\"mode\":\"0o644\",\"sha256\":\"d948911a746299dcb61e42eb1434b1ccdfd967f1404c9ab183c262acf81ff58a\",\"text\":true},{\"bytes\":133,\"descriptor\":{\"basename\":\"homelab-disk-space-health.service\",\"class\":\"etc\",\"path_sha256\":\"9a29b800386cc8c9692d535fa532d17cff8d5f250ae9ac16676682fd813b5b53\"},\"mode\":\"0o644\",\"sha256\":\"1737c5e53d5266f681f26df007774e8283a5da5ad5c2f9d5503798789dc34e00\",\"text\":true},{\"bytes\":188,\"descriptor\":{\"basename\":\"homelab-disk-space-health.timer\",\"class\":\"etc\",\"path_sha256\":\"f612d0cc6c7f19d63a8c2d11cfc45dadafd9b83553cb9a1e9a1c9dbe75a34fc0\"},\"mode\":\"0o644\",\"sha256\":\"67ad58fd20e74775c8dc12e08fceb7369e0c995101250a6707ce9180af92426b\",\"text\":true}],\"files_examined\":80,\"mutation_outcome\":\"NO_MUTATION\",\"next_action\":\"FIX_ONLY_PROVEN_READ_ONLY_SOURCE_MAP_GAP\",\"output_truncated_in_json\":false,\"patch_points\":[{\"fields\":[\"argv\",\"content_b64\",\"evidence\",\"payload\",\"portal\",\"secret\"],\"file\":{\"basename\":\"homelab-command-adapter\",\"class\":\"usr_local\",\"path_sha256\":\"c2e3b43f1f858c6fa265dc276d6a6a29e0cd25e4a127fbc093b8c8d9512bb739\"},\"process_calls\":[{\"call\":\"subprocess.run\",\"keywords\":[\"check\",\"env\",\"stderr\",\"stdin\",\"stdout\",\"text\",\"timeout\"],\"line\":664},{\"call\":\"subprocess.Popen\",\"keywords\":[\"close_fds\",\"env\",\"start_new_session\",\"stderr\",\"stdin\",\"stdout\"],\"line\":1626},{\"call\":\"subprocess.Popen\",\"keywords\":[\"close_fds\",\"env\",\"start_new_session\",\"stderr\",\"stdin\",\"stdout\",\"text\"],\"line\":2056}],\"redaction_symbols\":[\"create_evidence_bundle\",\"evidence_url\",\"remote_evidence_presign\",\"sanitize_state\",\"sign_evidence\",\"upload_evidence\"],\"routes\":[],\"sha256\":\"a1a7a615c99568bf915d084cc476f0ebf54ab0eedf3ecd578c4b0e072f58c43d\"}],\"rc\":0,\"read_only\":true,\"rollback_restored\":null,\"rollback_started\":false,\"root_cause_classification\":\"ADAPTER_PORTAL_SOURCE_MAP_INCOMPLETE\",\"schema\":1,\"status\":\"OK\",\"units\":[{\"environment_files_declared\":false,\"show_rc\":0,\"stderr_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"unit\":\"homelab-command-adapter.service\",\"user_class\":\"root\",\"working_directory_declared\":false},{\"environment_files_declared\":false,\"show_rc\":0,\"stderr_sha256\":\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\"unit\":\"homelab-command-portal.service\",\"user_class\":\"non_root\",\"working_directory_declared\":false}]}\n" + "output": "HOMELAB_RESULT_CONTRACT={\"changes_made\":false,\"command_id\":\"HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z\",\"command_rc\":0,\"control_plane_error\":null,\"exact_invalid_risk_source_found\":true,\"matching_file_count\":2,\"matching_file_manifest_sha256\":\"af904aec1040e2968d87c5e61b6ced9f013d49a0c7f5e0a48f70b292df1a966c\",\"mutation_outcome\":\"NO_MUTATION\",\"rc\":0,\"report_bytes\":20215,\"report_sha256\":\"4b4749cedde3bcaed3f4b01824f2c5de02d90e6525a59e5fd4e8b1b545344a95\",\"risk_candidate_tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"],\"risk_enum_confirmed\":true,\"rollback_restored\":false,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\n{\"candidate_roots\":[\"/\",\"/etc/systemd/system\",\"/etc/systemd/system/homelab-command-adapter.service\",\"/opt\",\"/srv\",\"/usr/bin\",\"/usr/bin/python3.13\",\"/usr/local\",\"/usr/local/lib\",\"/usr/local/sbin\",\"/usr/local/sbin/homelab-command-adapter\"],\"changes_made\":false,\"command_id\":\"HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z\",\"mutation_outcome\":\"NO_MUTATION\",\"read_only\":true,\"risk_enum\":{\"candidate_tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"],\"exact_enum_confirmed\":true,\"proof\":[{\"context\":[{\"line\":380,\"text\":\" ):\"},{\"line\":381,\"text\":\" raise AdapterError(\\\"invalid timeout_seconds\\\")\"},{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"}],\"match_line\":383,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"REVERSIBLE\"]},{\"context\":[{\"line\":381,\"text\":\" raise AdapterError(\\\"invalid timeout_seconds\\\")\"},{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"}],\"match_line\":384,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"REVERSIBLE\"]},{\"context\":[{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"}],\"match_line\":385,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]},{\"context\":[{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"}],\"match_line\":386,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]},{\"context\":[{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"}],\"match_line\":387,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]},{\"context\":[{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"},{\"line\":391,\"text\":\" flags = document.get(\\\"change_flags\\\")\"}],\"match_line\":388,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]},{\"context\":[{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"},{\"line\":391,\"text\":\" flags = document.get(\\\"change_flags\\\")\"},{\"line\":392,\"text\":\" if not isinstance(flags, dict):\"}],\"match_line\":389,\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"tokens\":[\"HIGH\",\"READ_ONLY\",\"REVERSIBLE\"]}]},\"rollback_restored\":false,\"rollback_started\":false,\"scan\":{\"exact_invalid_mode_matches\":1,\"exact_invalid_risk_matches\":1,\"files_scanned\":3,\"matching_file_manifest_sha256\":\"af904aec1040e2968d87c5e61b6ced9f013d49a0c7f5e0a48f70b292df1a966c\",\"matching_files\":2,\"uppercase_enum_tokens\":[\"FAIL\",\"HIGH\",\"NONE\",\"READ_ONLY\",\"REVERSIBLE\",\"UNKNOWN\",\"USAGE\"]},\"schema\":1,\"source_matches\":[{\"bytes\":21321,\"matches\":[{\"context\":[{\"line\":8,\"text\":\"import sys\"},{\"line\":9,\"text\":\"from pathlib import Path\"},{\"line\":10,\"text\":\"\"},{\"line\":11,\"text\":\"raw_path, command_id, mode, command_rc = sys.argv[1:]\"},{\"line\":12,\"text\":\"command_rc = int(command_rc)\"},{\"line\":13,\"text\":\"\"},{\"line\":14,\"text\":\"result = {\"}],\"match_line\":11},{\"context\":[{\"line\":21,\"text\":\" \\\"error\\\": \\\"NONE\\\",\"},{\"line\":22,\"text\":\"}\"},{\"line\":23,\"text\":\"\"},{\"line\":24,\"text\":\"if mode == \\\"change\\\":\"},{\"line\":25,\"text\":\" result = {\"},{\"line\":26,\"text\":\" \\\"valid\\\": False,\"},{\"line\":27,\"text\":\" \\\"status\\\": \\\"UNKNOWN\\\",\"}],\"match_line\":24},{\"context\":[{\"line\":188,\"text\":\"usage() {\"},{\"line\":189,\"text\":\" cat >&2 <<'USAGE'\"},{\"line\":190,\"text\":\"Usage:\"},{\"line\":191,\"text\":\" homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]\"},{\"line\":192,\"text\":\"\"},{\"line\":193,\"text\":\"MODE:\"},{\"line\":194,\"text\":\" read-only\"}],\"match_line\":191},{\"context\":[{\"line\":190,\"text\":\"Usage:\"},{\"line\":191,\"text\":\" homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]\"},{\"line\":192,\"text\":\"\"},{\"line\":193,\"text\":\"MODE:\"},{\"line\":194,\"text\":\" read-only\"},{\"line\":195,\"text\":\" verify\"},{\"line\":196,\"text\":\" change\"}],\"match_line\":193},{\"context\":[{\"line\":206,\"text\":\"[ \\\"$#\\\" -ge 5 ] || usage\"},{\"line\":207,\"text\":\"\"},{\"line\":208,\"text\":\"COMMAND_ID=\\\"$1\\\"\"},{\"line\":209,\"text\":\"MODE=\\\"$2\\\"\"},{\"line\":210,\"text\":\"COMPONENT=\\\"$3\\\"\"},{\"line\":211,\"text\":\"shift 3\"},{\"line\":212,\"text\":\"\"}],\"match_line\":209},{\"context\":[{\"line\":230,\"text\":\" ;;\"},{\"line\":231,\"text\":\"esac\"},{\"line\":232,\"text\":\"\"},{\"line\":233,\"text\":\"case \\\"$MODE\\\" in\"},{\"line\":234,\"text\":\" read-only|verify|change|transport-test)\"},{\"line\":235,\"text\":\" ;;\"},{\"line\":236,\"text\":\" *)\"}],\"match_line\":233},{\"context\":[{\"line\":304,\"text\":\"\"},{\"line\":305,\"text\":\"COMMAND_SHA256=\\\"$(\"},{\"line\":306,\"text\":\" {\"},{\"line\":307,\"text\":\" printf '%s\\\\0' \\\"$MODE\\\"\"},{\"line\":308,\"text\":\" printf '%s\\\\0' \\\"$COMPONENT\\\"\"},{\"line\":309,\"text\":\" printf '%s\\\\0' \\\"$@\\\"\"},{\"line\":310,\"text\":\" } |\"}],\"match_line\":307},{\"context\":[{\"line\":337,\"text\":\"RESULT_CONTRACT_ERROR='NONE'\"},{\"line\":338,\"text\":\"COMMAND_RC=''\"},{\"line\":339,\"text\":\"\"},{\"line\":340,\"text\":\"if [ \\\"$MODE\\\" = change ]; then\"},{\"line\":341,\"text\":\" CHANGE_DECLARED=true\"},{\"line\":342,\"text\":\" RESULT_CONTRACT_VALID=false\"},{\"line\":343,\"text\":\" CONTRACT_STATUS='UNKNOWN'\"}],\"match_line\":340},{\"context\":[{\"line\":416,\"text\":\" read_mutation_contract \\\\\"},{\"line\":417,\"text\":\" \\\"$RAW_FILE\\\" \\\\\"},{\"line\":418,\"text\":\" \\\"$COMMAND_ID\\\" \\\\\"},{\"line\":419,\"text\":\" \\\"$MODE\\\" \\\\\"},{\"line\":420,\"text\":\" \\\"$COMMAND_RC\\\"\"},{\"line\":421,\"text\":\" )\"},{\"line\":422,\"text\":\"\"}],\"match_line\":419},{\"context\":[{\"line\":420,\"text\":\" \\\"$COMMAND_RC\\\"\"},{\"line\":421,\"text\":\" )\"},{\"line\":422,\"text\":\"\"},{\"line\":423,\"text\":\" if [ \\\"$MODE\\\" = change ]; then\"},{\"line\":424,\"text\":\" if [ \\\"$RESULT_CONTRACT_VALID\\\" != true ]; then\"},{\"line\":425,\"text\":\" RC=76\"},{\"line\":426,\"text\":\" STATUS='FAIL'\"}],\"match_line\":423},{\"context\":[{\"line\":547,\"text\":\" \\\"$STATUS\\\" \\\\\"},{\"line\":548,\"text\":\" \\\"$RC\\\" \\\\\"},{\"line\":549,\"text\":\" \\\"$HOST_SHORT\\\" \\\\\"},{\"line\":550,\"text\":\" \\\"$MODE\\\" \\\\\"},{\"line\":551,\"text\":\" \\\"$COMPONENT\\\" \\\\\"},{\"line\":552,\"text\":\" \\\"$STARTED_AT\\\" \\\\\"},{\"line\":553,\"text\":\" \\\"$FINISHED_AT\\\" \\\\\"}],\"match_line\":550},{\"context\":[{\"line\":579,\"text\":\" status,\"},{\"line\":580,\"text\":\" rc,\"},{\"line\":581,\"text\":\" host,\"},{\"line\":582,\"text\":\" mode,\"},{\"line\":583,\"text\":\" component,\"},{\"line\":584,\"text\":\" started,\"},{\"line\":585,\"text\":\" finished,\"}],\"match_line\":582},{\"context\":[{\"line\":634,\"text\":\" \\\"status\\\": status,\"},{\"line\":635,\"text\":\" \\\"rc\\\": int(rc),\"},{\"line\":636,\"text\":\" \\\"host\\\": host,\"},{\"line\":637,\"text\":\" \\\"mode\\\": mode,\"},{\"line\":638,\"text\":\" \\\"component\\\": component,\"},{\"line\":639,\"text\":\" \\\"started_at_utc\\\": started,\"},{\"line\":640,\"text\":\" \\\"finished_at_utc\\\": finished,\"}],\"match_line\":637},{\"context\":[{\"line\":694,\"text\":\" echo \\\"STATUS=$STATUS\\\"\"},{\"line\":695,\"text\":\" echo \\\"RC=$RC\\\"\"},{\"line\":696,\"text\":\" echo \\\"HOST=$HOST_SHORT\\\"\"},{\"line\":697,\"text\":\" echo \\\"MODE=$MODE\\\"\"},{\"line\":698,\"text\":\" echo \\\"COMPONENT=$COMPONENT\\\"\"},{\"line\":699,\"text\":\" echo 'REFERENCE_REGISTER_CHECK=OK'\"},{\"line\":700,\"text\":\" echo \\\"REFERENCE_SHA256=$REFERENCE_SHA256\\\"\"}],\"match_line\":697}],\"path\":\"/usr/local/sbin/homelab-chat-run\",\"sha256\":\"b248a4c32c9cc64e5747e7dce6c7fc0a23f5124a77c71ce72e27a81aceae9d2d\"},{\"bytes\":86019,\"matches\":[{\"context\":[{\"line\":119,\"text\":\" \\\"transport-test\\\",\"},{\"line\":120,\"text\":\"}\"},{\"line\":121,\"text\":\"ALLOWED_RISKS = {\"},{\"line\":122,\"text\":\" \\\"READ_ONLY\\\",\"},{\"line\":123,\"text\":\" \\\"REVERSIBLE\\\",\"},{\"line\":124,\"text\":\" \\\"HIGH\\\",\"},{\"line\":125,\"text\":\"}\"}],\"match_line\":122},{\"context\":[{\"line\":129,\"text\":\" \\\"command_id\\\",\"},{\"line\":130,\"text\":\" \\\"title\\\",\"},{\"line\":131,\"text\":\" \\\"summary\\\",\"},{\"line\":132,\"text\":\" \\\"mode\\\",\"},{\"line\":133,\"text\":\" \\\"component\\\",\"},{\"line\":134,\"text\":\" \\\"target\\\",\"},{\"line\":135,\"text\":\" \\\"timeout_seconds\\\",\"}],\"match_line\":132},{\"context\":[{\"line\":133,\"text\":\" \\\"component\\\",\"},{\"line\":134,\"text\":\" \\\"target\\\",\"},{\"line\":135,\"text\":\" \\\"timeout_seconds\\\",\"},{\"line\":136,\"text\":\" \\\"risk\\\",\"},{\"line\":137,\"text\":\" \\\"change_flags\\\",\"},{\"line\":138,\"text\":\" \\\"rollback\\\",\"},{\"line\":139,\"text\":\" \\\"argv\\\",\"}],\"match_line\":136},{\"context\":[{\"line\":143,\"text\":\"}\"},{\"line\":144,\"text\":\"ALLOWED_PAYLOAD_FIELDS = {\"},{\"line\":145,\"text\":\" \\\"path\\\",\"},{\"line\":146,\"text\":\" \\\"mode\\\",\"},{\"line\":147,\"text\":\" \\\"sha256\\\",\"},{\"line\":148,\"text\":\" \\\"content_b64\\\",\"},{\"line\":149,\"text\":\"}\"}],\"match_line\":146},{\"context\":[{\"line\":262,\"text\":\"\"},{\"line\":263,\"text\":\"def ensure_layout() -> None:\"},{\"line\":264,\"text\":\" portal = pwd.getpwnam(PORTAL_USER)\"},{\"line\":265,\"text\":\" for path, mode in (\"},{\"line\":266,\"text\":\" (ROOT, 0o750),\"},{\"line\":267,\"text\":\" (STATE_DIR, 0o750),\"},{\"line\":268,\"text\":\" (CAPSULE_DIR, 0o700),\"}],\"match_line\":265},{\"context\":[{\"line\":270,\"text\":\" ):\"},{\"line\":271,\"text\":\" path.mkdir(parents=True, exist_ok=True)\"},{\"line\":272,\"text\":\" os.chown(path, 0, portal.pw_gid)\"},{\"line\":273,\"text\":\" os.chmod(path, mode)\"},{\"line\":274,\"text\":\"\"},{\"line\":275,\"text\":\"\"},{\"line\":276,\"text\":\"def unique_json_loads(raw: bytes) -> dict[str, Any]:\"}],\"match_line\":273},{\"context\":[{\"line\":332,\"text\":\"\"},{\"line\":333,\"text\":\" if document.get(\\\"schema_version\\\") != 1:\"},{\"line\":334,\"text\":\" raise AdapterError(\\\"unsupported capsule schema\\\")\"},{\"line\":335,\"text\":\" if document.get(\\\"kind\\\") != \\\"homelab-command-capsule\\\":\"},{\"line\":336,\"text\":\" raise AdapterError(\\\"invalid capsule kind\\\")\"},{\"line\":337,\"text\":\"\"},{\"line\":338,\"text\":\" command_id = validate_text(\"}],\"match_line\":335},{\"context\":[{\"line\":366,\"text\":\" maximum=2000,\"},{\"line\":367,\"text\":\" )\"},{\"line\":368,\"text\":\"\"},{\"line\":369,\"text\":\" mode = document.get(\\\"mode\\\")\"},{\"line\":370,\"text\":\" if mode not in ALLOWED_MODES:\"},{\"line\":371,\"text\":\" raise AdapterError(\\\"invalid mode\\\")\"},{\"line\":372,\"text\":\" if document.get(\\\"target\\\") != \\\"pve01\\\":\"}],\"match_line\":369},{\"context\":[{\"line\":367,\"text\":\" )\"},{\"line\":368,\"text\":\"\"},{\"line\":369,\"text\":\" mode = document.get(\\\"mode\\\")\"},{\"line\":370,\"text\":\" if mode not in ALLOWED_MODES:\"},{\"line\":371,\"text\":\" raise AdapterError(\\\"invalid mode\\\")\"},{\"line\":372,\"text\":\" if document.get(\\\"target\\\") != \\\"pve01\\\":\"},{\"line\":373,\"text\":\" raise AdapterError(\\\"only pve01 target is supported\\\")\"}],\"match_line\":370},{\"context\":[{\"line\":368,\"text\":\"\"},{\"line\":369,\"text\":\" mode = document.get(\\\"mode\\\")\"},{\"line\":370,\"text\":\" if mode not in ALLOWED_MODES:\"},{\"line\":371,\"text\":\" raise AdapterError(\\\"invalid mode\\\")\"},{\"line\":372,\"text\":\" if document.get(\\\"target\\\") != \\\"pve01\\\":\"},{\"line\":373,\"text\":\" raise AdapterError(\\\"only pve01 target is supported\\\")\"},{\"line\":374,\"text\":\"\"}],\"match_line\":371},{\"context\":[{\"line\":380,\"text\":\" ):\"},{\"line\":381,\"text\":\" raise AdapterError(\\\"invalid timeout_seconds\\\")\"},{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"}],\"match_line\":383},{\"context\":[{\"line\":381,\"text\":\" raise AdapterError(\\\"invalid timeout_seconds\\\")\"},{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"}],\"match_line\":384},{\"context\":[{\"line\":382,\"text\":\"\"},{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"}],\"match_line\":385},{\"context\":[{\"line\":383,\"text\":\" risk = document.get(\\\"risk\\\")\"},{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"}],\"match_line\":386},{\"context\":[{\"line\":384,\"text\":\" if risk not in ALLOWED_RISKS:\"},{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"}],\"match_line\":387},{\"context\":[{\"line\":385,\"text\":\" raise AdapterError(\\\"invalid risk\\\")\"},{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"},{\"line\":391,\"text\":\" flags = document.get(\\\"change_flags\\\")\"}],\"match_line\":388},{\"context\":[{\"line\":386,\"text\":\" if mode == \\\"change\\\" and risk not in {\\\"REVERSIBLE\\\", \\\"HIGH\\\"}:\"},{\"line\":387,\"text\":\" raise AdapterError(\\\"change capsule risk must be REVERSIBLE or HIGH\\\")\"},{\"line\":388,\"text\":\" if mode != \\\"change\\\" and risk != \\\"READ_ONLY\\\":\"},{\"line\":389,\"text\":\" raise AdapterError(\\\"non-change capsule risk must be READ_ONLY\\\")\"},{\"line\":390,\"text\":\"\"},{\"line\":391,\"text\":\" flags = document.get(\\\"change_flags\\\")\"},{\"line\":392,\"text\":\" if not isinstance(flags, dict):\"}],\"match_line\":389},{\"context\":[{\"line\":396,\"text\":\" if any(type(value) is not bool for value in flags.values()):\"},{\"line\":397,\"text\":\" raise AdapterError(\\\"change_flags values must be boolean\\\")\"},{\"line\":398,\"text\":\"\"},{\"line\":399,\"text\":\" if mode != \\\"change\\\" and any(flags.values()):\"},{\"line\":400,\"text\":\" raise AdapterError(\"},{\"line\":401,\"text\":\" \\\"non-change capsule cannot declare changes\\\"\"},{\"line\":402,\"text\":\" )\"}],\"match_line\":399},{\"context\":[{\"line\":400,\"text\":\" raise AdapterError(\"},{\"line\":401,\"text\":\" \\\"non-change capsule cannot declare changes\\\"\"},{\"line\":402,\"text\":\" )\"},{\"line\":403,\"text\":\" if mode == \\\"change\\\" and not flags[\\\"production\\\"]:\"},{\"line\":404,\"text\":\" raise AdapterError(\"},{\"line\":405,\"text\":\" \\\"change capsule must declare production change\\\"\"},{\"line\":406,\"text\":\" )\"}],\"match_line\":403},{\"context\":[{\"line\":418,\"text\":\" minimum=1,\"},{\"line\":419,\"text\":\" maximum=2000,\"},{\"line\":420,\"text\":\" )\"},{\"line\":421,\"text\":\" if mode == \\\"change\\\" and rollback[\\\"available\\\"] is not True:\"},{\"line\":422,\"text\":\" raise AdapterError(\"},{\"line\":423,\"text\":\" \\\"change capsule requires available rollback\\\"\"},{\"line\":424,\"text\":\" )\"}],\"match_line\":421}],\"path\":\"/usr/local/sbin/homelab-command-adapter\",\"sha256\":\"a1a7a615c99568bf915d084cc476f0ebf54ab0eedf3ecd578c4b0e072f58c43d\"}],\"status\":\"OK\",\"systemd_adapter\":[{\"cat_rc\":1,\"cat_stderr\":\"No files found for homelab-adapter.service.\\n\",\"show\":{\"ActiveState\":\"inactive\",\"DropInPaths\":\"\",\"FragmentPath\":\"\",\"LoadState\":\"not-found\",\"MainPID\":\"0\",\"SubState\":\"dead\",\"WorkingDirectory\":\"\"},\"show_rc\":0,\"show_stderr\":\"\",\"unit\":\"homelab-adapter.service\",\"unit_text\":\"\"},{\"cat_rc\":0,\"cat_stderr\":\"\",\"process\":{\"cmdline\":[\"/usr/bin/python3\",\"-B\",\"/usr/local/sbin/homelab-command-adapter\",\"--serve\"],\"cwd\":\"/\",\"exe\":\"/usr/bin/python3.13\",\"pid\":1131444},\"show\":{\"ActiveState\":\"active\",\"DropInPaths\":\"\",\"ExecStart\":\"{ path=/usr/bin/python3 ; argv[]=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }\",\"FragmentPath\":\"/etc/systemd/system/homelab-command-adapter.service\",\"LoadState\":\"loaded\",\"MainPID\":\"1131444\",\"SubState\":\"running\",\"WorkingDirectory\":\"\"},\"show_rc\":0,\"show_stderr\":\"\",\"unit\":\"homelab-command-adapter.service\",\"unit_text\":\"# /etc/systemd/system/homelab-command-adapter.service\\n[Unit]\\nDescription=Homelab command adapter\\nAfter=network-online.target\\nWants=network-online.target\\n\\n[Service]\\nType=simple\\nExecStart=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve\\nUser=root\\nGroup=homelab-command-portal\\nUMask=0027\\nRuntimeDirectory=homelab-command-adapter\\nRuntimeDirectoryMode=0750\\nRestart=on-failure\\nRestartSec=2\\nNoNewPrivileges=false\\nPrivateTmp=true\\nProtectClock=true\\nProtectControlGroups=true\\nProtectKernelLogs=true\\nProtectKernelModules=true\\nProtectKernelTunables=true\\nRestrictRealtime=true\\nLockPersonality=true\\nMemoryDenyWriteExecute=true\\nSystemCallArchitectures=native\\nTimeoutStopSec=15\\n\\n[Install]\\nWantedBy=multi-user.target\"}]}\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index 01c6132..ec5c78d 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,15 +1,15 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=HOMELAB-SKLADCHIK-BRIDGE-SECRET-HANDOFF-SOURCE-MAP-READ-ONLY-20260805T122000Z +COMMAND_ID=HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z STATUS=OK RC=0 HOST=pve01 MODE=verify -COMPONENT=skladchik-bridge-secret-handoff-source-map-read-only +COMPONENT=homelab-command-adapter-schema REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83 -COMMAND_SHA256=397518006b159203a533b4d5a7511d01374b37e290c4e3bf65029d55fdbbff08 +COMMAND_SHA256=8f5ea9cbbb504993bd994b501118c5e9eff048c652ee8819f91f9e1e372631f8 DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGE_DECLARED=false @@ -24,11 +24,11 @@ MUTATION_OUTCOME=NO_MUTATION SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=648a3c7a53af4486969a6a0861ab60c0417107b8079d1cff6fcaf9432962b102 -SANITIZED_OUTPUT_SHA256=648a3c7a53af4486969a6a0861ab60c0417107b8079d1cff6fcaf9432962b102 +RAW_EVIDENCE_SHA256=d491cbc5d16aa000a95ff0b394d333365a4aca69b7dd8d831e7ec7dfdedbf068 +SANITIZED_OUTPUT_SHA256=d491cbc5d16aa000a95ff0b394d333365a4aca69b7dd8d831e7ec7dfdedbf068 OUTPUT_BEGIN -HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"HOMELAB-SKLADCHIK-BRIDGE-SECRET-HANDOFF-SOURCE-MAP-READ-ONLY-20260805T122000Z","command_rc":0,"mutation_outcome":"NO_MUTATION","output_truncated_in_json":false,"rc":0,"rollback_restored":null,"rollback_started":false,"status":"OK","version":1} -{"aggregate":{"process_calls":3,"redaction_symbols":["create_evidence_bundle","evidence_url","remote_evidence_presign","sanitize_state","sign_evidence","upload_evidence"],"request_or_channel_fields":["Cookie","adapter","argv","content_b64","evidence","payload","portal","secret"],"routes":0},"analysis_ready":false,"changes_made":false,"command_id":"HOMELAB-SKLADCHIK-BRIDGE-SECRET-HANDOFF-SOURCE-MAP-READ-ONLY-20260805T122000Z","command_rc":0,"exact_exec_sha_verified":false,"file_inventory":[{"bytes":665,"descriptor":{"basename":"homelab-command-adapter.service","class":"etc","path_sha256":"afe4d91c280ac4e6e9999498b5f5d8b8842a1f33e30fd45d984879a6392bc045"},"mode":"0o644","sha256":"74d0f37878652ed9d46b53ae8556bbb30ebd683741f293c3f59b3527876ed2d7","text":true},{"bytes":86019,"descriptor":{"basename":"homelab-command-adapter","class":"usr_local","path_sha256":"c2e3b43f1f858c6fa265dc276d6a6a29e0cd25e4a127fbc093b8c8d9512bb739"},"expected_sha256":"c2e3b43f1f858c6fa265dc276d6a6a29e0cd25e4a127fbc093b8c8d9512bb739","mode":"0o755","sha256":"a1a7a615c99568bf915d084cc476f0ebf54ab0eedf3ecd578c4b0e072f58c43d","sha_verified":false,"text":true},{"bytes":981,"descriptor":{"basename":"homelab-command-portal.service","class":"etc","path_sha256":"adf87b0f1c821b17e3e2ff19cc024d783b55caf69460d01fa66f7d2579a71f5a"},"mode":"0o644","sha256":"8453eab30f5c3ccd285fc9f70fff18f564809bb27f7bf84f51f2ba593aa85263","text":true},{"bytes":39936,"descriptor":{"basename":"homelab-command-portal","class":"usr_local","path_sha256":"1132c3c355ed18cdc6406935cd26a128df298f71df7f48df690c72b202ddd7be"},"expected_sha256":"1132c3c355ed18cdc6406935cd26a128df298f71df7f48df690c72b202ddd7be","mode":"0o755","sha256":"97c69bd4fccf7272dadc911281c1503f411bae2dc11dac4b22b87f33d678ae52","sha_verified":false,"text":true},{"bytes":184,"descriptor":{"basename":"homelab-alerting-health.service","class":"etc","path_sha256":"65f987c4639cfe41887d81a0ca4a9e69f5cd1ebbbf5bfead9c0a12abafd69f2a"},"mode":"0o644","sha256":"2328f1042ac8f6b201603d86941afc87d62191ae12559bee0fd77709c76066f3","text":true},{"bytes":163,"descriptor":{"basename":"homelab-alerting-health.timer","class":"etc","path_sha256":"16473c4f545d506963d3759a2cc76a875669eaa5ac14ee32e133fedcad97d519"},"mode":"0o644","sha256":"28ceb1a533a392af460fc8a42886912fcd256ee6fe8da89460e6c8bdb6096ef1","text":true},{"bytes":209,"descriptor":{"basename":"homelab-alertmanager-backup.service","class":"etc","path_sha256":"b99f6af7e407c69eb96b30eceab66cbf4d08ac38db146134e82c6136b75e7e6c"},"mode":"0o644","sha256":"2544f81eb70d2f66ae85a3ff23108d18c392f33f368832ac363ce7199782e7dd","text":true},{"bytes":204,"descriptor":{"basename":"homelab-alertmanager-backup.timer","class":"etc","path_sha256":"352c09c23c02e625106d7c435e8532a898ac2e74df7713fa13a5bd52c1f697e8"},"mode":"0o644","sha256":"34f5fdf96d8def90035b365f92d877d411331c4d6147131153120e8b737ee0c9","text":true},{"bytes":207,"descriptor":{"basename":"homelab-appbackup-dockge-stacks.service","class":"etc","path_sha256":"4cb18a52e5ef24294a52d41193954c3ff2ac1a46a1915cd9284e30acf548d735"},"mode":"0o644","sha256":"a17ea8adc560454997b581f3f49d52dbcfd039b8883f0188a9ce440c8393cb26","text":true},{"bytes":182,"descriptor":{"basename":"homelab-appbackup-dockge-stacks.timer","class":"etc","path_sha256":"174817f002aa6b61a1fc6c017599b84d68f4a6b8d1d0eced919ec75f51ce0d3d"},"mode":"0o644","sha256":"008a8d2e3f83f15562539057d18893a5076ee66c04df1fdf22d7769bd5c52629","text":true},{"bytes":200,"descriptor":{"basename":"homelab-appbackup-mariadb-batch.service","class":"etc","path_sha256":"d39b189375339d4eb355d8c2516fc2532ffde390526d4132ef3e0c5166639ac8"},"mode":"0o644","sha256":"267aa3988e9fd65ba876d62791ecfd13c191cd069e5e1cf6d77a85220d8e6a0a","text":true},{"bytes":172,"descriptor":{"basename":"homelab-appbackup-mariadb-batch.timer","class":"etc","path_sha256":"34df635a54b198c51587957ce4c3706e83399a67116516d6e2732d5ace77def8"},"mode":"0o644","sha256":"0f977f4ef03cdf76c2dc6d144ce064a7c79c5d2651d69ace5dea632f39f2a76e","text":true},{"bytes":212,"descriptor":{"basename":"homelab-appbackup-npmplus-edge.service","class":"etc","path_sha256":"aeabf93d062d8e555b02e5c09306fc120c6f11d7500ce465101a072c0f323c8c"},"mode":"0o644","sha256":"238cf3867746ee914b9d79d4f8d8a24fd5352186ea0dda29ecbff52249c3a2b8","text":true},{"bytes":181,"descriptor":{"basename":"homelab-appbackup-npmplus-edge.timer","class":"etc","path_sha256":"c50f8c4dc29032baa3d8f5d2ca57f7173b084a2e8b7762000073e0c39869c823"},"mode":"0o644","sha256":"f78414ddbc85db4507b77a6970d8b1c4f39f930b5ca1c8383a13d2467885a2ae","text":true},{"bytes":418,"descriptor":{"basename":"homelab-appbackup-postgres-batch.service","class":"etc","path_sha256":"baddc516879128cef3d08f274700389a19a0d80f2b50e56c23352faf9e4f3078"},"mode":"0o644","sha256":"979991e9acc79b8034a37d94d539641c34c51d26cb4438c4a26a82cb430fe5b9","text":true},{"bytes":173,"descriptor":{"basename":"homelab-appbackup-postgres-batch.timer","class":"etc","path_sha256":"6b0d177f5c4602de757ad64b33c418f15605c299c242c736049f5dfb88394472"},"mode":"0o644","sha256":"665933e86019df10914612df67e56b088c9eaed2f1861b9ed56555ac0febd789","text":true},{"bytes":417,"descriptor":{"basename":"homelab-appbackup-sqlite-batch.service","class":"etc","path_sha256":"37d66bf09f5b1b10a1fd8dc30ec5f271c77148e98ad58dc52a48c41959881b1e"},"mode":"0o644","sha256":"0d18769b26baae048a68f85f403893b22c67fb2852cd3a14ff1cf909f5d34d76","text":true},{"bytes":171,"descriptor":{"basename":"homelab-appbackup-sqlite-batch.timer","class":"etc","path_sha256":"3d73c398b6366337b550ac6209655912e9d3af21f04c2943e9cd347fdab96661"},"mode":"0o644","sha256":"838a1ee3e034c0fef373efb6639e96b1fdc1b858eaafaca2f877fd26e463f9b8","text":true},{"bytes":181,"descriptor":{"basename":"homelab-authentik-backup.service","class":"etc","path_sha256":"b76cd271e6dd863922b8a036e6cbf4c121eb2f4a3a740050f11b83d26e09bfc6"},"mode":"0o644","sha256":"81a709901db99eaea51915af0b69d923d1b605ba7927b6fb95583f8b297b84e7","text":true},{"bytes":208,"descriptor":{"basename":"homelab-authentik-backup.timer","class":"etc","path_sha256":"1927d108c1fd89d29bbcd8398fcd7922e61ca8f43cbe1d834ca22fe39fd6d67c"},"mode":"0o644","sha256":"36aea53d4ff6d0b4cdb20925aa41a38db0485c2ba2bd632ebcec6f25a68ec54c","text":true},{"bytes":259,"descriptor":{"basename":"homelab-auto-backup.service","class":"etc","path_sha256":"ce57706dafbf1b1c70c85e89878e68fdc3265f68223debf22a14b4a4c5a5fc9e"},"mode":"0o644","sha256":"d8015c7137e58bada7519d60e0e35e803fca147078baf379ab439ee52295a018","text":true},{"bytes":205,"descriptor":{"basename":"homelab-auto-backup.timer","class":"etc","path_sha256":"7496836d1c027328616a26ec045e8c3bd5a71175151f2acbe8a62e271021adc7"},"mode":"0o644","sha256":"2e2b2b21ddc5884b3f54fa9158029f1450846b391815e6d1f2e0300825eddd58","text":true},{"bytes":131,"descriptor":{"basename":"homelab-backup-coverage-matrix.service","class":"etc","path_sha256":"44024c71ae439561429d05233d33943b83399cdc1e15ae0ba2c9b5989355ddda"},"mode":"0o644","sha256":"3903036cfc32a2f5e365549bf5bc7b3946f700fdddf96f2718ef2f53b4f1ab3c","text":true},{"bytes":164,"descriptor":{"basename":"homelab-backup-coverage-matrix.timer","class":"etc","path_sha256":"5c1338128ec2f8c11bc7341b88c694d6c0eb421ff8e8965f81f32e8f6af55250"},"mode":"0o644","sha256":"a193e47aa8524bdd00c9ae9947299767801a4faf49d2b0d2c0d83d3bc4ddf40f","text":true},{"bytes":246,"descriptor":{"basename":"homelab-backup-freshness.service","class":"etc","path_sha256":"4ae520fa731e2cbc6402fce317e07b15b67f8a28da3fc12e603dd53ebef877a6"},"mode":"0o644","sha256":"b8907cedd41c6a6640d2e7bbf80b0d340dbb629526786fd97d8fc85f950a1a5e","text":true},{"bytes":249,"descriptor":{"basename":"homelab-backup-freshness.service.bak.20260703T091211Z","class":"etc","path_sha256":"11da50b99cb5130fff2ead01cef7fc81fed05d92d6d542492b55a97f63fe0eed"},"mode":"0o644","sha256":"725db645150fae38980a40efe5e213f83fef5bdae1a89662da3caebc22fdf846","text":true},{"bytes":201,"descriptor":{"basename":"homelab-backup-freshness.timer","class":"etc","path_sha256":"358102a7e8b92a01ce7cd7492af821b847a19015c75d68673b42039e11688582"},"mode":"0o644","sha256":"c9b35236cdad23b18f968229bd67b66ef6e402daf01b44414754eca8d21b47b0","text":true},{"bytes":124,"descriptor":{"basename":"homelab-backup-healthcheck.service","class":"etc","path_sha256":"72b8190b110b60a9c7f4a0a02a0862bb8a6d5a57f8e7909fe0fe7c2f406ec665"},"mode":"0o644","sha256":"dbe8f6edfb60575f1df5b0b8bd96442e194ed8a126e3b47a28f7460de2969197","text":true},{"bytes":204,"descriptor":{"basename":"homelab-backup-healthcheck.timer","class":"etc","path_sha256":"834f8b351870fda9dde70071076b07991ffcdf83a4ac0e50adf52f50bbd85b61"},"mode":"0o644","sha256":"24e78312708659ad93068e3b7a9ae2af66658393abc406fd2c80d45584a801b0","text":true},{"bytes":187,"descriptor":{"basename":"homelab-backup-matrix-refresh.service","class":"etc","path_sha256":"7d91611f3ad2182f7973122749a2eabf3767bf999b72266497171f52a10edadb"},"mode":"0o644","sha256":"864cff5bd2dc6b748e2a9788d7b7908246619022ac4aaea70de5223864c7e84c","text":true},{"bytes":217,"descriptor":{"basename":"homelab-backup-matrix-refresh.timer","class":"etc","path_sha256":"0aee495d48f892152de2bdf525eb33ba4c1a2169be9c7d26051d84b1508e8d75"},"mode":"0o644","sha256":"708eb9721cf0bbe5ebf282a29dbb419372b1351789f720f6d554b1e608aea359","text":true},{"bytes":159,"descriptor":{"basename":"homelab-backup-sla-health.service","class":"etc","path_sha256":"946184204f79931a710450cd3893a93b84b6135d330b47fd1899ad2ac86e9f1f"},"mode":"0o644","sha256":"a97266ea9b01dbfe93e7217b489ae9b1fa8ab968581ec1b0a05a7ec7f376fac2","text":true},{"bytes":169,"descriptor":{"basename":"homelab-backup-sla-health.timer","class":"etc","path_sha256":"81a01289fc98b279c7d2faa929b76e5c6c9fa0bc17cb479c18342149e2c1907e"},"mode":"0o644","sha256":"913db5262172bf20f4213fcca892798a460b370f218ae23910ad31925e6270d5","text":true},{"bytes":197,"descriptor":{"basename":"homelab-beszel-backup.service","class":"etc","path_sha256":"d4cbaad62a74d3518645ca98a306b5205f28d1b9e9b1a34de15f3afa082240a9"},"mode":"0o644","sha256":"3ad161b2fc12b6003d3aed70d41009100b42b564c2f6d15406607ba1226c1309","text":true},{"bytes":202,"descriptor":{"basename":"homelab-beszel-backup.timer","class":"etc","path_sha256":"57e5bc30ce6147263f14799092a51da572867f4efc203565af4f2bb2a44be875"},"mode":"0o644","sha256":"ed86409337d0994e0e3abae3df19055d658b7138714515e6dbe6c685083af1dd","text":true},{"bytes":219,"descriptor":{"basename":"homelab-blackbox-exporter-backup.service","class":"etc","path_sha256":"2d6858d54a3c3461df4d40f42e00fc9554aa72fa6be35f410a21fbbf6860a579"},"mode":"0o644","sha256":"2fcd8c6a8b4c8168fcaeb3a5191351fdb8cd0925f76fe2be108ced5afe212fe5","text":true},{"bytes":224,"descriptor":{"basename":"homelab-blackbox-exporter-backup.timer","class":"etc","path_sha256":"f5a77d2f8ceecfd144cf6dd6e8fd6845868b281590b45ea6c3704464817679af"},"mode":"0o644","sha256":"840cb01e3acf221a2ae5b457e6ae4f12b49195c5ca055dfd1192847f6e78b895","text":true},{"bytes":147,"descriptor":{"basename":"homelab-capacity-risk.service","class":"etc","path_sha256":"91368f3c372f5038c5ae38fe06eb8f96b2a1c269e2f6102f4528c46311d13b33"},"mode":"0o644","sha256":"aa4302a6681da2726845444affbb68d1a97ade99a9aa2c138f48b35a0a8c0cd9","text":true},{"bytes":161,"descriptor":{"basename":"homelab-capacity-risk.timer","class":"etc","path_sha256":"79c8ef12bf1233a4ac4ea26e4ba07e4c247402a20635818a1576dbc21fc09b77"},"mode":"0o644","sha256":"6affbae63cc7be026318e8034c6bfcc2b1c877ee57c17f81dff9fa448f0befe9","text":true},{"bytes":231,"descriptor":{"basename":"homelab-cluster-admin-incident-engine-backup.service","class":"etc","path_sha256":"dbe77771fe5d21100579e740fda3b915bfeafaad41727e9527d10e9e55e3d5c5"},"mode":"0o644","sha256":"bc7f9010fd6e97dff3bbedd2fd2088d65836a1a842cbd6d465163251e2a7db31","text":true},{"bytes":238,"descriptor":{"basename":"homelab-cluster-admin-incident-engine-backup.timer","class":"etc","path_sha256":"3bd1f133505c5728e6c1b221d517f927e5317d81be89c64389dd67cab4945cfd"},"mode":"0o644","sha256":"7b34396b19b8d9139e3f59d7a03a5bbfe08440c95d6a1d85031057665a724d54","text":true},{"bytes":235,"descriptor":{"basename":"homelab-cluster-admin-inventory-sync.service","class":"etc","path_sha256":"f09f06a23ceec401b2846dba087c234a271d36c0f8a64d700169963260ccc1ed"},"mode":"0o644","sha256":"5237b68c736e77ff0108c77321bbe9b9cb7285e3a23d135361a43cd2fcb74264","text":true},{"bytes":235,"descriptor":{"basename":"homelab-cluster-admin-inventory-sync.timer","class":"etc","path_sha256":"905fa93f675463931a73457f7b182241f09b0216e710148918d4465b58f8124c"},"mode":"0o644","sha256":"4c9f51447b5d8f75fa05b494390e74089b6a2880ce899325643d47be4ce2180e","text":true},{"bytes":142,"descriptor":{"basename":"homelab-cluster-admin-pull.service","class":"etc","path_sha256":"a125ccdf5af51e63b6487adb7b544fa854bb229a8a948aa50ae36aad7f8e3d6c"},"mode":"0o644","sha256":"4a30f00113b7c68478f1cd2c8be959aed1931c55a0c7f7c99fda06cb742b914e","text":true},{"bytes":145,"descriptor":{"basename":"homelab-cluster-admin-pull.timer","class":"etc","path_sha256":"d256eb912a67a960f60dbafc7e2ac722a2dfb8b291f31dbc1dcda55fb5c8d861"},"mode":"0o644","sha256":"5e4936d1379c96088b17816a7aba42d77051009bd0938a253b3487bcb3b658a6","text":true},{"bytes":162,"descriptor":{"basename":"homelab-cluster-admin-webpanel-sync.service","class":"etc","path_sha256":"fdf71842c5c7d93b8b0fd9fa504634867092161c8fcebc0b5fd3872e1b5e8696"},"mode":"0o644","sha256":"d8091d4bb52513929cd7df742532977f70e08ee60ab8762a8f027e5863612c3b","text":true},{"bytes":169,"descriptor":{"basename":"homelab-cluster-admin-webpanel-sync.timer","class":"etc","path_sha256":"2bfb342d31abcb9a979ad8d8c6abdd0f6924e4d491f87cf172ba8fe1300c723a"},"mode":"0o644","sha256":"ef420cea1b506ff7ea6dbd02c1b19167e5771030f4f52eb850aa05b7e3eed094","text":true},{"bytes":314,"descriptor":{"basename":"homelab-cluster-internal-ip.service","class":"etc","path_sha256":"7febe1024cc75fbd4a00668d5074f501f0adff874d3dbc0bade2ddea4455ef13"},"mode":"0o644","sha256":"813fca6cacb2075a6dc7a6cead8d2fbf6234db47d86825725def2fa4b5095dcb","text":true},{"bytes":147,"descriptor":{"basename":"homelab-cluster-passport.service","class":"etc","path_sha256":"e53262b977c5305b25d282c332ae6caf4a145111b9b97530a5335630be3ead8f"},"mode":"0o644","sha256":"6add64848c301bfba276581c69d05ff854add9783e6d56d224a89624b775ea78","text":true},{"bytes":158,"descriptor":{"basename":"homelab-cluster-passport.timer","class":"etc","path_sha256":"cd4a5110a0ba10e5cbc171421b3a2072e437f2669ec0e6a6d044dca22aa99a50"},"mode":"0o644","sha256":"30c2f09882c3c19ef818c5e8059510500a0c789273627266b4421453c8a90ca8","text":true},{"bytes":164,"descriptor":{"basename":"homelab-crypto-portfolio-backup.service","class":"etc","path_sha256":"ff2ccb6b70941c3a67e8dd46de18c54aa2957e394a1f77ce6e69eb81fbc18b1c"},"mode":"0o644","sha256":"26893d40465a1d1072582d0e30c9ba59187b78a0969fdb638c2f413038675b7f","text":true},{"bytes":162,"descriptor":{"basename":"homelab-crypto-portfolio-backup.timer","class":"etc","path_sha256":"dda278ff41c9115e2362619b71f23f0e17c1256fbd43c3a1a2190346a6f8f6d9"},"mode":"0o644","sha256":"4c77b430d616e2da1f17a9a4ae602cb1a627911b87ce95be3ed7702aeb1e6641","text":true},{"bytes":197,"descriptor":{"basename":"homelab-crypto-portfolio-chart-health.service","class":"etc","path_sha256":"2afd3cfb8fc1344f45b5d761a31234f9ff724aac9389826524948f3fd2f34ccd"},"mode":"0o644","sha256":"265d173e16c3c6c3dded360d0bff1e96bd8fa38a07cb21c7bb89880a38bf1964","text":true},{"bytes":230,"descriptor":{"basename":"homelab-crypto-portfolio-chart-health.timer","class":"etc","path_sha256":"5ff52b5a7e794bb77539fda37700faefb8c86f7f5b613eb783ad0b129d7333f8"},"mode":"0o644","sha256":"173d663322fd8d4069d142a1c77a594735fe5b44cfe0cc0782d9dc40f428ac41","text":true},{"bytes":127,"descriptor":{"basename":"homelab-dependency-map-check.service","class":"etc","path_sha256":"5b71a334eca77c0d514954f6d9be94d4f23d6cdcfbaf4c761f7867414b0e65cb"},"mode":"0o644","sha256":"adec2fe651ed4870378aa6f07a0c50b81c82cd520a368dec91d27a11d4b85ca9","text":true},{"bytes":162,"descriptor":{"basename":"homelab-dependency-map-check.timer","class":"etc","path_sha256":"a2c5b8bd341bd69b8e225554fc24890e2aa1e25c9e70b4d986c599847a827792"},"mode":"0o644","sha256":"a1a8aa7ee0fd125768df19595c05372c4643e54bd80eab0a7a59f3a3d22db9fc","text":true},{"bytes":159,"descriptor":{"basename":"homelab-desired-state-sync.service","class":"etc","path_sha256":"be9d39311482a58e018015da172c7573c785df96f882c8a4fe37135a9d8f58fd"},"mode":"0o644","sha256":"98c71772e1af6b62459df2dc8d5c4b6c153933389dfe3c0dafef4c3ec1df3d1b","text":true},{"bytes":168,"descriptor":{"basename":"homelab-desired-state-sync.timer","class":"etc","path_sha256":"c2efa39355780cb4c44a2d964f51966bb637dc0dba645c8e2654e899519ecfb0"},"mode":"0o644","sha256":"d948911a746299dcb61e42eb1434b1ccdfd967f1404c9ab183c262acf81ff58a","text":true},{"bytes":133,"descriptor":{"basename":"homelab-disk-space-health.service","class":"etc","path_sha256":"9a29b800386cc8c9692d535fa532d17cff8d5f250ae9ac16676682fd813b5b53"},"mode":"0o644","sha256":"1737c5e53d5266f681f26df007774e8283a5da5ad5c2f9d5503798789dc34e00","text":true},{"bytes":188,"descriptor":{"basename":"homelab-disk-space-health.timer","class":"etc","path_sha256":"f612d0cc6c7f19d63a8c2d11cfc45dadafd9b83553cb9a1e9a1c9dbe75a34fc0"},"mode":"0o644","sha256":"67ad58fd20e74775c8dc12e08fceb7369e0c995101250a6707ce9180af92426b","text":true}],"files_examined":80,"mutation_outcome":"NO_MUTATION","next_action":"FIX_ONLY_PROVEN_READ_ONLY_SOURCE_MAP_GAP","output_truncated_in_json":false,"patch_points":[{"fields":["argv","content_b64","evidence","payload","portal","secret"],"file":{"basename":"homelab-command-adapter","class":"usr_local","path_sha256":"c2e3b43f1f858c6fa265dc276d6a6a29e0cd25e4a127fbc093b8c8d9512bb739"},"process_calls":[{"call":"subprocess.run","keywords":["check","env","stderr","stdin","stdout","text","timeout"],"line":664},{"call":"subprocess.Popen","keywords":["close_fds","env","start_new_session","stderr","stdin","stdout"],"line":1626},{"call":"subprocess.Popen","keywords":["close_fds","env","start_new_session","stderr","stdin","stdout","text"],"line":2056}],"redaction_symbols":["create_evidence_bundle","evidence_url","remote_evidence_presign","sanitize_state","sign_evidence","upload_evidence"],"routes":[],"sha256":"a1a7a615c99568bf915d084cc476f0ebf54ab0eedf3ecd578c4b0e072f58c43d"}],"rc":0,"read_only":true,"rollback_restored":null,"rollback_started":false,"root_cause_classification":"ADAPTER_PORTAL_SOURCE_MAP_INCOMPLETE","schema":1,"status":"OK","units":[{"environment_files_declared":false,"show_rc":0,"stderr_sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","unit":"homelab-command-adapter.service","user_class":"root","working_directory_declared":false},{"environment_files_declared":false,"show_rc":0,"stderr_sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","unit":"homelab-command-portal.service","user_class":"non_root","working_directory_declared":false}]} +HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z","command_rc":0,"control_plane_error":null,"exact_invalid_risk_source_found":true,"matching_file_count":2,"matching_file_manifest_sha256":"af904aec1040e2968d87c5e61b6ced9f013d49a0c7f5e0a48f70b292df1a966c","mutation_outcome":"NO_MUTATION","rc":0,"report_bytes":20215,"report_sha256":"4b4749cedde3bcaed3f4b01824f2c5de02d90e6525a59e5fd4e8b1b545344a95","risk_candidate_tokens":["HIGH","READ_ONLY","REVERSIBLE"],"risk_enum_confirmed":true,"rollback_restored":false,"rollback_started":false,"status":"OK","version":1} +{"candidate_roots":["/","/etc/systemd/system","/etc/systemd/system/homelab-command-adapter.service","/opt","/srv","/usr/bin","/usr/bin/python3.13","/usr/local","/usr/local/lib","/usr/local/sbin","/usr/local/sbin/homelab-command-adapter"],"changes_made":false,"command_id":"HOMELAB-V13-ADAPTER-RISK-SCHEMA-READ-ONLY-20260805T121700Z","mutation_outcome":"NO_MUTATION","read_only":true,"risk_enum":{"candidate_tokens":["HIGH","READ_ONLY","REVERSIBLE"],"exact_enum_confirmed":true,"proof":[{"context":[{"line":380,"text":" ):"},{"line":381,"text":" raise AdapterError(\"invalid timeout_seconds\")"},{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"}],"match_line":383,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","REVERSIBLE"]},{"context":[{"line":381,"text":" raise AdapterError(\"invalid timeout_seconds\")"},{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"}],"match_line":384,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","REVERSIBLE"]},{"context":[{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"}],"match_line":385,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]},{"context":[{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"}],"match_line":386,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]},{"context":[{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""}],"match_line":387,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]},{"context":[{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""},{"line":391,"text":" flags = document.get(\"change_flags\")"}],"match_line":388,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]},{"context":[{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""},{"line":391,"text":" flags = document.get(\"change_flags\")"},{"line":392,"text":" if not isinstance(flags, dict):"}],"match_line":389,"path":"/usr/local/sbin/homelab-command-adapter","tokens":["HIGH","READ_ONLY","REVERSIBLE"]}]},"rollback_restored":false,"rollback_started":false,"scan":{"exact_invalid_mode_matches":1,"exact_invalid_risk_matches":1,"files_scanned":3,"matching_file_manifest_sha256":"af904aec1040e2968d87c5e61b6ced9f013d49a0c7f5e0a48f70b292df1a966c","matching_files":2,"uppercase_enum_tokens":["FAIL","HIGH","NONE","READ_ONLY","REVERSIBLE","UNKNOWN","USAGE"]},"schema":1,"source_matches":[{"bytes":21321,"matches":[{"context":[{"line":8,"text":"import sys"},{"line":9,"text":"from pathlib import Path"},{"line":10,"text":""},{"line":11,"text":"raw_path, command_id, mode, command_rc = sys.argv[1:]"},{"line":12,"text":"command_rc = int(command_rc)"},{"line":13,"text":""},{"line":14,"text":"result = {"}],"match_line":11},{"context":[{"line":21,"text":" \"error\": \"NONE\","},{"line":22,"text":"}"},{"line":23,"text":""},{"line":24,"text":"if mode == \"change\":"},{"line":25,"text":" result = {"},{"line":26,"text":" \"valid\": False,"},{"line":27,"text":" \"status\": \"UNKNOWN\","}],"match_line":24},{"context":[{"line":188,"text":"usage() {"},{"line":189,"text":" cat >&2 <<'USAGE'"},{"line":190,"text":"Usage:"},{"line":191,"text":" homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]"},{"line":192,"text":""},{"line":193,"text":"MODE:"},{"line":194,"text":" read-only"}],"match_line":191},{"context":[{"line":190,"text":"Usage:"},{"line":191,"text":" homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]"},{"line":192,"text":""},{"line":193,"text":"MODE:"},{"line":194,"text":" read-only"},{"line":195,"text":" verify"},{"line":196,"text":" change"}],"match_line":193},{"context":[{"line":206,"text":"[ \"$#\" -ge 5 ] || usage"},{"line":207,"text":""},{"line":208,"text":"COMMAND_ID=\"$1\""},{"line":209,"text":"MODE=\"$2\""},{"line":210,"text":"COMPONENT=\"$3\""},{"line":211,"text":"shift 3"},{"line":212,"text":""}],"match_line":209},{"context":[{"line":230,"text":" ;;"},{"line":231,"text":"esac"},{"line":232,"text":""},{"line":233,"text":"case \"$MODE\" in"},{"line":234,"text":" read-only|verify|change|transport-test)"},{"line":235,"text":" ;;"},{"line":236,"text":" *)"}],"match_line":233},{"context":[{"line":304,"text":""},{"line":305,"text":"COMMAND_SHA256=\"$("},{"line":306,"text":" {"},{"line":307,"text":" printf '%s\\0' \"$MODE\""},{"line":308,"text":" printf '%s\\0' \"$COMPONENT\""},{"line":309,"text":" printf '%s\\0' \"$@\""},{"line":310,"text":" } |"}],"match_line":307},{"context":[{"line":337,"text":"RESULT_CONTRACT_ERROR='NONE'"},{"line":338,"text":"COMMAND_RC=''"},{"line":339,"text":""},{"line":340,"text":"if [ \"$MODE\" = change ]; then"},{"line":341,"text":" CHANGE_DECLARED=true"},{"line":342,"text":" RESULT_CONTRACT_VALID=false"},{"line":343,"text":" CONTRACT_STATUS='UNKNOWN'"}],"match_line":340},{"context":[{"line":416,"text":" read_mutation_contract \\"},{"line":417,"text":" \"$RAW_FILE\" \\"},{"line":418,"text":" \"$COMMAND_ID\" \\"},{"line":419,"text":" \"$MODE\" \\"},{"line":420,"text":" \"$COMMAND_RC\""},{"line":421,"text":" )"},{"line":422,"text":""}],"match_line":419},{"context":[{"line":420,"text":" \"$COMMAND_RC\""},{"line":421,"text":" )"},{"line":422,"text":""},{"line":423,"text":" if [ \"$MODE\" = change ]; then"},{"line":424,"text":" if [ \"$RESULT_CONTRACT_VALID\" != true ]; then"},{"line":425,"text":" RC=76"},{"line":426,"text":" STATUS='FAIL'"}],"match_line":423},{"context":[{"line":547,"text":" \"$STATUS\" \\"},{"line":548,"text":" \"$RC\" \\"},{"line":549,"text":" \"$HOST_SHORT\" \\"},{"line":550,"text":" \"$MODE\" \\"},{"line":551,"text":" \"$COMPONENT\" \\"},{"line":552,"text":" \"$STARTED_AT\" \\"},{"line":553,"text":" \"$FINISHED_AT\" \\"}],"match_line":550},{"context":[{"line":579,"text":" status,"},{"line":580,"text":" rc,"},{"line":581,"text":" host,"},{"line":582,"text":" mode,"},{"line":583,"text":" component,"},{"line":584,"text":" started,"},{"line":585,"text":" finished,"}],"match_line":582},{"context":[{"line":634,"text":" \"status\": status,"},{"line":635,"text":" \"rc\": int(rc),"},{"line":636,"text":" \"host\": host,"},{"line":637,"text":" \"mode\": mode,"},{"line":638,"text":" \"component\": component,"},{"line":639,"text":" \"started_at_utc\": started,"},{"line":640,"text":" \"finished_at_utc\": finished,"}],"match_line":637},{"context":[{"line":694,"text":" echo \"STATUS=$STATUS\""},{"line":695,"text":" echo \"RC=$RC\""},{"line":696,"text":" echo \"HOST=$HOST_SHORT\""},{"line":697,"text":" echo \"MODE=$MODE\""},{"line":698,"text":" echo \"COMPONENT=$COMPONENT\""},{"line":699,"text":" echo 'REFERENCE_REGISTER_CHECK=OK'"},{"line":700,"text":" echo \"REFERENCE_SHA256=$REFERENCE_SHA256\""}],"match_line":697}],"path":"/usr/local/sbin/homelab-chat-run","sha256":"b248a4c32c9cc64e5747e7dce6c7fc0a23f5124a77c71ce72e27a81aceae9d2d"},{"bytes":86019,"matches":[{"context":[{"line":119,"text":" \"transport-test\","},{"line":120,"text":"}"},{"line":121,"text":"ALLOWED_RISKS = {"},{"line":122,"text":" \"READ_ONLY\","},{"line":123,"text":" \"REVERSIBLE\","},{"line":124,"text":" \"HIGH\","},{"line":125,"text":"}"}],"match_line":122},{"context":[{"line":129,"text":" \"command_id\","},{"line":130,"text":" \"title\","},{"line":131,"text":" \"summary\","},{"line":132,"text":" \"mode\","},{"line":133,"text":" \"component\","},{"line":134,"text":" \"target\","},{"line":135,"text":" \"timeout_seconds\","}],"match_line":132},{"context":[{"line":133,"text":" \"component\","},{"line":134,"text":" \"target\","},{"line":135,"text":" \"timeout_seconds\","},{"line":136,"text":" \"risk\","},{"line":137,"text":" \"change_flags\","},{"line":138,"text":" \"rollback\","},{"line":139,"text":" \"argv\","}],"match_line":136},{"context":[{"line":143,"text":"}"},{"line":144,"text":"ALLOWED_PAYLOAD_FIELDS = {"},{"line":145,"text":" \"path\","},{"line":146,"text":" \"mode\","},{"line":147,"text":" \"sha256\","},{"line":148,"text":" \"content_b64\","},{"line":149,"text":"}"}],"match_line":146},{"context":[{"line":262,"text":""},{"line":263,"text":"def ensure_layout() -> None:"},{"line":264,"text":" portal = pwd.getpwnam(PORTAL_USER)"},{"line":265,"text":" for path, mode in ("},{"line":266,"text":" (ROOT, 0o750),"},{"line":267,"text":" (STATE_DIR, 0o750),"},{"line":268,"text":" (CAPSULE_DIR, 0o700),"}],"match_line":265},{"context":[{"line":270,"text":" ):"},{"line":271,"text":" path.mkdir(parents=True, exist_ok=True)"},{"line":272,"text":" os.chown(path, 0, portal.pw_gid)"},{"line":273,"text":" os.chmod(path, mode)"},{"line":274,"text":""},{"line":275,"text":""},{"line":276,"text":"def unique_json_loads(raw: bytes) -> dict[str, Any]:"}],"match_line":273},{"context":[{"line":332,"text":""},{"line":333,"text":" if document.get(\"schema_version\") != 1:"},{"line":334,"text":" raise AdapterError(\"unsupported capsule schema\")"},{"line":335,"text":" if document.get(\"kind\") != \"homelab-command-capsule\":"},{"line":336,"text":" raise AdapterError(\"invalid capsule kind\")"},{"line":337,"text":""},{"line":338,"text":" command_id = validate_text("}],"match_line":335},{"context":[{"line":366,"text":" maximum=2000,"},{"line":367,"text":" )"},{"line":368,"text":""},{"line":369,"text":" mode = document.get(\"mode\")"},{"line":370,"text":" if mode not in ALLOWED_MODES:"},{"line":371,"text":" raise AdapterError(\"invalid mode\")"},{"line":372,"text":" if document.get(\"target\") != \"pve01\":"}],"match_line":369},{"context":[{"line":367,"text":" )"},{"line":368,"text":""},{"line":369,"text":" mode = document.get(\"mode\")"},{"line":370,"text":" if mode not in ALLOWED_MODES:"},{"line":371,"text":" raise AdapterError(\"invalid mode\")"},{"line":372,"text":" if document.get(\"target\") != \"pve01\":"},{"line":373,"text":" raise AdapterError(\"only pve01 target is supported\")"}],"match_line":370},{"context":[{"line":368,"text":""},{"line":369,"text":" mode = document.get(\"mode\")"},{"line":370,"text":" if mode not in ALLOWED_MODES:"},{"line":371,"text":" raise AdapterError(\"invalid mode\")"},{"line":372,"text":" if document.get(\"target\") != \"pve01\":"},{"line":373,"text":" raise AdapterError(\"only pve01 target is supported\")"},{"line":374,"text":""}],"match_line":371},{"context":[{"line":380,"text":" ):"},{"line":381,"text":" raise AdapterError(\"invalid timeout_seconds\")"},{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"}],"match_line":383},{"context":[{"line":381,"text":" raise AdapterError(\"invalid timeout_seconds\")"},{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"}],"match_line":384},{"context":[{"line":382,"text":""},{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"}],"match_line":385},{"context":[{"line":383,"text":" risk = document.get(\"risk\")"},{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"}],"match_line":386},{"context":[{"line":384,"text":" if risk not in ALLOWED_RISKS:"},{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""}],"match_line":387},{"context":[{"line":385,"text":" raise AdapterError(\"invalid risk\")"},{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""},{"line":391,"text":" flags = document.get(\"change_flags\")"}],"match_line":388},{"context":[{"line":386,"text":" if mode == \"change\" and risk not in {\"REVERSIBLE\", \"HIGH\"}:"},{"line":387,"text":" raise AdapterError(\"change capsule risk must be REVERSIBLE or HIGH\")"},{"line":388,"text":" if mode != \"change\" and risk != \"READ_ONLY\":"},{"line":389,"text":" raise AdapterError(\"non-change capsule risk must be READ_ONLY\")"},{"line":390,"text":""},{"line":391,"text":" flags = document.get(\"change_flags\")"},{"line":392,"text":" if not isinstance(flags, dict):"}],"match_line":389},{"context":[{"line":396,"text":" if any(type(value) is not bool for value in flags.values()):"},{"line":397,"text":" raise AdapterError(\"change_flags values must be boolean\")"},{"line":398,"text":""},{"line":399,"text":" if mode != \"change\" and any(flags.values()):"},{"line":400,"text":" raise AdapterError("},{"line":401,"text":" \"non-change capsule cannot declare changes\""},{"line":402,"text":" )"}],"match_line":399},{"context":[{"line":400,"text":" raise AdapterError("},{"line":401,"text":" \"non-change capsule cannot declare changes\""},{"line":402,"text":" )"},{"line":403,"text":" if mode == \"change\" and not flags[\"production\"]:"},{"line":404,"text":" raise AdapterError("},{"line":405,"text":" \"change capsule must declare production change\""},{"line":406,"text":" )"}],"match_line":403},{"context":[{"line":418,"text":" minimum=1,"},{"line":419,"text":" maximum=2000,"},{"line":420,"text":" )"},{"line":421,"text":" if mode == \"change\" and rollback[\"available\"] is not True:"},{"line":422,"text":" raise AdapterError("},{"line":423,"text":" \"change capsule requires available rollback\""},{"line":424,"text":" )"}],"match_line":421}],"path":"/usr/local/sbin/homelab-command-adapter","sha256":"a1a7a615c99568bf915d084cc476f0ebf54ab0eedf3ecd578c4b0e072f58c43d"}],"status":"OK","systemd_adapter":[{"cat_rc":1,"cat_stderr":"No files found for homelab-adapter.service.\n","show":{"ActiveState":"inactive","DropInPaths":"","FragmentPath":"","LoadState":"not-found","MainPID":"0","SubState":"dead","WorkingDirectory":""},"show_rc":0,"show_stderr":"","unit":"homelab-adapter.service","unit_text":""},{"cat_rc":0,"cat_stderr":"","process":{"cmdline":["/usr/bin/python3","-B","/usr/local/sbin/homelab-command-adapter","--serve"],"cwd":"/","exe":"/usr/bin/python3.13","pid":1131444},"show":{"ActiveState":"active","DropInPaths":"","ExecStart":"{ path=/usr/bin/python3 ; argv[]=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }","FragmentPath":"/etc/systemd/system/homelab-command-adapter.service","LoadState":"loaded","MainPID":"1131444","SubState":"running","WorkingDirectory":""},"show_rc":0,"show_stderr":"","unit":"homelab-command-adapter.service","unit_text":"# /etc/systemd/system/homelab-command-adapter.service\n[Unit]\nDescription=Homelab command adapter\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=/usr/bin/python3 -B /usr/local/sbin/homelab-command-adapter --serve\nUser=root\nGroup=homelab-command-portal\nUMask=0027\nRuntimeDirectory=homelab-command-adapter\nRuntimeDirectoryMode=0750\nRestart=on-failure\nRestartSec=2\nNoNewPrivileges=false\nPrivateTmp=true\nProtectClock=true\nProtectControlGroups=true\nProtectKernelLogs=true\nProtectKernelModules=true\nProtectKernelTunables=true\nRestrictRealtime=true\nLockPersonality=true\nMemoryDenyWriteExecute=true\nSystemCallArchitectures=native\nTimeoutStopSec=15\n\n[Install]\nWantedBy=multi-user.target"}]} OUTPUT_END CHAT_OUTPUT_END