From abda0ef6176db90a9e39ba2559be41a7bcaededd Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 Jun 2026 20:01:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(iwooos):=20=E6=96=B0=E5=A2=9E=E4=B8=BB?= =?UTF-8?q?=E6=A9=9F=E6=9C=8D=E5=8B=99=E4=BA=8B=E6=95=85=E5=9B=9E=E8=AE=80?= =?UTF-8?q?=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/messages/en.json | 4 +- apps/web/messages/zh-TW.json | 4 +- apps/web/src/app/[locale]/iwooos/page.tsx | 30 +- .../iwooos_posture_projection_v1.schema.json | 181 +- .../HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md | 11 +- ...OST-SERVICE-POST-INCIDENT-READBACK-PLAN.md | 198 ++ .../IWOOOS-CONFIG-CONTROL-INVENTORY.md | 15 +- docs/security/IWOOOS-POSTURE-PROJECTION.md | 3 +- .../SECURITY-SUPPLY-CHAIN-PROGRESS.md | 10 +- ...alue-config-control-coverage.snapshot.json | 32 +- ...-post-incident-readback-plan.snapshot.json | 2392 +++++++++++++++++ .../iwooos-posture-projection.snapshot.json | 45 +- .../high-value-config-control-coverage.py | 10 +- ...ost-service-post-incident-readback-plan.py | 410 +++ .../security/iwooos-config-control-guard.py | 51 +- .../security-mirror-progress-guard.py | 231 +- 16 files changed, 3572 insertions(+), 55 deletions(-) create mode 100644 docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md create mode 100644 docs/security/host-service-post-incident-readback-plan.snapshot.json create mode 100644 scripts/security/host-service-post-incident-readback-plan.py diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index fb2d8257..878278ad 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -17920,7 +17920,7 @@ }, "coverage": { "label": "平均成熟度", - "detail": "owner response acceptance 與前台 source guard 推進後平均控管成熟度為 70%。" + "detail": "host service 事故回讀 gate 納入後,平均控管成熟度為 71%。" }, "runtimeGate": { "label": "執行期", @@ -17934,7 +17934,7 @@ }, "dockerSystemd": { "title": "Docker / systemd 主機服務", - "body": "只讀清冊、負責人回覆驗收與主機服務變更證據驗收已納入 9 個範圍;目前只讀成熟度 62%,26 個審查檢查項、10 條結果分流、39 類禁止動作,Docker daemon、compose、systemd、失敗單元、port binding、路由恢復與操作通知驗收仍全部為 0。" + "body": "只讀清冊、負責人回覆驗收、主機服務變更證據驗收與事故後回讀計畫已納入 9 個範圍;目前只讀成熟度 64%,28 個審查檢查項、10 條結果分流、41 類禁止動作。Docker daemon、compose、systemd、失敗單元、port binding、public/admin route、AI provider、監控告警、跨專案同步、防再發與 no-false-green 驗收仍全部為 0。" }, "aiProvider": { "title": "AI 供應商 / 模型路由", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index fb2d8257..878278ad 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -17920,7 +17920,7 @@ }, "coverage": { "label": "平均成熟度", - "detail": "owner response acceptance 與前台 source guard 推進後平均控管成熟度為 70%。" + "detail": "host service 事故回讀 gate 納入後,平均控管成熟度為 71%。" }, "runtimeGate": { "label": "執行期", @@ -17934,7 +17934,7 @@ }, "dockerSystemd": { "title": "Docker / systemd 主機服務", - "body": "只讀清冊、負責人回覆驗收與主機服務變更證據驗收已納入 9 個範圍;目前只讀成熟度 62%,26 個審查檢查項、10 條結果分流、39 類禁止動作,Docker daemon、compose、systemd、失敗單元、port binding、路由恢復與操作通知驗收仍全部為 0。" + "body": "只讀清冊、負責人回覆驗收、主機服務變更證據驗收與事故後回讀計畫已納入 9 個範圍;目前只讀成熟度 64%,28 個審查檢查項、10 條結果分流、41 類禁止動作。Docker daemon、compose、systemd、失敗單元、port binding、public/admin route、AI provider、監控告警、跨專案同步、防再發與 no-false-green 驗收仍全部為 0。" }, "aiProvider": { "title": "AI 供應商 / 模型路由", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 2ae40f7b..3c28f16a 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -2087,12 +2087,12 @@ const highValueConfigOwnerPacketSummary = [ const highValueConfigControlCoverageSummary = [ { key: 'categories', value: '14', icon: ListChecks, tone: 'steady' }, { key: 'c0', value: '8', icon: AlertTriangle, tone: 'warn' }, - { key: 'coverage', value: '70%', icon: ShieldCheck, tone: 'warn' }, + { key: 'coverage', value: '71%', icon: ShieldCheck, tone: 'warn' }, { key: 'runtimeGate', value: '0', icon: Lock, tone: 'locked' }, ] as const const highValueConfigControlCoverageItems: HighValueConfigControlCoverageItem[] = [ - { key: 'dockerSystemd', rank: 'P1-1', value: '62%', icon: Server, tone: 'warn' }, + { key: 'dockerSystemd', rank: 'P1-1', value: '64%', icon: Server, tone: 'warn' }, { key: 'sshNetwork', rank: 'P1-2', value: '64%', icon: Network, tone: 'warn' }, { key: 'aiProvider', rank: 'P1-3', value: '64%', icon: Cloud, tone: 'warn' }, { key: 'k8sGitops', rank: 'P1-4', value: '64%', icon: Workflow, tone: 'warn' }, @@ -2104,8 +2104,8 @@ const highValueConfigControlCoverageBoundaries = [ 'high_value_config_control_coverage_category_count=14', 'high_value_config_control_coverage_c0_category_count=8', 'high_value_config_control_coverage_c1_category_count=4', - 'high_value_config_control_coverage_average_percent=70', - 'high_value_config_control_coverage_needs_live_evidence_count=10', + 'high_value_config_control_coverage_average_percent=71', + 'high_value_config_control_coverage_needs_live_evidence_count=9', 'high_value_config_control_coverage_owner_response_required_count=14', 'high_value_config_control_coverage_owner_response_received_count=0', 'high_value_config_control_coverage_owner_response_accepted_count=0', @@ -2231,6 +2231,28 @@ const highValueConfigControlCoverageBoundaries = [ 'host_service_change_evidence_acceptance_public_route_recovery_accepted_count=0', 'host_service_change_evidence_acceptance_operator_notification_accepted_count=0', 'host_service_change_evidence_acceptance_runtime_gate_count=0', + 'host_service_post_incident_readback_plan_candidate_count=9', + 'host_service_post_incident_readback_plan_write_capable_candidate_count=3', + 'host_service_post_incident_readback_plan_live_evidence_required_candidate_count=8', + 'host_service_post_incident_readback_plan_required_readback_field_count=28', + 'host_service_post_incident_readback_plan_reviewer_check_count=28', + 'host_service_post_incident_readback_plan_outcome_lane_count=10', + 'host_service_post_incident_readback_plan_blocked_action_count=41', + 'host_service_post_incident_readback_plan_post_incident_readback_received_count=0', + 'host_service_post_incident_readback_plan_post_incident_readback_accepted_count=0', + 'host_service_post_incident_readback_plan_docker_daemon_state_accepted_count=0', + 'host_service_post_incident_readback_plan_compose_stack_state_accepted_count=0', + 'host_service_post_incident_readback_plan_systemd_unit_state_accepted_count=0', + 'host_service_post_incident_readback_plan_failed_unit_review_accepted_count=0', + 'host_service_post_incident_readback_plan_port_binding_state_accepted_count=0', + 'host_service_post_incident_readback_plan_public_route_recovery_accepted_count=0', + 'host_service_post_incident_readback_plan_admin_route_recovery_accepted_count=0', + 'host_service_post_incident_readback_plan_agent_provider_health_accepted_count=0', + 'host_service_post_incident_readback_plan_monitoring_alert_accepted_count=0', + 'host_service_post_incident_readback_plan_operator_notification_accepted_count=0', + 'host_service_post_incident_readback_plan_cross_project_sync_accepted_count=0', + 'host_service_post_incident_readback_plan_no_false_green_accepted_count=0', + 'host_service_post_incident_readback_plan_runtime_gate_count=0', 'ssh_network_access_inventory_surface_count=16', 'ssh_network_access_inventory_write_capable_surface_count=6', 'ssh_network_access_inventory_runtime_gate_count=0', diff --git a/docs/schemas/iwooos_posture_projection_v1.schema.json b/docs/schemas/iwooos_posture_projection_v1.schema.json index 422a96e1..176c4e82 100644 --- a/docs/schemas/iwooos_posture_projection_v1.schema.json +++ b/docs/schemas/iwooos_posture_projection_v1.schema.json @@ -393,7 +393,42 @@ "ssh_network_post_incident_readback_plan_runtime_gate_count", "ssh_network_post_incident_readback_plan_action_button_count", "ssh_network_post_incident_readback_plan_coverage_percent_after_readback_plan", - "ssh_firewall_network_access_coverage_percent" + "ssh_firewall_network_access_coverage_percent", + "host_service_post_incident_readback_plan_first_layer", + "host_service_post_incident_readback_plan_candidate_count", + "host_service_post_incident_readback_plan_write_capable_candidate_count", + "host_service_post_incident_readback_plan_live_evidence_required_candidate_count", + "host_service_post_incident_readback_plan_recovery_health_impact_review_required_candidate_count", + "host_service_post_incident_readback_plan_cross_project_sync_required_candidate_count", + "host_service_post_incident_readback_plan_no_false_green_required_candidate_count", + "host_service_post_incident_readback_plan_readback_field_count", + "host_service_post_incident_readback_plan_required_readback_field_count", + "host_service_post_incident_readback_plan_reviewer_check_count", + "host_service_post_incident_readback_plan_outcome_lane_count", + "host_service_post_incident_readback_plan_blocked_action_count", + "host_service_post_incident_readback_plan_post_incident_readback_received_count", + "host_service_post_incident_readback_plan_post_incident_readback_accepted_count", + "host_service_post_incident_readback_plan_actor_attribution_accepted_count", + "host_service_post_incident_readback_plan_before_after_state_accepted_count", + "host_service_post_incident_readback_plan_docker_daemon_state_accepted_count", + "host_service_post_incident_readback_plan_compose_stack_state_accepted_count", + "host_service_post_incident_readback_plan_systemd_unit_state_accepted_count", + "host_service_post_incident_readback_plan_failed_unit_review_accepted_count", + "host_service_post_incident_readback_plan_port_binding_state_accepted_count", + "host_service_post_incident_readback_plan_public_route_recovery_accepted_count", + "host_service_post_incident_readback_plan_admin_route_recovery_accepted_count", + "host_service_post_incident_readback_plan_agent_provider_health_accepted_count", + "host_service_post_incident_readback_plan_monitoring_alert_accepted_count", + "host_service_post_incident_readback_plan_operator_notification_accepted_count", + "host_service_post_incident_readback_plan_cross_project_sync_accepted_count", + "host_service_post_incident_readback_plan_restoration_evidence_accepted_count", + "host_service_post_incident_readback_plan_postcheck_readback_accepted_count", + "host_service_post_incident_readback_plan_recurrence_guard_accepted_count", + "host_service_post_incident_readback_plan_no_false_green_accepted_count", + "host_service_post_incident_readback_plan_runtime_gate_count", + "host_service_post_incident_readback_plan_action_button_count", + "host_service_post_incident_readback_plan_coverage_percent_after_readback_plan", + "docker_compose_systemd_host_config_coverage_percent" ], "properties": { "route_path": { @@ -653,11 +688,11 @@ }, "high_value_config_control_coverage_average_percent": { "type": "integer", - "const": 70 + "const": 71 }, "high_value_config_control_coverage_needs_live_evidence_count": { "type": "integer", - "const": 10 + "const": 9 }, "high_value_config_control_coverage_owner_response_required_count": { "type": "integer", @@ -1671,6 +1706,146 @@ "ssh_firewall_network_access_coverage_percent": { "type": "integer", "const": 64 + }, + "host_service_post_incident_readback_plan_first_layer": { + "type": "boolean", + "const": true + }, + "host_service_post_incident_readback_plan_candidate_count": { + "type": "integer", + "const": 9 + }, + "host_service_post_incident_readback_plan_write_capable_candidate_count": { + "type": "integer", + "const": 3 + }, + "host_service_post_incident_readback_plan_live_evidence_required_candidate_count": { + "type": "integer", + "const": 8 + }, + "host_service_post_incident_readback_plan_recovery_health_impact_review_required_candidate_count": { + "type": "integer", + "const": 9 + }, + "host_service_post_incident_readback_plan_cross_project_sync_required_candidate_count": { + "type": "integer", + "const": 9 + }, + "host_service_post_incident_readback_plan_no_false_green_required_candidate_count": { + "type": "integer", + "const": 9 + }, + "host_service_post_incident_readback_plan_readback_field_count": { + "type": "integer", + "const": 36 + }, + "host_service_post_incident_readback_plan_required_readback_field_count": { + "type": "integer", + "const": 28 + }, + "host_service_post_incident_readback_plan_reviewer_check_count": { + "type": "integer", + "const": 28 + }, + "host_service_post_incident_readback_plan_outcome_lane_count": { + "type": "integer", + "const": 10 + }, + "host_service_post_incident_readback_plan_blocked_action_count": { + "type": "integer", + "const": 41 + }, + "host_service_post_incident_readback_plan_post_incident_readback_received_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_post_incident_readback_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_actor_attribution_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_before_after_state_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_docker_daemon_state_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_compose_stack_state_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_systemd_unit_state_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_failed_unit_review_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_port_binding_state_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_public_route_recovery_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_admin_route_recovery_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_agent_provider_health_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_monitoring_alert_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_operator_notification_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_cross_project_sync_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_restoration_evidence_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_postcheck_readback_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_recurrence_guard_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_no_false_green_accepted_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_runtime_gate_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_action_button_count": { + "type": "integer", + "const": 0 + }, + "host_service_post_incident_readback_plan_coverage_percent_after_readback_plan": { + "type": "integer", + "const": 64 + }, + "docker_compose_systemd_host_config_coverage_percent": { + "type": "integer", + "const": 64 } }, "additionalProperties": false diff --git a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md index ecad00a2..c23e68fb 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -115,8 +115,8 @@ | C1 類別 | `4` | 監控、Docker / systemd、SSH / network、AI provider | | C2 類別 | `1` | 產品 runtime route 與跨產品邊界 | | C3 類別 | `1` | security evidence / snapshot / guard tooling | -| 平均只讀控管成熟度 | `70%` | 僅代表框架 / evidence / owner packet / acceptance ledger / source guard 準備度,不代表 runtime 可執行 | -| 需要 live / owner evidence 的類別 | `10` | 只能等 owner-provided redacted evidence 或維護窗口,不主動修改 workflow、secret、runner、route、CORS、env、備份或主機 | +| 平均只讀控管成熟度 | `71%` | 僅代表框架 / evidence / owner packet / acceptance ledger / source guard / post-incident readback 準備度,不代表 runtime 可執行 | +| 需要 live / owner evidence 的類別 | `9` | 只能等 owner-provided redacted evidence 或維護窗口,不主動修改 workflow、secret、runner、route、CORS、env、備份或主機 | | owner response required | `14` | 每類都需要 owner response 才能往 accepted 前進 | | owner response received / accepted | `0 / 0` | 不得假性提高 | | runtime gate | `0` | 不得產生執行按鈕 | @@ -125,8 +125,8 @@ | 優先 | 類別 | 目前成熟度 | 下一步 | |------|------|------------|--------| -| P1-1 | Docker Compose / systemd / host service config | `62%` | repo-only 清冊、owner response acceptance 與 host service change evidence acceptance 已納入 9 個 surface;重啟 actor、before / after、Docker daemon、compose / systemd、failed unit、port binding、dependency、cold-start、route recovery、operator notification、cross-project sync 與 no-false-green 已納入;仍缺 owner response、live hash、change evidence、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence | -| P1-2 | SSH / sudoers / known_hosts / firewall / WireGuard / NodePort | `62%` | repo-only 清冊已納入 16 個 SSH / network access surface,owner request draft、owner response acceptance 與事故型端口 / 防火牆變更證據驗收 ledger 已完成;仍缺 owner-provided change / incident ref、actor、before / after state、health impact、notification、cross-project sync、maintenance window、rollback owner 與 post-check evidence | +| P1-1 | Docker Compose / systemd / host service config | `64%` | repo-only 清冊、owner response acceptance、host service change evidence acceptance 與 post-incident readback plan 已納入 9 個 surface;重啟 actor、boot / recovery window、before / after、Docker daemon、compose / systemd、failed unit、port binding、dependency、public/admin route recovery、AI provider、monitoring、operator notification、cross-project sync、防再發與 no-false-green 已納入;仍缺 owner response、live hash、事故回讀包、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence | +| P1-2 | SSH / sudoers / known_hosts / firewall / WireGuard / NodePort | `64%` | repo-only 清冊已納入 16 個 SSH / network access surface,owner response acceptance、事故型端口 / 防火牆變更證據驗收與 post-incident readback plan 已完成;仍缺 owner-provided change / incident ref、actor、before / after state、health impact、notification、cross-project sync、maintenance window、rollback owner 與 post-check evidence | | P1-3 | AI provider / model routing / Ollama proxy / cost and privacy | `64%` | 已新增 owner response acceptance 帳本,固定 8 個候選、24 個 owner 必填欄位、24 個 reviewer checks、10 條 outcome lanes、38 類 blocked actions;仍缺 provider owner、fallback order、dry-run、benchmark、cost review、privacy review、data classification、prompt redaction、quality gate、rollback owner 與 post-check evidence,不切 production | | P1-4 | K8s / ArgoCD / production manifests | `64%` | manifest inventory、owner response acceptance 與 GitOps change evidence acceptance 已完成;仍缺 proposed commit ref、rendered manifest diff、ArgoCD app / sync revision、health before / after、rollout、route smoke、metrics / alert、blast radius、rollback revision、maintenance window 與 post-check owner | | P1-5 | Backup / restore / escrow / retention | `64%` | repo-only 清冊已納入 38 個 surface,owner request draft 與 owner response acceptance ledger 已完成,並補 restore recovery、freshness SLO、隔離還原目標、remote delete guard、retention runway、credential recovery metadata-only 與 no-false-green backup health Gate;仍缺 owner response、restore drill approval package、offsite / escrow owner、rollback owner、validation plan 與 no-secret-value evidence | @@ -266,6 +266,7 @@ python3 scripts/security/iwooos-config-control-guard.py --root . | Monitoring / alerting / observability owner response acceptance backfill | `100%` | 已將 `monitoring_owner_response_acceptance_v1` 補強為 60 個 candidate、11 個 write-capable、38 個 acceptance fields、23 個 reviewer checks、12 條 outcome lanes、34 類 blocked action;monitoring / alerting / observability 成熟度 `66% -> 68%` | | AI provider / model routing owner response acceptance | `100%` | 已新增 `ai_provider_owner_response_acceptance_v1`,8 個 candidate、5 個 write-capable、24 個 owner 必填欄位、24 個 reviewer checks、10 條 outcome lanes、38 類 blocked action;AI provider / model routing 成熟度 `60% -> 64%` | | SSH / firewall / network post-incident readback plan | `100%` | 已新增 `ssh_network_post_incident_readback_plan_v1`,14 個事故回讀 candidate、6 個 write-capable、24 個必填欄位、24 個 reviewer checks、10 條 outcome lanes、34 類 blocked action;成熟度 `62% -> 64%`,readback received / accepted、actor、before / after、impact、通知、同步、恢復、防再發與 runtime gate 仍為 `0` | +| Docker / systemd / host service post-incident readback plan | `100%` | 已新增 `host_service_post_incident_readback_plan_v1`,9 個事故回讀 candidate、3 個 write-capable、28 個必填欄位、28 個 reviewer checks、10 條 outcome lanes、41 類 blocked action;成熟度 `62% -> 64%`,readback received / accepted、Docker daemon、compose、systemd、failed unit、port binding、public/admin route、AI provider、monitoring、同步、防再發與 runtime gate 仍為 `0` | | owner response 收件 | `0%` | 尚未收到或接受任何 owner response | | live evidence collection | `0%` | 未 SSH、未 live probe、未 active scan | | runtime gate | `0%` | 未開啟任何執行期閘門 | @@ -278,6 +279,8 @@ python3 scripts/security/iwooos-config-control-guard.py --root . 2026-06-15 追加事故回補欄位,將 `host_service_owner_response_acceptance_v1` 固定為 `acceptance_field_count=34`、`required_owner_field_count=18`、`reviewer_check_count=21`、`outcome_lane_count=8`、`blocked_action_count=27`。新增要求包含 source-of-truth、服務依賴圖、port binding、cold-start sequence、incident recovery evidence 與 daemon / runner contention review。此更新讓 `docker_compose_systemd_host_config` 從 `54%` 推進到 `58%`,但 owner response received / accepted、live hash、maintenance / restart window、rollback owner、post-check plan、disable switch、live host read、SSH、Docker Compose、systemctl、repair-bot、Ansible、sudo、host write、runtime gate 與 action button 仍全部為 `0`。 +2026-06-15 再新增 `host_service_post_incident_readback_plan_v1`,將同一批 Docker / systemd / compose / repair-bot / Ansible / host config surface 轉成 `readback_candidate_count=9`、`write_capable_readback_candidate_count=3`、`live_evidence_required_readback_candidate_count=8`、`required_readback_field_count=28`、`reviewer_check_count=28`、`outcome_lane_count=10`、`blocked_action_count=41` 的事故後回讀計畫。此更新讓 `docker_compose_systemd_host_config` 從 `62%` 推進到 `64%`,但 post-incident readback received / accepted、actor attribution、before / after state、Docker daemon、compose、systemd、failed unit、port binding、public/admin route recovery、AI provider health、monitoring alert、operator notification、cross-project sync、restoration evidence、post-check、recurrence guard、no-false-green、runtime gate 與 action button 仍全部為 `0`。 + ## 9. P1-2 SSH / network access 清冊更新 `ssh_network_access_inventory_v1` 已把 SSH target、known_hosts workflow、CI deploy SSH、monitoring SSH、backup SSH capture、sudoers wrapper、NetworkPolicy、NodePort、WireGuard runbook 與 alert SSH action catalog 納入 repo-only 清冊,共 `16` 個 surface、`6` 個 write-capable surface、`2` 個 NetworkPolicy、`2` 個 NodePort、`1` 個 sudoers surface 與 `1` 個 WireGuard surface。此更新只讓 `ssh_firewall_network_access` 從 `48%` 推進到 `54%`;owner response、live evidence、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0`。 diff --git a/docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md b/docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md new file mode 100644 index 00000000..29065397 --- /dev/null +++ b/docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md @@ -0,0 +1,198 @@ +# IwoooS Docker / systemd / 主機服務事故後回讀計畫 + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-15 | +| 狀態 | `post_incident_readback_plan_ready_no_runtime_action` | +| 工具 | `scripts/security/host-service-post-incident-readback-plan.py` | +| Snapshot | `docs/security/host-service-post-incident-readback-plan.snapshot.json` | +| Source acceptance | `docs/security/host-service-change-evidence-acceptance.snapshot.json` | +| runtime gate | `0` | + +## 1. 目的 + +本文件承接 Docker / systemd / host service 變更證據驗收帳本,補上事故後回讀計畫。未來若再次發生主機重啟、Docker daemon 卡住、compose stack 異常、systemd failed unit、repair-bot / runner 競爭、port binding / gateway 不一致、public route 或 AI provider 健康異常,IwoooS 必須先收齊「誰動、何時動、改前改後狀態、影響哪些服務、如何恢復、是否同步相關產品、如何防再發」的脫敏證據。 + +這不是 SSH 授權、不是 live host read、不是 docker / systemctl 操作、不是 repair-bot 執行、不是 Ansible apply、不是 route smoke、不是 host restart,也不是 runtime gate。它只建立 post-incident readback 的欄位、reviewer checks、分流與拒收條件,避免把「Docker API 可回應」、「container up」、「route 200」、「dashboard 可見」或「服務暫時恢復」誤判成「事故原因、責任、影響、恢復與防再發都已驗收」。 + +## 2. 摘要 + +| 指標 | 目前值 | 說明 | +|------|--------|------| +| readback candidate | `9` | 承接 compose、systemd、repair-bot、Ansible service role 與 host config backup capture surface | +| write-capable readback candidate | `3` | Ansible docker compose service role、110 repair-bot whitelist、188 repair-bot whitelist | +| live evidence required | `8` | 除本機開發 compose 外,其餘都需要 owner 提供脫敏 live evidence ref | +| recovery / health impact review required | `9` | 全部都必須交代 service、route、AI provider、monitoring 與產品影響 | +| cross-project sync required | `9` | 全部都必須交代跨產品 / owner / Session 同步 ref | +| no-false-green required | `9` | 全部都不得用服務變綠替代事故驗收 | +| readback field | `36` | readback 欄位總數 | +| required readback field | `28` | owner / reviewer 必填欄位 | +| reviewer check | `28` | actor、boot / recovery、before / after、daemon、compose、systemd、failed unit、port binding、impact、同步、防再發與 no-false-green 檢查 | +| outcome lane | `10` | waiting、補 actor、補 before-after、補服務狀態、補 impact、隔離、拒收、review、防再發回補、runtime gate | +| blocked action | `41` | SSH、Docker、systemctl、repair-bot、Ansible、route smoke、reload、restart、secret、raw log / config、active scan、production write 等 | +| post-incident readback received / accepted | `0 / 0` | 尚未收到或驗收 | +| no-false-green accepted | `0` | 不把 route 200、container up、Docker API 回應、dashboard up 或 service healthy 當事故驗收 | +| runtime gate / action button | `0 / 0` | 不提供操作入口 | + +## 3. Readback Candidate 範圍 + +| Candidate | 驗收焦點 | +|-----------|----------| +| `host_service_post_incident_readback:local_dev_compose` | 本機 compose 與 production 邊界,避免把開發狀態誤投影到正式服務 | +| `host_service_post_incident_readback:monitoring_110_compose` | 110 monitoring compose、Prometheus / Alertmanager / exporter、route recovery 與 alert false-green | +| `host_service_post_incident_readback:monitoring_exporters_188_compose` | 188 exporter compose、資料庫 / Redis 指標、monitoring 影響與 post-check | +| `host_service_post_incident_readback:sentry_110_reference_compose` | Sentry self-hosted compose、核心容器狀態、public route 與 admin route recovery | +| `host_service_post_incident_readback:langfuse_110_compose` | Langfuse compose、trace / prompt privacy 邊界、route 與 DB 依賴 | +| `host_service_post_incident_readback:ansible_docker_compose_service_role` | Ansible service role、compose action 權限、maintenance window 與 rollback owner | +| `host_service_post_incident_readback:repair_bot_110_whitelist` | 110 repair-bot whitelist、Harbor / registry / Gitea / Langfuse / Alertmanager / SigNoz 影響 | +| `host_service_post_incident_readback:repair_bot_188_whitelist` | 188 repair-bot whitelist、OpenClaw / MinIO / SigNoz / Redis / Nginx / Ollama 影響 | +| `host_service_post_incident_readback:config_backup_host_capture` | host config backup capture、systemd / Docker / Nginx / cron / K8s 來源與 no raw config 邊界 | + +## 4. 必填 Readback 欄位 + +1. `change_or_incident_ref` +2. `actor_attribution_ref` +3. `boot_time_ref` +4. `restart_or_recovery_window_ref` +5. `before_service_state_ref` +6. `after_service_state_ref` +7. `docker_daemon_state_ref` +8. `compose_stack_state_ref` +9. `systemd_unit_state_ref` +10. `failed_unit_review_ref` +11. `port_binding_state_ref` +12. `dependency_impact_ref` +13. `public_route_recovery_ref` +14. `admin_route_recovery_ref` +15. `agent_provider_health_ref` +16. `monitoring_alert_ref` +17. `operator_notification_ref` +18. `cross_project_sync_ref` +19. `restoration_evidence_ref` +20. `postcheck_readback_ref` +21. `recurrence_guard_ref` +22. `maintenance_window` +23. `rollback_owner` +24. `followup_owner` +25. `redacted_evidence_refs` +26. `no_secret_value_attestation` +27. `no_raw_log_or_config_attestation` +28. `no_false_green_attestation` + +## 5. Reviewer Checks + +1. `source_change_evidence_current` +2. `incident_ref_present` +3. `actor_not_anonymous` +4. `boot_or_recovery_window_present` +5. `before_after_service_state_present` +6. `docker_daemon_state_present` +7. `compose_stack_state_present` +8. `systemd_unit_state_present` +9. `failed_unit_review_present` +10. `port_binding_state_present` +11. `dependency_impact_present` +12. `public_route_recovery_present` +13. `admin_route_recovery_present` +14. `agent_provider_health_present` +15. `monitoring_alert_ref_present` +16. `operator_notification_present` +17. `cross_project_sync_present` +18. `restoration_evidence_present` +19. `postcheck_independent` +20. `recurrence_guard_present` +21. `runner_repair_bot_contention_present` +22. `maintenance_window_present` +23. `rollback_owner_present` +24. `no_false_green_route_or_container` +25. `raw_log_config_absent` +26. `secret_or_key_value_absent` +27. `counts_transition_safe` +28. `runtime_stays_zero` + +## 6. Outcome Lanes + +| Lane | 說明 | +|------|------| +| `waiting_post_incident_readback` | 尚未收到主機服務事故回讀包;所有 accepted / runtime count 維持 0 | +| `request_actor_supplement` | 缺 actor / owner / decision 時要求補件 | +| `request_before_after_supplement` | 缺 before / after、boot time、restart window 或 restoration evidence 時要求補件 | +| `request_service_state_supplement` | 缺 Docker daemon、compose、systemd、failed unit、port binding 或 dependency 狀態時要求補件 | +| `request_impact_supplement` | 缺 public/admin route、AI provider、monitoring、operator notification 或 cross-project sync 時要求補件 | +| `quarantine_raw_payload` | 收到 secret、env dump、raw log、raw journal、raw compose 或未脫敏 host config 時只能隔離 | +| `reject_unattributed_restart` | 無 actor、無 affected scope、無 rollback 或無 notification 的 restart / kill / compose action 不得驗收 | +| `ready_for_host_service_post_incident_review` | metadata 合格後,只能進 reviewer review | +| `recurrence_guard_backfill_required` | 需補防再發 guard、owner review、change freeze 或 automation block | +| `waiting_runtime_gate` | 即使 readback accepted,runtime gate 仍需獨立人工批准 | + +## 7. 禁止動作 + +1. `ssh_read` +2. `ssh_write` +3. `live_host_read` +4. `docker_ps_live_read` +5. `docker_restart` +6. `docker_kill` +7. `docker_start` +8. `docker_compose_up` +9. `docker_compose_down` +10. `docker_compose_pull` +11. `systemctl_restart` +12. `systemctl_reload` +13. `systemctl_kill` +14. `systemctl_start` +15. `repair_bot_execute` +16. `ansible_apply` +17. `sudo_action` +18. `host_file_write` +19. `firewall_change` +20. `port_change` +21. `route_smoke` +22. `public_gateway_reload` +23. `nginx_reload` +24. `active_scan` +25. `secret_value_collection` +26. `raw_live_config_storage` +27. `raw_docker_log_storage` +28. `raw_journal_storage` +29. `raw_env_dump_storage` +30. `accept_restart_without_actor` +31. `accept_recovery_without_before_after` +32. `accept_service_healthy_as_config_accepted` +33. `accept_route_200_as_all_green` +34. `accept_container_up_as_all_green` +35. `skip_dependency_map_review` +36. `skip_port_binding_review` +37. `hide_daemon_runner_contention` +38. `mark_readback_accepted_without_reviewer_record` +39. `open_runtime_gate` +40. `add_action_button` +41. `production_write` + +## 8. 指令 + +產生 committed snapshot: + +```bash +python3 scripts/security/host-service-post-incident-readback-plan.py \ + --root . \ + --source-change-evidence-report docs/security/host-service-change-evidence-acceptance.snapshot.json \ + --output docs/security/host-service-post-incident-readback-plan.snapshot.json \ + --generated-at 2026-06-15T20:30:00+08:00 +``` + +驗證 guard: + +```bash +python3 scripts/security/security-mirror-progress-guard.py --root . +``` + +## 9. 完成度 + +- 只讀計畫:`100%` +- owner readback received:`0%` +- reviewer accepted:`0%` +- runtime gate:`0%` +- action button:`0%` + +下一步是請 owner 以脫敏 evidence ref 補齊 110 / 188 / service surface 的事故回讀包;在驗收前,IwoooS 不會把任何 Docker / systemd / compose / repair-bot / route / monitoring 狀態提高成執行期授權。 diff --git a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md index c5958115..bc993616 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -32,8 +32,8 @@ | 註冊配置類別 | `14` | 代表已進 Gate 分類,不代表已批准 | | C0 類別 | `8` | Nginx、DNS / TLS、K8s、secret、workflow / runner、runtime config、backup、agent-bounty runtime | | C1 類別 | `4` | 監控、Docker / systemd、SSH / network、AI provider | -| 平均只讀控管成熟度 | `70%` | 只代表框架 / evidence / owner packet / acceptance ledger / source guard 準備度 | -| 需要 live evidence 類別 | `10` | 只能等 owner-provided redacted evidence 或維護窗口,不主動 SSH、不改 route / CORS / env / backup | +| 平均只讀控管成熟度 | `71%` | 只代表框架 / evidence / owner packet / acceptance ledger / source guard / post-incident readback 準備度 | +| 需要 live evidence 類別 | `9` | 只能等 owner-provided redacted evidence 或維護窗口,不主動 SSH、不改 route / CORS / env / backup | | owner response required | `14` | owner response received / accepted 仍 `0 / 0` | | runtime gate | `0` | 不提供執行按鈕 | @@ -135,7 +135,13 @@ 此更新只表示未來 host service 事故或變更證據已有收件驗收規則;change evidence received / accepted、Docker daemon state accepted、compose stack state accepted、systemd unit state accepted、failed unit review accepted、port binding accepted、route recovery accepted、operator notification accepted、live host read、SSH、Docker / systemd、repair-bot、Ansible、route smoke、host write、runtime gate 仍全部為 `0 / false`。 -### 0.8b 2026-06-15 AI provider / model routing owner response acceptance 只讀帳本 +### 0.8b 2026-06-15 Docker / systemd / host service 事故後回讀計畫 + +`host_service_post_incident_readback_plan_v1` 已把同一批 9 個 Docker / systemd / host service surface 補成 post-incident readback plan。固定 `readback_candidates=9`、`write_capable=3`、`live_evidence_required=8`、`readback_fields=36`、`required_readback_fields=28`、`reviewer_checks=28`、`outcome_lanes=10`、`blocked_actions=41`,並要求 actor、boot time、restart / recovery window、before / after、Docker daemon、compose、systemd、failed unit、port binding、dependency、public/admin route、AI provider、monitoring、operator notification、cross-project sync、restoration evidence、post-check、recurrence guard 與 no-false-green attestation,讓 Docker / systemd / host service 類別成熟度從 `62%` 推進到 `64%`。 + +此更新只表示 110 / 188 類主機服務事故已有事故後回讀收件規則;post-incident readback received / accepted、actor attribution accepted、Docker daemon accepted、compose accepted、systemd accepted、route recovery accepted、monitoring accepted、cross-project sync accepted、recurrence guard accepted、live host read、SSH、Docker / systemd、repair-bot、Ansible、route smoke、host write、production write、runtime gate 仍全部為 `0 / false`。 + +### 0.8c 2026-06-15 AI provider / model routing owner response acceptance 只讀帳本 `ai_provider_owner_response_acceptance_v1` 已把 AI router provider policy、Ollama proxy gateway、fallback order / circuit breaker、cost budget / quota、privacy / data egress、benchmark / dry-run、model card / version inventory 與 agent replacement candidate boundary 轉成 metadata-only owner response acceptance 帳本。固定 `candidates=8`、`write_capable=5`、`paid_provider_related=5`、`data_egress=6`、`live_evidence_required=6`、`acceptance_fields=37`、`required_owner_fields=24`、`reviewer_checks=24`、`outcome_lanes=10`、`blocked_actions=38`,讓 AI provider / model routing 類別成熟度從 `60%` 推進到 `64%`。 @@ -154,7 +160,7 @@ | P1 | 高價值配置變更 Gate | 已有 C0-C3 清冊與 Hard Rule,但原本缺少可重跑 path 分類 | reviewer 只能靠人工記憶判斷 Nginx、workflow、secret、K8s、DNS、AI provider 是否需 owner gate | 已新增 `scripts/security/high-value-config-change-gate.py`;本階段只分類,不接 CI blocking | | P0 | DNS / TLS / certbot | 已有 domain / certificate path 清冊、owner confirmation request 與 owner response acceptance 只讀帳本,但仍缺 owner-provided coverage metadata、expiry metadata、renewal owner、ACME route owner、maintenance window 與 rollback owner | 憑證過期、錯誤 cert path、ACME challenge 被覆蓋會造成公開服務中斷 | 維持 C0;下一步只收脫敏 metadata ref,不做 DNS query、TLS probe、certbot renew 或 reload | | P1 | workflow / runner / deploy key / secret name | 已有 Gitea / GitHub readiness 盤點,但尚未把配置變更和 IwoooS 高價值配置共用 gate 合併 | workflow 或 runner 改錯會直接影響部署與 secret 注入 | 納入 C0,維持只讀 owner response,不收 secret value | -| P1 | Docker Compose / systemd live config | 已有 repo-only inventory、owner request draft 與 owner response acceptance 只讀帳本,但仍缺 owner-provided live hash、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence | restart policy、port、volume、env 改動會影響 Harbor、Sentry、Langfuse、Gitea 與代理賞金協議 runtime | 下一步只收脫敏 owner response / live hash metadata,不主動 SSH、不重啟、不跑 repair-bot | +| P1 | Docker Compose / systemd live config | 已有 repo-only inventory、owner request draft、owner response acceptance、change evidence acceptance 與 post-incident readback plan 只讀帳本,但仍缺 owner-provided live hash、事故回讀包、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence | restart policy、port、volume、env、daemon / compose / systemd 異動會影響 Harbor、Sentry、Langfuse、Gitea、監控、AI provider 與代理賞金協議 runtime | 下一步只收脫敏 owner response / live hash metadata / 事故回讀 ref,不主動 SSH、不重啟、不跑 repair-bot | | P1 | AI provider / Ollama proxy | Nginx proxy template、API provider route、fallback order、模型治理卡與 agent replacement 候選 | provider route drift 會造成成本、可用性、資料外送與模型品質風險 | 納入 C1,owner response acceptance 已固定;任何切換仍需 dry-run / benchmark / cost / privacy / rollback owner gate | | P1 | agent-bounty-protocol runtime / treasury / A2A / MCP | 已納入只讀範圍,但尚未有 production host、compose、domain、TLS、rollback owner 完整資料 | 外部 agent、claim / submit、payout 或 webhook 若未控管,風險高於一般網站 | 納入 C2,仍不改該 repo、不讀 `.env`、不部署 | @@ -274,6 +280,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 | Docker / systemd owner request draft | `100%` | 已將 9 個 host service surface 轉成 owner request draft;request sent / received / accepted 仍為 0 | | Docker / systemd owner response acceptance | `100%` | 已新增 `host_service_owner_response_acceptance_v1`,9 個 candidate、3 個 write-capable、8 個需 live evidence、21 個 reviewer checks、8 條 outcome lanes、27 類 blocked action;成熟度 `54% -> 58%` | | Docker / systemd change evidence acceptance | `100%` | 已新增 `host_service_change_evidence_acceptance_v1`,9 個 candidate、3 個 write-capable、26 個 reviewer checks、10 條 outcome lanes、39 類 blocked action;成熟度 `58% -> 62%` | +| Docker / systemd 事故後回讀計畫 | `100%` | 已新增 `host_service_post_incident_readback_plan_v1`,9 個 readback candidate、28 個必填欄位、28 個 reviewer checks、10 條 outcome lanes、41 類 blocked action;成熟度 `62% -> 64%`,readback accepted 與 runtime gate 仍為 `0` | | SSH / firewall / network owner request draft | `100%` | 已將 16 個 SSH / network access surface 轉成 owner request draft;request sent / received / accepted、port change、firewall change、NetworkPolicy apply、NodePort change、WireGuard change 仍為 0 | | SSH / firewall / network owner response acceptance | `100%` | 已新增 `ssh_network_owner_response_acceptance_v1`,16 個 candidate、6 個 write-capable、15 個 reviewer checks、7 條 outcome lanes、22 類 blocked action;成熟度 `54% -> 58%` | | 端口 / 防火牆變更證據驗收 | `100%` | 已新增並強化 `port_firewall_change_evidence_acceptance_v1`,14 個 candidate、6 個 write-capable、21 個 reviewer checks、9 條 outcome lanes、28 類 blocked action;成熟度 `58% -> 62%` | diff --git a/docs/security/IWOOOS-POSTURE-PROJECTION.md b/docs/security/IWOOOS-POSTURE-PROJECTION.md index b251b468..c3466caf 100644 --- a/docs/security/IWOOOS-POSTURE-PROJECTION.md +++ b/docs/security/IWOOOS-POSTURE-PROJECTION.md @@ -95,10 +95,11 @@ IwoooS 首版只讀取或對齊以下已提交 evidence: 51. 10 個 frontend surface reverse bridge statuses,顯示既有資安入口目前是 embedded bridge、direct bridge 或 AwoooP read-only candidate;這只是連接狀態,不代表 owner response、runtime authorization、Code Review blocker、Gitea/GitHub action 或任何執行控制。 52. 6 個 source control primary readiness items,顯示 GitHub primary 前置缺口:candidate repo inventory、primary ready counter、owner response validation、refs truth、workflow / secret name inventory、rollback ADR;這只是 readiness,不代表 repo 建立、visibility 變更、refs mutation、secret value collection、primary switch 或 Gitea 停用。 53. 4 個 rollout risk read-only items,顯示風險來源部署 marker、`AWOOOI_ROLLOUT_RISK=1`、ArgoCD `Degraded` / `OutOfSync`、API health / smoke 已通過與執行期閘門仍為 0;這只是部署風險可見性,不代表 ArgoCD sync、kubectl、主機重啟、修復、部署或 runtime gate 已授權。 -54. 14 類 high-value config control coverage statuses,顯示 Nginx、DNS / TLS、K8s、機密、工作流程、執行器、backup、agent-bounty runtime、monitoring、Docker / systemd、SSH / network、AI provider、產品 route 與 security evidence 的全域配置控管覆蓋矩陣;平均只讀成熟度 `70%`、C0 類別 `8`、需 live / owner evidence 類別 `10`、owner response received / accepted 與 runtime gate 仍為 `0`,不代表 reload、sync、scan、secret rotation、payout 或主機操作授權。 +54. 14 類 high-value config control coverage statuses,顯示 Nginx、DNS / TLS、K8s、機密、工作流程、執行器、backup、agent-bounty runtime、monitoring、Docker / systemd、SSH / network、AI provider、產品 route 與 security evidence 的全域配置控管覆蓋矩陣;平均只讀成熟度 `71%`、C0 類別 `8`、需 live / owner evidence 類別 `9`、owner response received / accepted 與 runtime gate 仍為 `0`,不代表 reload、sync、scan、secret rotation、payout 或主機操作授權。 54a. 前台 source / messages 敏感資訊防洩漏 guard 已固定 `public_surface_file_count=225`、`forbidden_pattern_count=12`、`allowlisted_match_count=2`、`violation_count=0`、`runtime_gate_count=0`,讓 `public_admin_api_runtime_config` 從 `64%` 推進到 `66%`;這只代表 source-control 防洩漏 gate,仍不是 production bundle scan accepted、desktop / mobile production smoke accepted、owner response accepted 或 runtime gate。 55. 9 個 host-service config repo-only inventory surfaces,顯示 Docker Compose、systemd / repair-bot、Ansible service role 與 host config backup capture 的第一層清冊;write-capable surface `3`、repair-bot whitelist `2`、systemd restart surface `1`,owner response、live evidence、restart window、rollback owner、runtime gate 與 action button 仍全部為 `0`,不代表 `docker compose`、`systemctl`、repair-bot 或 Ansible apply 已授權。 55a. 9 個 Docker / systemd / host service change evidence acceptance 候選,顯示重啟 actor、before / after service state、Docker daemon state、compose / systemd state、failed unit review、port binding、dependency impact、cold-start sequence、route recovery、operator notification、cross-project sync 與 no-false-green service health 收件規則;write-capable candidate `3`、required evidence field `25`、reviewer check `26`、outcome lane `10`、blocked action `39`,讓 Docker / systemd / host service 類別成熟度從 `58%` 推進到 `62%`;change evidence、Docker daemon state accepted、compose stack accepted、systemd unit accepted、failed unit review accepted、port binding accepted、route recovery accepted、operator notification accepted、live host read、Docker / systemd、repair-bot、Ansible、route smoke、runtime gate 與 action button 仍全部為 `0`。 +55b. 9 個 Docker / systemd / host service post-incident readback 候選,顯示主機重啟、Docker daemon、compose、systemd、failed unit、port binding、public/admin route、AI provider、monitoring、operator notification、cross-project sync、restoration evidence、post-check、recurrence guard 與 no-false-green attestation 的事故後回讀規則;write-capable candidate `3`、live evidence required `8`、required readback field `28`、reviewer check `28`、outcome lane `10`、blocked action `41`,讓 Docker / systemd / host service 類別成熟度從 `62%` 推進到 `64%`;readback received / accepted、Docker daemon accepted、compose accepted、systemd accepted、route recovery accepted、monitoring accepted、cross-project sync accepted、recurrence guard accepted、runtime gate 與 action button 仍全部為 `0`。 56. 16 個 SSH / network access repo-only inventory surfaces、owner response acceptance 與端口 / 防火牆變更證據驗收只讀帳本,顯示 SSH target、known_hosts workflow、CI deploy SSH、monitoring SSH、backup SSH capture、sudoers wrapper、NetworkPolicy、NodePort、WireGuard runbook 與 alert SSH action catalog 的第一層清冊;write-capable surface `6`、NetworkPolicy `2`、NodePort `2`、sudoers `1`、WireGuard `1`,acceptance candidate `16`、change evidence candidate `14`、reviewer check `21`、outcome lane `9`、blocked action `28`,讓 SSH / network 類別成熟度從 `58%` 推進到 `62%`;owner response、change evidence、actor、before / after state、service health impact、operator notification、cross-project sync、post-check evidence、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0`,不代表 SSH、sudo、firewall、port close / open、NetworkPolicy、NodePort、WireGuard、route smoke 或 known_hosts patch 已授權。 56d. 14 個 SSH / network / firewall post-incident readback 候選,顯示端口關閉、firewall / NetworkPolicy / NodePort / WireGuard policy、deploy SSH、sudo 與 alert action 事故後必須回讀 actor、before / after、service / public route / AI provider / monitoring impact、operator notification、cross-project sync、restoration evidence、post-check、recurrence guard 與 no-false-green attestation;write-capable candidate `6`、policy / exposure candidate `5`、required readback field `24`、reviewer check `24`、outcome lane `10`、blocked action `34`,讓 SSH / network 類別成熟度從 `62%` 推進到 `64%`;readback received / accepted、actor accepted、before / after accepted、impact accepted、notification accepted、sync accepted、restoration accepted、recurrence guard accepted、runtime gate 與 action button 仍全部為 `0`。 56a. 4 個 K8s / ArgoCD GitOps 變更證據驗收候選,顯示 production manifests、ArgoCD app、Velero、monitoring manifests 的 proposed commit、rendered manifest diff、ArgoCD app / sync revision、health before / after、rollout、route smoke、metrics / alert、secret metadata parity、blast radius、maintenance window、rollback revision 與 postcheck owner 收件規則;C0 candidate `3`、write-capable candidate `4`、reviewer check `18`、outcome lane `8`、blocked action `28`,讓 K8s / ArgoCD 類別成熟度從 `62%` 推進到 `64%`;change evidence、runtime approval package、ArgoCD API read、ArgoCD sync、kubectl action、Helm upgrade、NetworkPolicy / NodePort / RBAC change、production write、runtime gate 與 action button 仍全部為 `0`。 diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index 2b6fb614..d25a84a2 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -3,17 +3,23 @@ | 項目 | 內容 | |------|------| | 日期 | 2026-06-15 | -| 狀態 | IwoooS 64% 只讀治理推進中;高價值配置集中 guard、Package / Docker 供應鏈 repo-only baseline 與 Package / Docker 供應鏈 owner policy gate 已完成;Frontend public sensitive surface guard、Backup / Restore / Escrow owner response acceptance backfill、Monitoring / Alerting / Observability no-false-green owner response acceptance、Host Service change evidence acceptance、AI provider / model routing owner response acceptance、CD / Runner / Secret 注入變更證據驗收與 Public / Admin / API runtime config 變更證據驗收只讀帳本已本地完成;端口 / 防火牆變更證據驗收、主機服務事故回補與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 | +| 狀態 | IwoooS 64% 只讀治理推進中;高價值配置集中 guard、Package / Docker 供應鏈 repo-only baseline 與 Package / Docker 供應鏈 owner policy gate 已完成;Frontend public sensitive surface guard、Backup / Restore / Escrow owner response acceptance backfill、Monitoring / Alerting / Observability no-false-green owner response acceptance、Host Service change evidence acceptance、Host Service post-incident readback plan、AI provider / model routing owner response acceptance、CD / Runner / Secret 注入變更證據驗收與 Public / Admin / API runtime config 變更證據驗收只讀帳本已本地完成;端口 / 防火牆變更證據驗收、主機服務事故回補與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 | | 本階段完成 | 資安供應鏈 contract manifest + Source Control Approval Board + Draft Reconcile Plan + Ref Detail Diff + Ref Truth Classification + Source Control Ref Truth Owner Response 收件包 + GitHub Primary Readiness Gate + GitHub Primary Rollback ADR + GitHub Target Owner Decision Response 收件包 + Gitea 認證清冊匯出請求 + Gitea 認證清冊匯入驗收契約 + Gitea 清冊覆蓋 Owner Attestation + Gitea Owner Attestation Approval Lane 對齊 + Gitea Owner Attestation Response 收件包 + Workflow / Secret Name Inventory + Workflow / Secret Name Local Evidence + Workflow / Secret Name Redacted Export Request + Workflow / Secret Name Owner Response 收件包 + Source Control Owner Response Validation Rollup + Kali 112 live integration status + Security Finding contract + Kali scan scope approval package + Security Approval Queue + S3 人工批准 Gate + S3 人工決策紀錄 + S3 人工審查封包 + S3 人工決策狀態轉移 + S3 後續 runtime gate 準備契約 + 鏡像 readiness index + 鏡像接收計畫 + 鏡像事件信封 + 鏡像路由矩陣 + 鏡像驗收契約 + 鏡像隔離契約 + 鏡像 dry-run 報告契約 + 鏡像狀態彙整契約 + IwoooS 前端態勢入口 + IwoooS posture projection contract + IwoooS 既有前端資安頁面整合 + IwoooS 覆蓋與邊界矩陣 + IwoooS 只讀資安處理旅程 + IwoooS owner evidence readiness board + IwoooS host coverage view + IwoooS host action gate matrix + IwoooS host evidence readiness board + IwoooS host evidence collection order + IwoooS host evidence intake preflight + IwoooS host evidence review outcome lanes + IwoooS host evidence review handoff packets + IwoooS host evidence reviewer checklist + IwoooS host evidence reviewer outcome lanes + IwoooS host owner decision candidate packets + IwoooS host owner decision review checklist + IwoooS host owner decision review outcome lanes + IwoooS host owner decision record draft packets + IwoooS host owner decision record draft review checklist + IwoooS host owner decision record draft review outcome lanes + IwoooS host owner decision record write-up packets + IwoooS host owner decision record write-up review checklist + IwoooS host owner decision record write-up review outcome lanes + IwoooS host owner decision record formal candidate packets + IwoooS host owner decision record formal candidate review checklist + IwoooS host owner decision record formal candidate review outcome lanes + IwoooS host owner decision record formal record queue packets + IwoooS host owner decision record formal record queue review checklist + IwoooS host owner decision record formal record queue review outcome lanes + IwoooS host owner decision record human handoff readiness packets + IwoooS host owner decision record human handoff readiness review checklist + IwoooS host owner decision record human handoff readiness review outcome lanes + IwoooS host owner decision record human record owner review candidate packets + IwoooS host owner decision record human record owner review candidate checklist + IwoooS host owner decision record human record owner review candidate outcome lanes + IwoooS host owner decision record human record owner review preparation packets + IwoooS host owner decision record human record owner review preparation checklist + IwoooS progress acceleration lanes + IwoooS owner response next-action focus + IwoooS S4.9 owner response preflight + IwoooS S4.9 owner response request templates + IwoooS progress hold movement gates + IwoooS AwoooP read-only landing readiness + IwoooS AwoooP cross-session handoff packets + AwoooP 首頁 IwoooS 資安鏡像候選 + AwoooP 工作鏈路 IwoooS 資安鏡像候選 + AwoooP 審批佇列 IwoooS owner response 只讀焦點 | | 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP 執行監控 IwoooS 執行狀態只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 + IwoooS GitHub 主要來源就緒度只讀狀態板 + AwoooP 工作鏈路 GitHub 主要來源就緒度只讀工作項 + AwoooP 合約儀表板 GitHub 主要來源就緒度合約只讀候選 + AwoooP 審批佇列 GitHub 主要來源就緒度審批邊界 + AwoooP 首頁 GitHub 主要來源就緒度只讀摘要 + AwoooP 租戶管理 GitHub 主要來源就緒度租戶範圍 + AwoooP 執行監控 GitHub 主要來源就緒度執行邊界 + IwoooS / AwoooP 資安可視區塊繁體中文呈現防護檢查 + AwoooP 執行詳情 / 審批詳情繁體中文呈現防護檢查 + AwoooP 首頁負責人回覆驗收總覽 + AwoooP 工作鏈路負責人回覆驗收只讀工作項 + AwoooP 合約儀表板負責人回覆驗收契約只讀候選 + AwoooP 審批佇列負責人回覆驗收只讀審查邊界 + AwoooP 租戶管理負責人回覆驗收租戶範圍 + AwoooP 執行監控負責人回覆驗收執行邊界 + AwoooP 執行詳情負責人回覆驗收詳情邊界 + AwoooP 審批決策負責人回覆驗收審批邊界 + IwoooS AwoooP 資安入口覆蓋狀態板 + IwoooS 階段式資安收斂節奏圖 + IwoooS 下一步人工收件作戰板 + IwoooS 人工回覆安全驗收閘道 + IwoooS 人工回覆審查結果分流 + IwoooS 人工決策準備佇列 + IwoooS 人工決策紀錄草稿防誤用 + IwoooS 人工決策正式紀錄負責人指派確認準備包 + IwoooS 人工決策正式紀錄負責人指派確認清單 + IwoooS 人工決策正式紀錄負責人指派確認結果分流 + IwoooS 人工決策正式紀錄負責人指派決策準備包 + IwoooS 人工決策正式紀錄負責人指派決策檢查清單 + IwoooS S4.9 負責人回覆封套欄位 + IwoooS S4.9 負責人回覆封套送件前檢查 + IwoooS S4.9 負責人回覆封套送件前結果分流 + IwoooS S4.9 負責人回覆送件請求草稿 + IwoooS S4.9 負責人回覆送件鏈路摘要 + IwoooS 低摩擦分階段收斂主控 + IwoooS 低摩擦下一步行動邊界 + IwoooS 64% 進度移動訊號驗收條 + IwoooS 第一個進度解鎖路徑 + IwoooS 第一解鎖證據包 + IwoooS 第一解鎖證據包預檢分流 + IwoooS 第一解鎖證據包補件路徑 + IwoooS 第一解鎖證據包補件送審前檢查 + IwoooS 第一解鎖證據包補件送審結果分流 + IwoooS 第一解鎖證據包 reviewer 指派準備包 + IwoooS 第一解鎖證據包 reviewer 指派前檢查 + IwoooS 第一解鎖證據包 reviewer 指派前檢查結果分流 + IwoooS 正式只讀 landing 與 Kali 112 只讀證據進度重估 | | 本階段追加補充 | IwoooS 目前具體工作地圖 + IwoooS 目前具體交付清單 + IwoooS 目前阻塞與解除條件 + IwoooS 三軸進度與全產品套用範圍 + IwoooS 全產品分階段套用台帳 + IwoooS 全產品 rollout 波次驗收門檻 + IwoooS 全產品 rollout 驗收結果分流 + IwoooS 全產品證據接線地圖 + IwoooS 全產品證據接線預檢 + IwoooS 全產品證據接線預檢結果分流 + IwoooS 全產品預檢補件回收台帳 + IwoooS 全產品補件重試門檻 + IwoooS 全產品重試結果分流 + IwoooS 全產品人工審查候選準備 + IwoooS 全產品人工審查候選預檢 + IwoooS 全產品人工審查候選預檢結果分流 + IwoooS 全產品人工審查候選預檢補件回收台帳 + IwoooS 全產品人工審查候選預檢補件重試門檻 + IwoooS 全產品只讀套用快照 + P2-145 owner response acceptance gate 正式驗證完成 | | P0 追加 | IwoooS P0 配置控管優先序前台正式驗證完成;Nginx public gateway、DNS / TLS / certbot、K8s / ArgoCD / production manifests、Workflow / runner / secret metadata、Public / admin / API runtime config、agent-bounty runtime / treasury 六類先列為即時風險配置;高價值配置 Gate 已補上 `k8s/nginx/**`、`scripts/ops/**/*cert*`、`scripts/ops/**/*tls*`,sample 從 `matched=0 / C0=0` 收斂到 `matched=3 / C0=2`;Gate 預設工作樹 preflight 已可讀取 staged / unstaged / untracked,本地 smoke 對臨時 `k8s/nginx/*` 檔命中 C0;Owner Packet snapshot 已同步為 `packets=3 / c0=2`,Coverage snapshot 已同步最新 patterns;IwoooS / AwoooP 前台 Owner Packet 摘要已正式驗證 `packet=3 / c0=2`,feature commit `e999c16b`、deploy marker `16c6b983`、Gitea code-review `2973` / CD `2972` success;IwoooS posture projection snapshot / schema / guard 已同步 `packet=3 / c0=2`,不再保留舊 `1 / 0` 口徑;高價值配置 Owner Packet 收件預檢已新增 `checks=9 / lanes=5 / required_fields=27 / blocked_requests=16`;高價值配置 Owner Request 草稿包已新增 `drafts=3 / handoff_fields=11 / forbidden_payloads=12 / sent=0`;Public Gateway live conf 匯出請求包已新增 `requests=3 / c0=2 / redaction_rules=8 / received=0`;Public Gateway redacted export 收件預檢已新增 `candidates=3 / c0=2 / checks=10 / rejection_guards=12 / received=0 / accepted=0`;Public Gateway rendered diff / nginx gate 草稿已新增 `candidates=3 / c0=2 / stages=7 / blocked=14 / rendered_diff=0 / runtime=0`;Public Gateway owner response acceptance 只讀帳本已新增 `candidates=3 / c0=2 / fields=33 / checks=22 / lanes=8 / blocked=28 / accepted=0 / runtime=0`,並補上手動 / 緊急 gateway 變更的 intent、approval / break-glass、route health、rollback validation 與 post-change monitoring 必填 ref;DNS / TLS / certbot Owner Confirmation Request 已新增 `requests=4 / c0=4 / fields=9 / questions=5 / guards=12 / received=0 / accepted=0`;K8s / ArgoCD manifest repo-only 清冊已新增 `files=49 / c0=36 / yaml=45 / kinds=20 / blocked=13 / runtime=0`;K8s / ArgoCD Owner Request Draft 已新增 `drafts=4 / c0=3 / fields=11 / sent=0 / runtime=0`;K8s / ArgoCD owner response acceptance 只讀帳本已新增 `candidates=4 / c0=3 / fields=11 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;K8s / ArgoCD GitOps 變更證據驗收已新增 `candidates=4 / c0=3 / write_capable=4 / evidence_fields=18 / checks=18 / lanes=8 / blocked=28 / accepted=0 / runtime=0`;CD / Runner / Secret 注入變更證據驗收已新增 `candidates=5 / c0=4 / write_capable=5 / workflow_files=33 / secret_names=42 / runner_labels=5 / evidence_fields=19 / checks=19 / lanes=8 / blocked=32 / accepted=0 / runtime=0`;Public / Admin / API runtime config 變更證據驗收已新增 `candidates=6 / c0=5 / write_capable=6 / source_refs=20 / evidence_fields=21 / checks=21 / lanes=8 / blocked=32 / accepted=0 / runtime=0`,並把 raw namespace、repo slug、內部狀態碼與內部協作內容外洩列為拒收 / 隔離;Frontend public sensitive surface guard 已新增 `files=225 / patterns=12 / allowlisted=2 / violations=0 / runtime=0`,讓 public runtime config 成熟度 `64% -> 66%`、高價值配置平均 `69% -> 70%`;Backup / Restore / Escrow owner response acceptance 只讀帳本已更新為 `candidates=38 / write_capable=27 / fields=33 / owner_fields=23 / reviewer_checks=22 / lanes=9 / blocked=31 / accepted=0 / runtime=0`;SSH / Firewall / Network Access owner response acceptance 只讀帳本已新增 `candidates=16 / write_capable=6 / fields=13 / checks=15 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;端口 / 防火牆變更證據驗收只讀帳本已新增 `candidates=14 / write_capable=6 / policy_or_exposure=5 / evidence_fields=16 / checks=16 / lanes=8 / blocked=24 / accepted=0 / runtime=0`;owner response / live evidence / runtime gate / action buttons 仍全部為 0 | | P0 agent-bounty 追加 | agent-bounty-protocol Owner Request Draft 已新增 `drafts=11 / control=4 / surface=7 / write_capable=8 / treasury=4 / mcp_a2a=5 / fields=22 / forbidden_inputs=25 / blocked=28 / sent=0 / runtime=0`;這是 repo / refs、deployment、data classification、MCP / A2A、cron / daemon、admin / treasury、webhook / traffic 的人工送件前草稿,不是 owner response、repo push、refs sync、workflow 修改、secret 收集、deploy、compose restart、DB migration、claim / submit、payout / withdrawal、cron / daemon、external send、host write 或 runtime gate | -| P1 追加 | Docker / systemd / Host Service Owner Request Draft 已新增 `drafts=9 / write_capable=3 / fields=12 / blocked=14 / sent=0 / runtime=0`;Docker / systemd / Host Service Owner Response Acceptance 已更新為 `candidates=9 / write_capable=3 / live_evidence_required=8 / fields=34 / owner_fields=18 / reviewer_checks=21 / lanes=8 / blocked=27 / accepted=0 / runtime=0`;Docker / systemd / Host Service Change Evidence Acceptance 已新增 `candidates=9 / write_capable=3 / live_evidence_required=8 / evidence_fields=45 / required_fields=25 / reviewer_checks=26 / lanes=10 / blocked=39 / accepted=0 / runtime=0`;AI provider / Model Routing Owner Response Acceptance 已新增 `candidates=8 / write_capable=5 / paid_provider=5 / data_egress=6 / fields=37 / owner_fields=24 / reviewer_checks=24 / lanes=10 / blocked=38 / accepted=0 / runtime=0`;SSH / Firewall / Network Access Owner Request Draft 已新增 `drafts=16 / write_capable=6 / fields=13 / blocked=16 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Request Draft 已新增 `drafts=38 / write_capable=27 / fields=14 / blocked=18 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Response Acceptance 已更新為 `candidates=38 / write_capable=27 / owner_fields=23 / reviewer_checks=22 / lanes=9 / blocked=31 / accepted=0 / runtime=0`;Monitoring / Alerting / Observability Owner Request Draft 已新增 `drafts=60 / write_capable=11 / fields=14 / blocked=24 / sent=0 / runtime=0`;Monitoring / Alerting / Observability Owner Response Acceptance 已更新為 `candidates=60 / write_capable=11 / live_evidence_required=60 / fields=38 / owner_fields=14 / reviewer_checks=23 / lanes=12 / blocked=34 / accepted=0 / runtime=0`,並補 incident context、receiver receipt、stale alert、silence / dedup、post-reload readback 與 false-green risk review;上述全部仍是人工送件前草稿或只讀 acceptance 帳本,不是 owner response、change evidence accepted、live evidence、provider switch、外部 provider call、付費呼叫、prompt send、reload、restart、backup、restore、Telegram send、alert smoke、host write 或 runtime gate | +| P1 追加 | Docker / systemd / Host Service Owner Request Draft 已新增 `drafts=9 / write_capable=3 / fields=12 / blocked=14 / sent=0 / runtime=0`;Docker / systemd / Host Service Owner Response Acceptance 已更新為 `candidates=9 / write_capable=3 / live_evidence_required=8 / fields=34 / owner_fields=18 / reviewer_checks=21 / lanes=8 / blocked=27 / accepted=0 / runtime=0`;Docker / systemd / Host Service Change Evidence Acceptance 已新增 `candidates=9 / write_capable=3 / live_evidence_required=8 / evidence_fields=45 / required_fields=25 / reviewer_checks=26 / lanes=10 / blocked=39 / accepted=0 / runtime=0`;Docker / systemd / Host Service Post-incident Readback Plan 已新增 `candidates=9 / write_capable=3 / live_evidence_required=8 / readback_fields=36 / required_fields=28 / reviewer_checks=28 / lanes=10 / blocked=41 / accepted=0 / runtime=0`;AI provider / Model Routing Owner Response Acceptance 已新增 `candidates=8 / write_capable=5 / paid_provider=5 / data_egress=6 / fields=37 / owner_fields=24 / reviewer_checks=24 / lanes=10 / blocked=38 / accepted=0 / runtime=0`;SSH / Firewall / Network Access Owner Request Draft 已新增 `drafts=16 / write_capable=6 / fields=13 / blocked=16 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Request Draft 已新增 `drafts=38 / write_capable=27 / fields=14 / blocked=18 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Response Acceptance 已更新為 `candidates=38 / write_capable=27 / owner_fields=23 / reviewer_checks=22 / lanes=9 / blocked=31 / accepted=0 / runtime=0`;Monitoring / Alerting / Observability Owner Request Draft 已新增 `drafts=60 / write_capable=11 / fields=14 / blocked=24 / sent=0 / runtime=0`;Monitoring / Alerting / Observability Owner Response Acceptance 已更新為 `candidates=60 / write_capable=11 / live_evidence_required=60 / fields=38 / owner_fields=14 / reviewer_checks=23 / lanes=12 / blocked=34 / accepted=0 / runtime=0`,並補 incident context、receiver receipt、stale alert、silence / dedup、post-reload readback 與 false-green risk review;上述全部仍是人工送件前草稿、只讀 acceptance 帳本或事故後回讀計畫,不是 owner response、change evidence accepted、live evidence、provider switch、外部 provider call、付費呼叫、prompt send、reload、restart、backup、restore、Telegram send、alert smoke、host write 或 runtime gate | | P2 供應鏈追加 | Package / Docker 供應鏈 repo-only baseline 已新增 `package_json=6 / pyproject=4 / requirements=2 / dockerfiles=2 / compose=6 / gaps=5 / runtime=0`;Package / Docker 供應鏈 owner policy gate 已新增 `requests=6 / c0=2 / fields=8 / checks=12 / blocked=20 / sent=0 / accepted=0 / runtime=0`;缺口為 Python lockfile 缺席、requirements 未 pin、Docker base image 未全數 digest pinning、Docker `COPY --from` 外部 image 未 digest pinning、compose image 未 digest pinning,以及 CVE / license / SBOM window 未定;目前尚未列入 36 個正式 AwoooP 消費 contract,後續若要前台消費需同步 manifest / readiness / route / rollup / dry-run / posture projection / guard count;本輪不 install、不 upgrade、不跑 CVE、不 pull / build / push image、不改 tag、不登入 registry、不部署 | | 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary | | P0 主控板 | `docs/workplans/2026-06-04-iwooos-security-governance-p0.md` | +## 0.00aaaaaaaa 2026-06-15 Docker / systemd / Host Service post-incident readback plan + +本輪把 Docker / systemd / Host Service 從變更證據驗收再補一層事故後回讀計畫:`host_service_post_incident_readback_plan_v1` 固定 `candidates=9`、`write_capable=3`、`live_evidence_required=8`、`readback_fields=36`、`required_readback_fields=28`、`reviewer_checks=28`、`outcome_lanes=10`、`blocked_actions=41`,並讓 `docker_compose_systemd_host_config` 只讀治理成熟度 `62% -> 64%`、高價值配置平均成熟度 `70% -> 71%`。新增要求包含 actor、boot / recovery window、before / after、Docker daemon、compose、systemd、failed unit、port binding、public / admin route、AI provider、monitoring、operator notification、cross-project sync、restoration evidence、post-check、recurrence guard 與 no-false-green attestation。 + +同步邊界:IwoooS headline 維持 `64%`,active runtime gate 維持 `0`;readback received / accepted、Docker daemon accepted、compose accepted、systemd accepted、route recovery accepted、monitoring accepted、cross-project sync accepted、recurrence guard accepted、runtime gate 與 action buttons 全部仍為 `0 / false`。本段只更新文件、snapshot、guard、投影契約與前端 marker,不 SSH、不讀 live host、不碰 Docker daemon、systemd、repair-bot、Ansible、route smoke、Nginx、firewall、iptables 或主機。 + ## 0.00aaaaaaa 2026-06-15 Docker / systemd / Host Service change evidence acceptance 本輪把 Docker / systemd / host service 從 owner response acceptance 再補一層事故 / 變更證據驗收只讀帳本:`host_service_change_evidence_acceptance_v1` 固定 `candidates=9`、`write_capable=3`、`live_evidence_required=8`、`change_evidence_fields=45`、`required_evidence_fields=25`、`reviewer_checks=26`、`outcome_lanes=10`、`blocked_actions=39`,並讓 `docker_compose_systemd_host_config` 只讀治理成熟度 `58% -> 62%`。新增要求包含重啟 actor、before / after service state、Docker daemon state、compose / systemd state、failed unit review、port binding、dependency impact、cold-start sequence、route recovery、operator notification、cross-project sync 與 no-false-green service health。 diff --git a/docs/security/high-value-config-control-coverage.snapshot.json b/docs/security/high-value-config-control-coverage.snapshot.json index c0ad1e01..14c60774 100644 --- a/docs/security/high-value-config-control-coverage.snapshot.json +++ b/docs/security/high-value-config-control-coverage.snapshot.json @@ -368,9 +368,9 @@ "action_buttons_allowed": false, "category_id": "docker_compose_systemd_host_config", "control_tier": "C1", - "coverage_percent": 62, - "coverage_status": "change_evidence_acceptance_ready_needs_host_service_owner_evidence", - "current_gap": "已固定 9 份 Docker / systemd / host service owner response acceptance candidate,並新增 host service change evidence acceptance;重啟 actor、before / after state、Docker daemon、compose / systemd state、failed unit、port binding、dependency、cold-start、route recovery、operator notice、cross-project sync 與 no-false-green 皆已納入只讀帳本;仍缺 owner response、live hash、change evidence、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。", + "coverage_percent": 64, + "coverage_status": "post_incident_readback_plan_ready_needs_host_service_owner_evidence", + "current_gap": "已固定 9 份 Docker / systemd / host service owner response acceptance candidate、change evidence acceptance 與 post-incident readback plan;重啟 actor、boot / recovery window、before / after state、Docker daemon、compose / systemd state、failed unit、port binding、dependency、public/admin route recovery、AI provider health、monitoring alert、operator notice、cross-project sync、restoration、recurrence guard 與 no-false-green 皆已納入只讀帳本;仍缺 owner response、live hash、事故回讀包、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。", "evidence_refs": [ "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md", "docs/security/HOST-SERVICE-CONFIG-INVENTORY.md", @@ -381,10 +381,12 @@ "docs/security/host-service-owner-response-acceptance.snapshot.json", "docs/security/HOST-SERVICE-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/host-service-change-evidence-acceptance.snapshot.json", + "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/host-service-post-incident-readback-plan.snapshot.json", "docs/security/DEV-HOSTS-112-111-168-OBSERVE-ONLY-MAPPING.md" ], "label": "Docker Compose / systemd / host service config", - "next_owner_action": "補 owner-provided live hash / disposition、change / incident ref、actor role / team、before / after state、Docker daemon state、compose / systemd state、failed unit review、port binding、服務依賴圖、cold-start sequence、route recovery、operator notification、cross-project sync、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。", + "next_owner_action": "補 host service 事故回讀包:owner-provided live hash / disposition、change / incident ref、actor role / team、boot time、restart / recovery window、before / after state、Docker daemon state、compose / systemd state、failed unit review、port binding、服務依賴圖、public/admin route recovery、AI provider health、monitoring alert、operator notification、cross-project sync、restoration evidence、recurrence guard、rollback owner、post-check plan 與 no-secret-value evidence。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -641,16 +643,9 @@ "websocket_route_change_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-06-15T19:40:00+08:00", - "git_commit": "3d0c3cc8", + "generated_at": "2026-06-15T20:32:00+08:00", + "git_commit": "c641d1b2", "lowest_coverage_categories": [ - { - "category_id": "docker_compose_systemd_host_config", - "coverage_percent": 62, - "current_gap": "已固定 9 份 Docker / systemd / host service owner response acceptance candidate,並新增 host service change evidence acceptance;重啟 actor、before / after state、Docker daemon、compose / systemd state、failed unit、port binding、dependency、cold-start、route recovery、operator notice、cross-project sync 與 no-false-green 皆已納入只讀帳本;仍缺 owner response、live hash、change evidence、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。", - "label": "Docker Compose / systemd / host service config", - "next_owner_action": "補 owner-provided live hash / disposition、change / incident ref、actor role / team、before / after state、Docker daemon state、compose / systemd state、failed unit review、port binding、服務依賴圖、cold-start sequence、route recovery、operator notification、cross-project sync、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。" - }, { "category_id": "k8s_production_gitops", "coverage_percent": 64, @@ -665,6 +660,13 @@ "label": "Backup / restore / escrow / retention", "next_owner_action": "補 restore drill approval package、freshness SLO、隔離 restore target、依賴圖、資料分級、offsite remote delete guard、credential recovery non-secret proof、retention runway、observer / stop condition、rollback owner、validation plan 與 no-secret-value evidence。" }, + { + "category_id": "docker_compose_systemd_host_config", + "coverage_percent": 64, + "current_gap": "已固定 9 份 Docker / systemd / host service owner response acceptance candidate、change evidence acceptance 與 post-incident readback plan;重啟 actor、boot / recovery window、before / after state、Docker daemon、compose / systemd state、failed unit、port binding、dependency、public/admin route recovery、AI provider health、monitoring alert、operator notice、cross-project sync、restoration、recurrence guard 與 no-false-green 皆已納入只讀帳本;仍缺 owner response、live hash、事故回讀包、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。", + "label": "Docker Compose / systemd / host service config", + "next_owner_action": "補 host service 事故回讀包:owner-provided live hash / disposition、change / incident ref、actor role / team、boot time、restart / recovery window、before / after state、Docker daemon state、compose / systemd state、failed unit review、port binding、服務依賴圖、public/admin route recovery、AI provider health、monitoring alert、operator notification、cross-project sync、restoration evidence、recurrence guard、rollback owner、post-check plan 與 no-secret-value evidence。" + }, { "category_id": "ssh_firewall_network_access", "coverage_percent": 64, @@ -698,14 +700,14 @@ "status": "coverage_matrix_ready", "summary": { "action_button_count": 0, - "average_coverage_percent": 70, + "average_coverage_percent": 71, "c0_category_count": 8, "c1_category_count": 4, "c2_category_count": 1, "c3_category_count": 1, "category_count": 14, "lowest_coverage_category_count": 4, - "needs_live_evidence_count": 10, + "needs_live_evidence_count": 9, "owner_response_accepted_count": 0, "owner_response_received_count": 0, "owner_response_required_count": 14, diff --git a/docs/security/host-service-post-incident-readback-plan.snapshot.json b/docs/security/host-service-post-incident-readback-plan.snapshot.json new file mode 100644 index 00000000..dcb12557 --- /dev/null +++ b/docs/security/host-service-post-incident-readback-plan.snapshot.json @@ -0,0 +1,2392 @@ +{ + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boundaries": { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "ansible_apply_authorized": false, + "docker_action_authorized": false, + "docker_compose_action_authorized": false, + "docker_kill_authorized": false, + "docker_restart_authorized": false, + "docker_start_authorized": false, + "live_host_read_authorized": false, + "nginx_reload_authorized": false, + "not_authorization": true, + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "raw_log_or_config_storage_allowed": false, + "repair_bot_execution_authorized": false, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "secret_value_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "systemctl_action_authorized": false, + "systemctl_restart_authorized": false + }, + "generated_at": "2026-06-15T20:30:00+08:00", + "git_commit": "c641d1b2", + "outcome_lanes": [ + { + "lane_id": "waiting_post_incident_readback", + "meaning": "尚未收到主機服務事故回讀包;所有 accepted / runtime count 維持 0。" + }, + { + "lane_id": "request_actor_supplement", + "meaning": "缺 actor / owner / decision 時要求補件。" + }, + { + "lane_id": "request_before_after_supplement", + "meaning": "缺 before / after、boot time、restart window 或 restoration evidence 時要求補件。" + }, + { + "lane_id": "request_service_state_supplement", + "meaning": "缺 Docker daemon、compose、systemd、failed unit、port binding 或 dependency 狀態時要求補件。" + }, + { + "lane_id": "request_impact_supplement", + "meaning": "缺 public/admin route、AI provider、monitoring、operator notification 或 cross-project sync 時要求補件。" + }, + { + "lane_id": "quarantine_raw_payload", + "meaning": "收到 secret、env dump、raw log、raw journal、raw compose 或未脫敏 host config 時只能隔離。" + }, + { + "lane_id": "reject_unattributed_restart", + "meaning": "無 actor、無 affected scope、無 rollback 或無 notification 的 restart / kill / compose action 不得驗收。" + }, + { + "lane_id": "ready_for_host_service_post_incident_review", + "meaning": "metadata 合格後,只能進 reviewer review。" + }, + { + "lane_id": "recurrence_guard_backfill_required", + "meaning": "需補防再發 guard、owner review、change freeze 或 automation block。" + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "即使 readback accepted,runtime gate 仍需獨立人工批准。" + } + ], + "readback_candidates": [ + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "docker_compose_source", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "local_dev_only", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "AWOOOI local development compose", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:local_dev_compose", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": false, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "web", + "api", + "postgres", + "redis" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:local_dev_compose", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "local_dev_compose", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "docker_compose_source", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "192.168.0.110", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "110 monitoring docker compose", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:monitoring_110_compose", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": true, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "cadvisor", + "prometheus", + "grafana", + "blackbox-exporter", + "alertmanager", + "github-exporter" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:monitoring_110_compose", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "monitoring_110_compose", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "docker_compose_source", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "192.168.0.188", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "188 database exporters compose", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:monitoring_exporters_188_compose", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": true, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "postgres-exporter", + "redis-exporter" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:monitoring_exporters_188_compose", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "monitoring_exporters_188_compose", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "docker_compose_reference", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "192.168.0.110", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "110 Sentry self-hosted reference compose", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:sentry_110_reference_compose", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": true, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "sentry-placeholder-reference" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:sentry_110_reference_compose", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "sentry_110_reference_compose", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "docker_compose_source", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "192.168.0.110", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "110 Langfuse compose", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:langfuse_110_compose", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": true, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "langfuse", + "langfuse-db" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:langfuse_110_compose", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "langfuse_110_compose", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "ansible_service_executor", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "multi_host", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "Ansible docker-compose-service role", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:ansible_docker_compose_service_role", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": true, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "docker compose up -d" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:ansible_docker_compose_service_role", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "ansible_docker_compose_service_role", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "host_repair_whitelist", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "192.168.0.110", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "110 repair-bot compose whitelist", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:repair_bot_110_whitelist", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": true, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "sentry", + "harbor", + "gitea", + "gitea-runner", + "langfuse", + "alertmanager", + "signoz" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:repair_bot_110_whitelist", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "repair_bot_110_whitelist", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "host_repair_whitelist", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "192.168.0.188", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "188 repair-bot compose/systemd whitelist", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:repair_bot_188_whitelist", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": true, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "openclaw", + "minio", + "signoz", + "redis", + "nginx", + "ollama" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:repair_bot_188_whitelist", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "repair_bot_188_whitelist", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "admin_route_recovery_accepted": false, + "admin_route_recovery_ref": null, + "after_service_state_ref": null, + "agent_provider_health_accepted": false, + "agent_provider_health_ref": null, + "ansible_apply_authorized": false, + "before_after_state_accepted": false, + "before_service_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "boot_time_ref": null, + "change_or_incident_ref": null, + "compose_stack_state_accepted": false, + "compose_stack_state_ref": null, + "config_kind": "backup_capture_contract", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "dependency_impact_accepted": false, + "dependency_impact_ref": null, + "docker_action_authorized": false, + "docker_daemon_state_accepted": false, + "docker_daemon_state_ref": null, + "expected_host_scope": "110_188_120_121_cluster", + "failed_unit_review_accepted": false, + "failed_unit_review_ref": null, + "followup_owner": "pending_post_incident_readback", + "label": "host config backup capture contract", + "live_host_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_accepted": false, + "monitoring_alert_ref": null, + "no_false_green_accepted": false, + "not_approval": true, + "operator_notification_accepted": false, + "operator_notification_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_supplement", + "request_before_after_supplement", + "request_service_state_supplement", + "request_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_restart", + "ready_for_host_service_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "port_binding_state_accepted": false, + "port_binding_state_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "public_route_recovery_accepted": false, + "public_route_recovery_ref": null, + "readback_candidate_id": "host_service_post_incident_readback:config_backup_host_capture", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "repair_bot_execution_authorized": false, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "requires_live_evidence": true, + "restart_or_recovery_window_ref": null, + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "boot_or_recovery_window_present", + "before_after_service_state_present", + "docker_daemon_state_present", + "compose_stack_state_present", + "systemd_unit_state_present", + "failed_unit_review_present", + "port_binding_state_present", + "dependency_impact_present", + "public_route_recovery_present", + "admin_route_recovery_present", + "agent_provider_health_present", + "monitoring_alert_ref_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "runner_repair_bot_contention_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_or_container", + "raw_log_config_absent", + "secret_or_key_value_absent", + "counts_transition_safe", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "rollback_owner_accepted": false, + "route_smoke_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_scope": [ + "systemd", + "docker", + "nginx", + "cron", + "k8s", + "host-configs" + ], + "source_change_evidence_candidate_id": "host_service_change_evidence:config_backup_host_capture", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "config_backup_host_capture", + "systemctl_action_authorized": false, + "systemd_unit_state_accepted": false, + "systemd_unit_state_ref": null, + "write_capable_surface": false + } + ], + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation" + ], + "reviewer_checks": [ + { + "check_id": "source_change_evidence_current", + "instruction": "來源 host service change evidence snapshot 必須是目前版本。" + }, + { + "check_id": "incident_ref_present", + "instruction": "必須有可追溯 change / incident ref。" + }, + { + "check_id": "actor_not_anonymous", + "instruction": "必須標示 actor role / team,不接受匿名 restart、kill、start、compose 或 daemon 操作。" + }, + { + "check_id": "boot_or_recovery_window_present", + "instruction": "boot time、restart window 或 recovery window 必須有脫敏 ref。" + }, + { + "check_id": "before_after_service_state_present", + "instruction": "必須有 before / after service state ref,不能只寫服務已恢復。" + }, + { + "check_id": "docker_daemon_state_present", + "instruction": "Docker daemon active、starting、failed、socket、contention 或 API reachable 狀態必須有摘要 ref。" + }, + { + "check_id": "compose_stack_state_present", + "instruction": "Compose stack / container state 只能收脫敏狀態摘要 ref,不保存 raw docker ps dump。" + }, + { + "check_id": "systemd_unit_state_present", + "instruction": "systemd failed unit、restart policy 或 degraded state 必須有摘要 ref。" + }, + { + "check_id": "failed_unit_review_present", + "instruction": "必須說明 failed unit 是否與事故、restart 或服務恢復相關。" + }, + { + "check_id": "port_binding_state_present", + "instruction": "必須確認 host port、container port、proxy、gateway 與 firewall 狀態是否一致。" + }, + { + "check_id": "dependency_impact_present", + "instruction": "必須列出上游、下游、DB、queue、registry、AI provider、public route 與 monitoring 影響。" + }, + { + "check_id": "public_route_recovery_present", + "instruction": "public route 受影響時需有恢復 ref;無影響也需明確不適用。" + }, + { + "check_id": "admin_route_recovery_present", + "instruction": "admin / internal operator route 受影響時需有恢復 ref;無影響也需明確不適用。" + }, + { + "check_id": "agent_provider_health_present", + "instruction": "Ollama、AI provider、agent route 或 webhook 受影響時需有健康 readback ref。" + }, + { + "check_id": "monitoring_alert_ref_present", + "instruction": "需列 monitoring / alert / dashboard / incident ref,不能只靠人工觀察。" + }, + { + "check_id": "operator_notification_present", + "instruction": "需提供已通知受影響產品、owner 或 Session 的脫敏 ref。" + }, + { + "check_id": "cross_project_sync_present", + "instruction": "若影響 AwoooP、IwoooS、agent-bounty、StockPlatform、公開網站或監控,需有跨專案同步 ref。" + }, + { + "check_id": "restoration_evidence_present", + "instruction": "已恢復事故需提供恢復時間與恢復證據;未恢復需提供 still-degraded ref。" + }, + { + "check_id": "postcheck_independent", + "instruction": "post-check 必須獨立於原操作人與 UI 卡片。" + }, + { + "check_id": "recurrence_guard_present", + "instruction": "必須提出防再發 guard、change freeze、owner review 或自動化阻擋。" + }, + { + "check_id": "runner_repair_bot_contention_present", + "instruction": "必須確認 runner、repair-bot、backup job、iptables / xtables 或 compose action 是否競爭。" + }, + { + "check_id": "maintenance_window_present", + "instruction": "後續任何 restart / repair / compose / systemd 操作都需維護窗口。" + }, + { + "check_id": "rollback_owner_present", + "instruction": "rollback owner 與 rollback plan 必須同時存在。" + }, + { + "check_id": "no_false_green_route_or_container", + "instruction": "不得只用 route 200、container up、Docker API 回應、dashboard up 或 service healthy 當成事故已驗收。" + }, + { + "check_id": "raw_log_config_absent", + "instruction": "不得保存 raw docker logs、raw journal、raw compose、raw systemd unit、env dump 或未脫敏 host config。" + }, + { + "check_id": "secret_or_key_value_absent", + "instruction": "不得包含 secret、SSH key、token、cookie、private key、hash 或 partial secret。" + }, + { + "check_id": "counts_transition_safe", + "instruction": "只有 reviewer record 能更新 accepted count,且不得同時開 runtime gate。" + }, + { + "check_id": "runtime_stays_zero", + "instruction": "readback plan 不得觸發任何 SSH、Docker、systemctl、repair-bot、Ansible、route smoke 或 production write。" + } + ], + "schema_version": "host_service_post_incident_readback_plan_v1", + "source_paths": [ + "docs/security/HOST-SERVICE-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/host-service-change-evidence-acceptance.snapshot.json", + "docs/security/HOST-SERVICE-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/host-service-owner-response-acceptance.snapshot.json" + ], + "source_schema_version": "host_service_change_evidence_acceptance_v1", + "source_status": "change_evidence_acceptance_ready_no_runtime_action", + "status": "post_incident_readback_plan_ready_no_runtime_action", + "summary": { + "action_button_count": 0, + "actor_attribution_accepted_count": 0, + "admin_route_recovery_accepted_count": 0, + "agent_provider_health_accepted_count": 0, + "before_after_state_accepted_count": 0, + "blocked_action_count": 41, + "compose_stack_state_accepted_count": 0, + "coverage_percent_after_readback_plan": 64, + "cross_project_sync_accepted_count": 0, + "cross_project_sync_required_candidate_count": 9, + "dependency_impact_accepted_count": 0, + "docker_daemon_state_accepted_count": 0, + "failed_unit_review_accepted_count": 0, + "live_evidence_required_readback_candidate_count": 8, + "monitoring_alert_accepted_count": 0, + "no_false_green_accepted_count": 0, + "no_false_green_required_candidate_count": 9, + "operator_notification_accepted_count": 0, + "outcome_lane_count": 10, + "port_binding_state_accepted_count": 0, + "post_incident_readback_accepted_count": 0, + "post_incident_readback_received_count": 0, + "postcheck_readback_accepted_count": 0, + "public_route_recovery_accepted_count": 0, + "readback_candidate_count": 9, + "readback_field_count": 36, + "recovery_health_impact_review_required_candidate_count": 9, + "recurrence_guard_accepted_count": 0, + "required_readback_field_count": 28, + "restoration_evidence_accepted_count": 0, + "reviewer_check_count": 28, + "runtime_gate_count": 0, + "systemd_unit_state_accepted_count": 0, + "write_capable_readback_candidate_count": 3 + } +} diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json index 228c6ad4..de329c70 100644 --- a/docs/security/iwooos-posture-projection.snapshot.json +++ b/docs/security/iwooos-posture-projection.snapshot.json @@ -8428,7 +8428,9 @@ "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/ai-provider-owner-response-acceptance.snapshot.json", "docs/security/ssh-network-post-incident-readback-plan.snapshot.json", - "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md" + "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/host-service-post-incident-readback-plan.snapshot.json", + "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md" ], "status": "draft", "summary": { @@ -8620,14 +8622,14 @@ "global_security_mesh_matrix_read_only_count": 9, "global_security_mesh_matrix_runtime_gate_count": 0, "high_value_config_control_coverage_action_button_count": 0, - "high_value_config_control_coverage_average_percent": 70, + "high_value_config_control_coverage_average_percent": 71, "high_value_config_control_coverage_c0_category_count": 8, "high_value_config_control_coverage_c1_category_count": 4, "high_value_config_control_coverage_category_count": 14, "high_value_config_control_coverage_first_layer": true, "high_value_config_control_coverage_item_count": 4, "high_value_config_control_coverage_lowest_category_count": 4, - "high_value_config_control_coverage_needs_live_evidence_count": 10, + "high_value_config_control_coverage_needs_live_evidence_count": 9, "high_value_config_control_coverage_owner_response_accepted_count": 0, "high_value_config_control_coverage_owner_response_received_count": 0, "high_value_config_control_coverage_owner_response_required_count": 14, @@ -9090,7 +9092,42 @@ "ssh_network_post_incident_readback_plan_runtime_gate_count": 0, "ssh_network_post_incident_readback_plan_action_button_count": 0, "ssh_network_post_incident_readback_plan_coverage_percent_after_readback_plan": 64, - "ssh_firewall_network_access_coverage_percent": 64 + "ssh_firewall_network_access_coverage_percent": 64, + "host_service_post_incident_readback_plan_first_layer": true, + "host_service_post_incident_readback_plan_candidate_count": 9, + "host_service_post_incident_readback_plan_write_capable_candidate_count": 3, + "host_service_post_incident_readback_plan_live_evidence_required_candidate_count": 8, + "host_service_post_incident_readback_plan_recovery_health_impact_review_required_candidate_count": 9, + "host_service_post_incident_readback_plan_cross_project_sync_required_candidate_count": 9, + "host_service_post_incident_readback_plan_no_false_green_required_candidate_count": 9, + "host_service_post_incident_readback_plan_readback_field_count": 36, + "host_service_post_incident_readback_plan_required_readback_field_count": 28, + "host_service_post_incident_readback_plan_reviewer_check_count": 28, + "host_service_post_incident_readback_plan_outcome_lane_count": 10, + "host_service_post_incident_readback_plan_blocked_action_count": 41, + "host_service_post_incident_readback_plan_post_incident_readback_received_count": 0, + "host_service_post_incident_readback_plan_post_incident_readback_accepted_count": 0, + "host_service_post_incident_readback_plan_actor_attribution_accepted_count": 0, + "host_service_post_incident_readback_plan_before_after_state_accepted_count": 0, + "host_service_post_incident_readback_plan_docker_daemon_state_accepted_count": 0, + "host_service_post_incident_readback_plan_compose_stack_state_accepted_count": 0, + "host_service_post_incident_readback_plan_systemd_unit_state_accepted_count": 0, + "host_service_post_incident_readback_plan_failed_unit_review_accepted_count": 0, + "host_service_post_incident_readback_plan_port_binding_state_accepted_count": 0, + "host_service_post_incident_readback_plan_public_route_recovery_accepted_count": 0, + "host_service_post_incident_readback_plan_admin_route_recovery_accepted_count": 0, + "host_service_post_incident_readback_plan_agent_provider_health_accepted_count": 0, + "host_service_post_incident_readback_plan_monitoring_alert_accepted_count": 0, + "host_service_post_incident_readback_plan_operator_notification_accepted_count": 0, + "host_service_post_incident_readback_plan_cross_project_sync_accepted_count": 0, + "host_service_post_incident_readback_plan_restoration_evidence_accepted_count": 0, + "host_service_post_incident_readback_plan_postcheck_readback_accepted_count": 0, + "host_service_post_incident_readback_plan_recurrence_guard_accepted_count": 0, + "host_service_post_incident_readback_plan_no_false_green_accepted_count": 0, + "host_service_post_incident_readback_plan_runtime_gate_count": 0, + "host_service_post_incident_readback_plan_action_button_count": 0, + "host_service_post_incident_readback_plan_coverage_percent_after_readback_plan": 64, + "docker_compose_systemd_host_config_coverage_percent": 64 }, "topology_atlas_lenses": [ { diff --git a/scripts/security/high-value-config-control-coverage.py b/scripts/security/high-value-config-control-coverage.py index 9cb7003e..de592220 100644 --- a/scripts/security/high-value-config-control-coverage.py +++ b/scripts/security/high-value-config-control-coverage.py @@ -157,8 +157,8 @@ CONTROL_STATUS_BY_CATEGORY = { "next_owner_action": "補 Prometheus / Alertmanager / Grafana / SigNoz / Sentry / Langfuse / Telegram owner、live drift evidence、reload window、receiver owner、receipt proof、stale alert review、silence / dedup review、route smoke plan、noise budget、rollback owner 與 no-secret-value evidence。", }, "docker_compose_systemd_host_config": { - "coverage_status": "change_evidence_acceptance_ready_needs_host_service_owner_evidence", - "coverage_percent": 62, + "coverage_status": "post_incident_readback_plan_ready_needs_host_service_owner_evidence", + "coverage_percent": 64, "evidence_refs": [ "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md", "docs/security/HOST-SERVICE-CONFIG-INVENTORY.md", @@ -169,10 +169,12 @@ CONTROL_STATUS_BY_CATEGORY = { "docs/security/host-service-owner-response-acceptance.snapshot.json", "docs/security/HOST-SERVICE-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/host-service-change-evidence-acceptance.snapshot.json", + "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/host-service-post-incident-readback-plan.snapshot.json", "docs/security/DEV-HOSTS-112-111-168-OBSERVE-ONLY-MAPPING.md", ], - "current_gap": "已固定 9 份 Docker / systemd / host service owner response acceptance candidate,並新增 host service change evidence acceptance;重啟 actor、before / after state、Docker daemon、compose / systemd state、failed unit、port binding、dependency、cold-start、route recovery、operator notice、cross-project sync 與 no-false-green 皆已納入只讀帳本;仍缺 owner response、live hash、change evidence、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。", - "next_owner_action": "補 owner-provided live hash / disposition、change / incident ref、actor role / team、before / after state、Docker daemon state、compose / systemd state、failed unit review、port binding、服務依賴圖、cold-start sequence、route recovery、operator notification、cross-project sync、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。", + "current_gap": "已固定 9 份 Docker / systemd / host service owner response acceptance candidate、change evidence acceptance 與 post-incident readback plan;重啟 actor、boot / recovery window、before / after state、Docker daemon、compose / systemd state、failed unit、port binding、dependency、public/admin route recovery、AI provider health、monitoring alert、operator notice、cross-project sync、restoration、recurrence guard 與 no-false-green 皆已納入只讀帳本;仍缺 owner response、live hash、事故回讀包、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。", + "next_owner_action": "補 host service 事故回讀包:owner-provided live hash / disposition、change / incident ref、actor role / team、boot time、restart / recovery window、before / after state、Docker daemon state、compose / systemd state、failed unit review、port binding、服務依賴圖、public/admin route recovery、AI provider health、monitoring alert、operator notification、cross-project sync、restoration evidence、recurrence guard、rollback owner、post-check plan 與 no-secret-value evidence。", }, "ssh_firewall_network_access": { "coverage_status": "post_incident_readback_plan_ready_needs_network_owner_evidence", diff --git a/scripts/security/host-service-post-incident-readback-plan.py b/scripts/security/host-service-post-incident-readback-plan.py new file mode 100644 index 00000000..263ff9c0 --- /dev/null +++ b/scripts/security/host-service-post-incident-readback-plan.py @@ -0,0 +1,410 @@ +#!/usr/bin/env python3 +""" +IwoooS Docker / systemd / host service post-incident readback 只讀計畫產生器。 + +本工具讀取 host service change evidence acceptance snapshot,建立事故後回讀 +計畫:誰動了 Docker / systemd / compose / repair-bot、何時動、改前改後狀態、 +哪些 public / admin route、AI provider、monitoring 與產品受影響、如何恢復、 +如何防再發。它不 SSH、不讀 live host、不執行 docker / systemctl、不呼叫 +repair-bot、不跑 Ansible、不做 route smoke、不保存 raw log / raw config, +也不把「服務變綠」誤判成 runtime authorization。 +""" + +from __future__ import annotations + +import argparse +import json +import subprocess +import sys +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any + + +TAIPEI = timezone(timedelta(hours=8)) + +READBACK_FIELDS = [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "label", + "expected_host_scope", + "config_kind", + "service_scope", + "control_tier", + "write_capable_surface", + "requires_live_evidence", + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "reviewer_outcome", + "followup_owner", + "not_approval", +] + +REQUIRED_READBACK_FIELDS = [ + "change_or_incident_ref", + "actor_attribution_ref", + "boot_time_ref", + "restart_or_recovery_window_ref", + "before_service_state_ref", + "after_service_state_ref", + "docker_daemon_state_ref", + "compose_stack_state_ref", + "systemd_unit_state_ref", + "failed_unit_review_ref", + "port_binding_state_ref", + "dependency_impact_ref", + "public_route_recovery_ref", + "admin_route_recovery_ref", + "agent_provider_health_ref", + "monitoring_alert_ref", + "operator_notification_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "postcheck_readback_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_log_or_config_attestation", + "no_false_green_attestation", +] + +REVIEWER_CHECKS = [ + {"check_id": "source_change_evidence_current", "instruction": "來源 host service change evidence snapshot 必須是目前版本。"}, + {"check_id": "incident_ref_present", "instruction": "必須有可追溯 change / incident ref。"}, + {"check_id": "actor_not_anonymous", "instruction": "必須標示 actor role / team,不接受匿名 restart、kill、start、compose 或 daemon 操作。"}, + {"check_id": "boot_or_recovery_window_present", "instruction": "boot time、restart window 或 recovery window 必須有脫敏 ref。"}, + {"check_id": "before_after_service_state_present", "instruction": "必須有 before / after service state ref,不能只寫服務已恢復。"}, + {"check_id": "docker_daemon_state_present", "instruction": "Docker daemon active、starting、failed、socket、contention 或 API reachable 狀態必須有摘要 ref。"}, + {"check_id": "compose_stack_state_present", "instruction": "Compose stack / container state 只能收脫敏狀態摘要 ref,不保存 raw docker ps dump。"}, + {"check_id": "systemd_unit_state_present", "instruction": "systemd failed unit、restart policy 或 degraded state 必須有摘要 ref。"}, + {"check_id": "failed_unit_review_present", "instruction": "必須說明 failed unit 是否與事故、restart 或服務恢復相關。"}, + {"check_id": "port_binding_state_present", "instruction": "必須確認 host port、container port、proxy、gateway 與 firewall 狀態是否一致。"}, + {"check_id": "dependency_impact_present", "instruction": "必須列出上游、下游、DB、queue、registry、AI provider、public route 與 monitoring 影響。"}, + {"check_id": "public_route_recovery_present", "instruction": "public route 受影響時需有恢復 ref;無影響也需明確不適用。"}, + {"check_id": "admin_route_recovery_present", "instruction": "admin / internal operator route 受影響時需有恢復 ref;無影響也需明確不適用。"}, + {"check_id": "agent_provider_health_present", "instruction": "Ollama、AI provider、agent route 或 webhook 受影響時需有健康 readback ref。"}, + {"check_id": "monitoring_alert_ref_present", "instruction": "需列 monitoring / alert / dashboard / incident ref,不能只靠人工觀察。"}, + {"check_id": "operator_notification_present", "instruction": "需提供已通知受影響產品、owner 或 Session 的脫敏 ref。"}, + {"check_id": "cross_project_sync_present", "instruction": "若影響 AwoooP、IwoooS、agent-bounty、StockPlatform、公開網站或監控,需有跨專案同步 ref。"}, + {"check_id": "restoration_evidence_present", "instruction": "已恢復事故需提供恢復時間與恢復證據;未恢復需提供 still-degraded ref。"}, + {"check_id": "postcheck_independent", "instruction": "post-check 必須獨立於原操作人與 UI 卡片。"}, + {"check_id": "recurrence_guard_present", "instruction": "必須提出防再發 guard、change freeze、owner review 或自動化阻擋。"}, + {"check_id": "runner_repair_bot_contention_present", "instruction": "必須確認 runner、repair-bot、backup job、iptables / xtables 或 compose action 是否競爭。"}, + {"check_id": "maintenance_window_present", "instruction": "後續任何 restart / repair / compose / systemd 操作都需維護窗口。"}, + {"check_id": "rollback_owner_present", "instruction": "rollback owner 與 rollback plan 必須同時存在。"}, + {"check_id": "no_false_green_route_or_container", "instruction": "不得只用 route 200、container up、Docker API 回應、dashboard up 或 service healthy 當成事故已驗收。"}, + {"check_id": "raw_log_config_absent", "instruction": "不得保存 raw docker logs、raw journal、raw compose、raw systemd unit、env dump 或未脫敏 host config。"}, + {"check_id": "secret_or_key_value_absent", "instruction": "不得包含 secret、SSH key、token、cookie、private key、hash 或 partial secret。"}, + {"check_id": "counts_transition_safe", "instruction": "只有 reviewer record 能更新 accepted count,且不得同時開 runtime gate。"}, + {"check_id": "runtime_stays_zero", "instruction": "readback plan 不得觸發任何 SSH、Docker、systemctl、repair-bot、Ansible、route smoke 或 production write。"}, +] + +OUTCOME_LANES = [ + {"lane_id": "waiting_post_incident_readback", "meaning": "尚未收到主機服務事故回讀包;所有 accepted / runtime count 維持 0。"}, + {"lane_id": "request_actor_supplement", "meaning": "缺 actor / owner / decision 時要求補件。"}, + {"lane_id": "request_before_after_supplement", "meaning": "缺 before / after、boot time、restart window 或 restoration evidence 時要求補件。"}, + {"lane_id": "request_service_state_supplement", "meaning": "缺 Docker daemon、compose、systemd、failed unit、port binding 或 dependency 狀態時要求補件。"}, + {"lane_id": "request_impact_supplement", "meaning": "缺 public/admin route、AI provider、monitoring、operator notification 或 cross-project sync 時要求補件。"}, + {"lane_id": "quarantine_raw_payload", "meaning": "收到 secret、env dump、raw log、raw journal、raw compose 或未脫敏 host config 時只能隔離。"}, + {"lane_id": "reject_unattributed_restart", "meaning": "無 actor、無 affected scope、無 rollback 或無 notification 的 restart / kill / compose action 不得驗收。"}, + {"lane_id": "ready_for_host_service_post_incident_review", "meaning": "metadata 合格後,只能進 reviewer review。"}, + {"lane_id": "recurrence_guard_backfill_required", "meaning": "需補防再發 guard、owner review、change freeze 或 automation block。"}, + {"lane_id": "waiting_runtime_gate", "meaning": "即使 readback accepted,runtime gate 仍需獨立人工批准。"}, +] + +BLOCKED_ACTIONS = [ + "ssh_read", + "ssh_write", + "live_host_read", + "docker_ps_live_read", + "docker_restart", + "docker_kill", + "docker_start", + "docker_compose_up", + "docker_compose_down", + "docker_compose_pull", + "systemctl_restart", + "systemctl_reload", + "systemctl_kill", + "systemctl_start", + "repair_bot_execute", + "ansible_apply", + "sudo_action", + "host_file_write", + "firewall_change", + "port_change", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "active_scan", + "secret_value_collection", + "raw_live_config_storage", + "raw_docker_log_storage", + "raw_journal_storage", + "raw_env_dump_storage", + "accept_restart_without_actor", + "accept_recovery_without_before_after", + "accept_service_healthy_as_config_accepted", + "accept_route_200_as_all_green", + "accept_container_up_as_all_green", + "skip_dependency_map_review", + "skip_port_binding_review", + "hide_daemon_runner_contention", + "mark_readback_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write", +] + + +def git_short_sha(root: Path) -> str: + try: + result = subprocess.run( + ["git", "rev-parse", "--short", "HEAD"], + cwd=root, + check=True, + capture_output=True, + text=True, + ) + return result.stdout.strip() + except Exception: + return "unknown" + + +def load_json(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def build_candidate(source: dict[str, Any]) -> dict[str, Any]: + surface_id = source["surface_id"] + return { + "readback_candidate_id": f"host_service_post_incident_readback:{surface_id}", + "status": "waiting_post_incident_readback", + "source_change_evidence_candidate_id": source["change_evidence_candidate_id"], + "surface_id": surface_id, + "label": source["label"], + "expected_host_scope": source["expected_host_scope"], + "config_kind": source["config_kind"], + "service_scope": source["service_scope"], + "control_tier": source["control_tier"], + "write_capable_surface": source["write_capable_surface"], + "requires_live_evidence": source["requires_live_evidence"], + "change_or_incident_ref": None, + "actor_attribution_ref": None, + "boot_time_ref": None, + "restart_or_recovery_window_ref": None, + "before_service_state_ref": None, + "after_service_state_ref": None, + "docker_daemon_state_ref": None, + "compose_stack_state_ref": None, + "systemd_unit_state_ref": None, + "failed_unit_review_ref": None, + "port_binding_state_ref": None, + "dependency_impact_ref": None, + "public_route_recovery_ref": None, + "admin_route_recovery_ref": None, + "agent_provider_health_ref": None, + "monitoring_alert_ref": None, + "operator_notification_ref": None, + "cross_project_sync_ref": None, + "restoration_evidence_ref": None, + "postcheck_readback_ref": None, + "recurrence_guard_ref": None, + "maintenance_window": "pending_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "reviewer_outcome": "waiting_post_incident_readback", + "followup_owner": "pending_post_incident_readback", + "readback_fields": READBACK_FIELDS, + "required_readback_fields": REQUIRED_READBACK_FIELDS, + "reviewer_checks": [item["check_id"] for item in REVIEWER_CHECKS], + "outcome_lanes": [item["lane_id"] for item in OUTCOME_LANES], + "blocked_actions": BLOCKED_ACTIONS, + "not_approval": True, + "post_incident_readback_received": False, + "post_incident_readback_accepted": False, + "actor_attribution_accepted": False, + "before_after_state_accepted": False, + "docker_daemon_state_accepted": False, + "compose_stack_state_accepted": False, + "systemd_unit_state_accepted": False, + "failed_unit_review_accepted": False, + "port_binding_state_accepted": False, + "dependency_impact_accepted": False, + "public_route_recovery_accepted": False, + "admin_route_recovery_accepted": False, + "agent_provider_health_accepted": False, + "monitoring_alert_accepted": False, + "operator_notification_accepted": False, + "cross_project_sync_accepted": False, + "restoration_evidence_accepted": False, + "postcheck_readback_accepted": False, + "recurrence_guard_accepted": False, + "maintenance_window_accepted": False, + "rollback_owner_accepted": False, + "no_false_green_accepted": False, + "ssh_read_authorized": False, + "ssh_write_authorized": False, + "live_host_read_authorized": False, + "docker_action_authorized": False, + "systemctl_action_authorized": False, + "repair_bot_execution_authorized": False, + "ansible_apply_authorized": False, + "route_smoke_authorized": False, + "secret_value_collection_allowed": False, + "active_scan_authorized": False, + "runtime_gate": False, + "action_buttons_allowed": False, + "production_write_authorized": False, + } + + +def build_report(root: Path, source_report: dict[str, Any], generated_at: str | None) -> dict[str, Any]: + report_time = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds") + source_candidates = source_report.get("change_evidence_candidates", []) + readback_candidates = [build_candidate(item) for item in source_candidates] + write_capable = [item for item in readback_candidates if item["write_capable_surface"]] + live_required = [item for item in readback_candidates if item["requires_live_evidence"]] + + return { + "schema_version": "host_service_post_incident_readback_plan_v1", + "generated_at": report_time, + "git_commit": git_short_sha(root), + "status": "post_incident_readback_plan_ready_no_runtime_action", + "source_schema_version": source_report.get("schema_version"), + "source_status": source_report.get("status"), + "source_paths": [ + "docs/security/HOST-SERVICE-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/host-service-change-evidence-acceptance.snapshot.json", + "docs/security/HOST-SERVICE-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/host-service-owner-response-acceptance.snapshot.json", + ], + "summary": { + "readback_candidate_count": len(readback_candidates), + "write_capable_readback_candidate_count": len(write_capable), + "live_evidence_required_readback_candidate_count": len(live_required), + "recovery_health_impact_review_required_candidate_count": len(readback_candidates), + "cross_project_sync_required_candidate_count": len(readback_candidates), + "no_false_green_required_candidate_count": len(readback_candidates), + "readback_field_count": len(READBACK_FIELDS), + "required_readback_field_count": len(REQUIRED_READBACK_FIELDS), + "reviewer_check_count": len(REVIEWER_CHECKS), + "outcome_lane_count": len(OUTCOME_LANES), + "blocked_action_count": len(BLOCKED_ACTIONS), + "post_incident_readback_received_count": 0, + "post_incident_readback_accepted_count": 0, + "actor_attribution_accepted_count": 0, + "before_after_state_accepted_count": 0, + "docker_daemon_state_accepted_count": 0, + "compose_stack_state_accepted_count": 0, + "systemd_unit_state_accepted_count": 0, + "failed_unit_review_accepted_count": 0, + "port_binding_state_accepted_count": 0, + "dependency_impact_accepted_count": 0, + "public_route_recovery_accepted_count": 0, + "admin_route_recovery_accepted_count": 0, + "agent_provider_health_accepted_count": 0, + "monitoring_alert_accepted_count": 0, + "operator_notification_accepted_count": 0, + "cross_project_sync_accepted_count": 0, + "restoration_evidence_accepted_count": 0, + "postcheck_readback_accepted_count": 0, + "recurrence_guard_accepted_count": 0, + "no_false_green_accepted_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "coverage_percent_after_readback_plan": 64, + }, + "required_readback_fields": REQUIRED_READBACK_FIELDS, + "reviewer_checks": REVIEWER_CHECKS, + "outcome_lanes": OUTCOME_LANES, + "blocked_actions": BLOCKED_ACTIONS, + "readback_candidates": readback_candidates, + "boundaries": { + "not_authorization": True, + "ssh_read_authorized": False, + "ssh_write_authorized": False, + "live_host_read_authorized": False, + "docker_action_authorized": False, + "docker_restart_authorized": False, + "docker_kill_authorized": False, + "docker_start_authorized": False, + "docker_compose_action_authorized": False, + "systemctl_action_authorized": False, + "systemctl_restart_authorized": False, + "repair_bot_execution_authorized": False, + "ansible_apply_authorized": False, + "route_smoke_authorized": False, + "public_gateway_reload_authorized": False, + "nginx_reload_authorized": False, + "active_scan_authorized": False, + "secret_value_collection_allowed": False, + "raw_log_or_config_storage_allowed": False, + "runtime_execution_authorized": False, + "production_write_authorized": False, + "action_buttons_allowed": False, + }, + } + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--root", default=".") + parser.add_argument( + "--source-change-evidence-report", + default="docs/security/host-service-change-evidence-acceptance.snapshot.json", + ) + parser.add_argument( + "--output", + default="docs/security/host-service-post-incident-readback-plan.snapshot.json", + ) + parser.add_argument("--generated-at") + args = parser.parse_args() + + root = Path(args.root).resolve() + source_report = load_json(root / args.source_change_evidence_report) + report = build_report(root, source_report, args.generated_at) + payload = json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + + output_path = root / args.output + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(payload + "\n", encoding="utf-8") + + summary = report["summary"] + print( + "HOST_SERVICE_POST_INCIDENT_READBACK_PLAN_OK " + f"candidates={summary['readback_candidate_count']} " + f"checks={summary['reviewer_check_count']} " + f"lanes={summary['outcome_lane_count']} " + f"accepted={summary['post_incident_readback_accepted_count']} " + f"runtime_gate={summary['runtime_gate_count']}" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/security/iwooos-config-control-guard.py b/scripts/security/iwooos-config-control-guard.py index bd51afaf..8f87a4d0 100644 --- a/scripts/security/iwooos-config-control-guard.py +++ b/scripts/security/iwooos-config-control-guard.py @@ -26,7 +26,7 @@ EXPECTED_CATEGORIES = { "backup_restore_credential": 64, "agent_bounty_protocol_runtime": 68, "monitoring_alerting_observability": 68, - "docker_compose_systemd_host_config": 62, + "docker_compose_systemd_host_config": 64, "ssh_firewall_network_access": 64, "ai_provider_model_routing": 64, "product_surface_runtime_routes": 72, @@ -53,6 +53,7 @@ REQUIRED_CONTROL_DOCS = [ "docs/security/DOMAIN-TLS-CERTBOT-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/HOST-SERVICE-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/HOST-SERVICE-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md", "docs/security/SSH-NETWORK-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md", @@ -223,6 +224,54 @@ ARTIFACT_SPECS = [ "runtime_gate_count": 0, }, }, + { + "label": "host service post incident readback plan", + "path": "docs/security/host-service-post-incident-readback-plan.snapshot.json", + "schema": "host_service_post_incident_readback_plan_v1", + "status": "post_incident_readback_plan_ready_no_runtime_action", + "list_counts": { + "readback_candidates": 9, + "blocked_actions": 41, + "reviewer_checks": 28, + "outcome_lanes": 10, + "required_readback_fields": 28, + }, + "summary_counts": { + "readback_candidate_count": 9, + "write_capable_readback_candidate_count": 3, + "live_evidence_required_readback_candidate_count": 8, + "recovery_health_impact_review_required_candidate_count": 9, + "cross_project_sync_required_candidate_count": 9, + "no_false_green_required_candidate_count": 9, + "readback_field_count": 36, + "required_readback_field_count": 28, + "reviewer_check_count": 28, + "outcome_lane_count": 10, + "blocked_action_count": 41, + "post_incident_readback_received_count": 0, + "post_incident_readback_accepted_count": 0, + "actor_attribution_accepted_count": 0, + "before_after_state_accepted_count": 0, + "docker_daemon_state_accepted_count": 0, + "compose_stack_state_accepted_count": 0, + "systemd_unit_state_accepted_count": 0, + "failed_unit_review_accepted_count": 0, + "port_binding_state_accepted_count": 0, + "public_route_recovery_accepted_count": 0, + "admin_route_recovery_accepted_count": 0, + "agent_provider_health_accepted_count": 0, + "monitoring_alert_accepted_count": 0, + "operator_notification_accepted_count": 0, + "cross_project_sync_accepted_count": 0, + "restoration_evidence_accepted_count": 0, + "postcheck_readback_accepted_count": 0, + "recurrence_guard_accepted_count": 0, + "no_false_green_accepted_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "coverage_percent_after_readback_plan": 64, + }, + }, { "label": "ssh network owner response acceptance", "path": "docs/security/ssh-network-owner-response-acceptance.snapshot.json", diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 36724022..2db643c8 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -153,6 +153,9 @@ def validate(root: Path) -> None: host_service_change_evidence_acceptance = load_json( security_dir / "host-service-change-evidence-acceptance.snapshot.json" ) + host_service_post_incident_readback_plan = load_json( + security_dir / "host-service-post-incident-readback-plan.snapshot.json" + ) ssh_network_access_inventory = load_json(security_dir / "ssh-network-access-inventory.snapshot.json") ssh_network_owner_request_draft = load_json( security_dir / "ssh-network-owner-request-draft.snapshot.json" @@ -2756,12 +2759,12 @@ def validate(root: Path) -> None: assert_equal( "high_value_config_coverage.summary.average_coverage_percent", high_value_config_coverage["summary"]["average_coverage_percent"], - 70, + 71, ) assert_equal( "high_value_config_coverage.summary.needs_live_evidence_count", high_value_config_coverage["summary"]["needs_live_evidence_count"], - 10, + 9, ) for key in [ "owner_response_received_count", @@ -3178,12 +3181,12 @@ def validate(root: Path) -> None: assert_equal( "high_value_config_coverage.coverage_categories.docker.coverage_percent", docker_systemd_category["coverage_percent"], - 62, + 64, ) assert_equal( "high_value_config_coverage.coverage_categories.docker.coverage_status", docker_systemd_category["coverage_status"], - "change_evidence_acceptance_ready_needs_host_service_owner_evidence", + "post_incident_readback_plan_ready_needs_host_service_owner_evidence", ) for evidence_ref in [ "docs/security/HOST-SERVICE-CONFIG-INVENTORY.md", @@ -3194,6 +3197,8 @@ def validate(root: Path) -> None: "docs/security/host-service-owner-response-acceptance.snapshot.json", "docs/security/HOST-SERVICE-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/host-service-change-evidence-acceptance.snapshot.json", + "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/host-service-post-incident-readback-plan.snapshot.json", ]: assert_contains( "high_value_config_coverage.coverage_categories.docker.evidence_refs", @@ -3928,6 +3933,155 @@ def validate(root: Path) -> None: f"host_service_change_evidence_acceptance.{item['change_evidence_candidate_id']}.{false_key}", item[false_key], ) + assert_equal( + "host_service_post_incident_readback_plan.schema", + host_service_post_incident_readback_plan["schema_version"], + "host_service_post_incident_readback_plan_v1", + ) + assert_equal( + "host_service_post_incident_readback_plan.status", + host_service_post_incident_readback_plan["status"], + "post_incident_readback_plan_ready_no_runtime_action", + ) + assert_equal( + "host_service_post_incident_readback_plan.source_schema_version", + host_service_post_incident_readback_plan["source_schema_version"], + "host_service_change_evidence_acceptance_v1", + ) + expected_host_service_post_incident_summary = { + "readback_candidate_count": 9, + "write_capable_readback_candidate_count": 3, + "live_evidence_required_readback_candidate_count": 8, + "recovery_health_impact_review_required_candidate_count": 9, + "cross_project_sync_required_candidate_count": 9, + "no_false_green_required_candidate_count": 9, + "readback_field_count": 36, + "required_readback_field_count": 28, + "reviewer_check_count": 28, + "outcome_lane_count": 10, + "blocked_action_count": 41, + "post_incident_readback_received_count": 0, + "post_incident_readback_accepted_count": 0, + "actor_attribution_accepted_count": 0, + "before_after_state_accepted_count": 0, + "docker_daemon_state_accepted_count": 0, + "compose_stack_state_accepted_count": 0, + "systemd_unit_state_accepted_count": 0, + "failed_unit_review_accepted_count": 0, + "port_binding_state_accepted_count": 0, + "dependency_impact_accepted_count": 0, + "public_route_recovery_accepted_count": 0, + "admin_route_recovery_accepted_count": 0, + "agent_provider_health_accepted_count": 0, + "monitoring_alert_accepted_count": 0, + "operator_notification_accepted_count": 0, + "cross_project_sync_accepted_count": 0, + "restoration_evidence_accepted_count": 0, + "postcheck_readback_accepted_count": 0, + "recurrence_guard_accepted_count": 0, + "no_false_green_accepted_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "coverage_percent_after_readback_plan": 64, + } + for key, expected in expected_host_service_post_incident_summary.items(): + assert_equal( + f"host_service_post_incident_readback_plan.summary.{key}", + host_service_post_incident_readback_plan["summary"][key], + expected, + ) + for key, value in host_service_post_incident_readback_plan["boundaries"].items(): + if key == "not_authorization": + assert_true(f"host_service_post_incident_readback_plan.boundaries.{key}", value) + else: + assert_false(f"host_service_post_incident_readback_plan.boundaries.{key}", value) + assert_equal( + "host_service_post_incident_readback_plan.readback_candidates.count", + len(host_service_post_incident_readback_plan["readback_candidates"]), + 9, + ) + expected_host_service_readback_ids = [ + "host_service_post_incident_readback:local_dev_compose", + "host_service_post_incident_readback:monitoring_110_compose", + "host_service_post_incident_readback:monitoring_exporters_188_compose", + "host_service_post_incident_readback:sentry_110_reference_compose", + "host_service_post_incident_readback:langfuse_110_compose", + "host_service_post_incident_readback:ansible_docker_compose_service_role", + "host_service_post_incident_readback:repair_bot_110_whitelist", + "host_service_post_incident_readback:repair_bot_188_whitelist", + "host_service_post_incident_readback:config_backup_host_capture", + ] + assert_equal( + "host_service_post_incident_readback_plan.readback_candidates", + [item["readback_candidate_id"] for item in host_service_post_incident_readback_plan["readback_candidates"]], + expected_host_service_readback_ids, + ) + for item in host_service_post_incident_readback_plan["readback_candidates"]: + assert_equal( + f"host_service_post_incident_readback_plan.{item['readback_candidate_id']}.required_readback_fields", + len(item["required_readback_fields"]), + 28, + ) + assert_equal( + f"host_service_post_incident_readback_plan.{item['readback_candidate_id']}.reviewer_checks", + len(item["reviewer_checks"]), + 28, + ) + assert_equal( + f"host_service_post_incident_readback_plan.{item['readback_candidate_id']}.outcome_lanes", + len(item["outcome_lanes"]), + 10, + ) + assert_equal( + f"host_service_post_incident_readback_plan.{item['readback_candidate_id']}.blocked_actions", + len(item["blocked_actions"]), + 41, + ) + assert_true( + f"host_service_post_incident_readback_plan.{item['readback_candidate_id']}.not_approval", + item["not_approval"], + ) + for false_key in [ + "post_incident_readback_received", + "post_incident_readback_accepted", + "actor_attribution_accepted", + "before_after_state_accepted", + "docker_daemon_state_accepted", + "compose_stack_state_accepted", + "systemd_unit_state_accepted", + "failed_unit_review_accepted", + "port_binding_state_accepted", + "dependency_impact_accepted", + "public_route_recovery_accepted", + "admin_route_recovery_accepted", + "agent_provider_health_accepted", + "monitoring_alert_accepted", + "operator_notification_accepted", + "cross_project_sync_accepted", + "restoration_evidence_accepted", + "postcheck_readback_accepted", + "recurrence_guard_accepted", + "maintenance_window_accepted", + "rollback_owner_accepted", + "no_false_green_accepted", + "ssh_read_authorized", + "ssh_write_authorized", + "live_host_read_authorized", + "docker_action_authorized", + "systemctl_action_authorized", + "repair_bot_execution_authorized", + "ansible_apply_authorized", + "route_smoke_authorized", + "secret_value_collection_allowed", + "active_scan_authorized", + "runtime_gate", + "action_buttons_allowed", + "production_write_authorized", + ]: + assert_false( + f"host_service_post_incident_readback_plan.{item['readback_candidate_id']}.{false_key}", + item[false_key], + ) assert_equal( "ssh_network_access_inventory.schema", ssh_network_access_inventory["schema_version"], @@ -6975,6 +7129,8 @@ def validate(root: Path) -> None: "docs/security/K8S-ARGOCD-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/host-service-config-inventory.snapshot.json", "docs/security/HOST-SERVICE-CONFIG-INVENTORY.md", + "docs/security/host-service-post-incident-readback-plan.snapshot.json", + "docs/security/HOST-SERVICE-POST-INCIDENT-READBACK-PLAN.md", "docs/schemas/host_service_config_inventory_v1.schema.json", "docs/security/ssh-network-access-inventory.snapshot.json", "docs/security/SSH-NETWORK-ACCESS-INVENTORY.md", @@ -7018,8 +7174,8 @@ def validate(root: Path) -> None: "high_value_config_control_coverage_category_count": 14, "high_value_config_control_coverage_c0_category_count": 8, "high_value_config_control_coverage_c1_category_count": 4, - "high_value_config_control_coverage_average_percent": 70, - "high_value_config_control_coverage_needs_live_evidence_count": 10, + "high_value_config_control_coverage_average_percent": 71, + "high_value_config_control_coverage_needs_live_evidence_count": 9, "high_value_config_control_coverage_owner_response_required_count": 14, "high_value_config_control_coverage_owner_response_received_count": 0, "high_value_config_control_coverage_owner_response_accepted_count": 0, @@ -7114,6 +7270,41 @@ def validate(root: Path) -> None: "host_service_change_evidence_acceptance_operator_notification_accepted_count": 0, "host_service_change_evidence_acceptance_runtime_gate_count": 0, "host_service_change_evidence_acceptance_coverage_percent_after_acceptance": 62, + "host_service_post_incident_readback_plan_first_layer": True, + "host_service_post_incident_readback_plan_candidate_count": 9, + "host_service_post_incident_readback_plan_write_capable_candidate_count": 3, + "host_service_post_incident_readback_plan_live_evidence_required_candidate_count": 8, + "host_service_post_incident_readback_plan_recovery_health_impact_review_required_candidate_count": 9, + "host_service_post_incident_readback_plan_cross_project_sync_required_candidate_count": 9, + "host_service_post_incident_readback_plan_no_false_green_required_candidate_count": 9, + "host_service_post_incident_readback_plan_readback_field_count": 36, + "host_service_post_incident_readback_plan_required_readback_field_count": 28, + "host_service_post_incident_readback_plan_reviewer_check_count": 28, + "host_service_post_incident_readback_plan_outcome_lane_count": 10, + "host_service_post_incident_readback_plan_blocked_action_count": 41, + "host_service_post_incident_readback_plan_post_incident_readback_received_count": 0, + "host_service_post_incident_readback_plan_post_incident_readback_accepted_count": 0, + "host_service_post_incident_readback_plan_actor_attribution_accepted_count": 0, + "host_service_post_incident_readback_plan_before_after_state_accepted_count": 0, + "host_service_post_incident_readback_plan_docker_daemon_state_accepted_count": 0, + "host_service_post_incident_readback_plan_compose_stack_state_accepted_count": 0, + "host_service_post_incident_readback_plan_systemd_unit_state_accepted_count": 0, + "host_service_post_incident_readback_plan_failed_unit_review_accepted_count": 0, + "host_service_post_incident_readback_plan_port_binding_state_accepted_count": 0, + "host_service_post_incident_readback_plan_public_route_recovery_accepted_count": 0, + "host_service_post_incident_readback_plan_admin_route_recovery_accepted_count": 0, + "host_service_post_incident_readback_plan_agent_provider_health_accepted_count": 0, + "host_service_post_incident_readback_plan_monitoring_alert_accepted_count": 0, + "host_service_post_incident_readback_plan_operator_notification_accepted_count": 0, + "host_service_post_incident_readback_plan_cross_project_sync_accepted_count": 0, + "host_service_post_incident_readback_plan_restoration_evidence_accepted_count": 0, + "host_service_post_incident_readback_plan_postcheck_readback_accepted_count": 0, + "host_service_post_incident_readback_plan_recurrence_guard_accepted_count": 0, + "host_service_post_incident_readback_plan_no_false_green_accepted_count": 0, + "host_service_post_incident_readback_plan_runtime_gate_count": 0, + "host_service_post_incident_readback_plan_action_button_count": 0, + "host_service_post_incident_readback_plan_coverage_percent_after_readback_plan": 64, + "docker_compose_systemd_host_config_coverage_percent": 64, } for key, expected in expected_host_service_projection_summary.items(): assert_equal( @@ -17008,7 +17199,7 @@ def validate(root: Path) -> None: assert_text_contains( "iwooos_page.high_value_config_control_coverage_docker_systemd_percent", iwooos_projection_page, - "{ key: 'dockerSystemd', rank: 'P1-1', value: '62%'", + "{ key: 'dockerSystemd', rank: 'P1-1', value: '64%'", ) assert_text_contains( "iwooos_page.high_value_config_control_coverage_ssh_network_percent", @@ -17037,8 +17228,8 @@ def validate(root: Path) -> None: "high_value_config_control_coverage_category_count=14", "high_value_config_control_coverage_c0_category_count=8", "high_value_config_control_coverage_c1_category_count=4", - "high_value_config_control_coverage_average_percent=70", - "high_value_config_control_coverage_needs_live_evidence_count=10", + "high_value_config_control_coverage_average_percent=71", + "high_value_config_control_coverage_needs_live_evidence_count=9", "high_value_config_control_coverage_owner_response_required_count=14", "high_value_config_control_coverage_owner_response_received_count=0", "high_value_config_control_coverage_owner_response_accepted_count=0", @@ -17164,6 +17355,28 @@ def validate(root: Path) -> None: "host_service_change_evidence_acceptance_public_route_recovery_accepted_count=0", "host_service_change_evidence_acceptance_operator_notification_accepted_count=0", "host_service_change_evidence_acceptance_runtime_gate_count=0", + "host_service_post_incident_readback_plan_candidate_count=9", + "host_service_post_incident_readback_plan_write_capable_candidate_count=3", + "host_service_post_incident_readback_plan_live_evidence_required_candidate_count=8", + "host_service_post_incident_readback_plan_required_readback_field_count=28", + "host_service_post_incident_readback_plan_reviewer_check_count=28", + "host_service_post_incident_readback_plan_outcome_lane_count=10", + "host_service_post_incident_readback_plan_blocked_action_count=41", + "host_service_post_incident_readback_plan_post_incident_readback_received_count=0", + "host_service_post_incident_readback_plan_post_incident_readback_accepted_count=0", + "host_service_post_incident_readback_plan_docker_daemon_state_accepted_count=0", + "host_service_post_incident_readback_plan_compose_stack_state_accepted_count=0", + "host_service_post_incident_readback_plan_systemd_unit_state_accepted_count=0", + "host_service_post_incident_readback_plan_failed_unit_review_accepted_count=0", + "host_service_post_incident_readback_plan_port_binding_state_accepted_count=0", + "host_service_post_incident_readback_plan_public_route_recovery_accepted_count=0", + "host_service_post_incident_readback_plan_admin_route_recovery_accepted_count=0", + "host_service_post_incident_readback_plan_agent_provider_health_accepted_count=0", + "host_service_post_incident_readback_plan_monitoring_alert_accepted_count=0", + "host_service_post_incident_readback_plan_operator_notification_accepted_count=0", + "host_service_post_incident_readback_plan_cross_project_sync_accepted_count=0", + "host_service_post_incident_readback_plan_no_false_green_accepted_count=0", + "host_service_post_incident_readback_plan_runtime_gate_count=0", "ssh_network_access_inventory_surface_count=16", "ssh_network_access_inventory_write_capable_surface_count=6", "ssh_network_access_inventory_runtime_gate_count=0",