diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 0ef3576cc..fb2d8257a 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -17942,7 +17942,7 @@ }, "sshNetwork": { "title": "SSH / network / firewall", - "body": "repo-only 清冊已納入 16 個 SSH / network access surface,且 owner response acceptance 與事故型端口 / 防火牆變更證據驗收只讀帳本已固定;下一步仍需 change / incident ref、actor、before / after state、service health impact、operator notification、restoration time、cross-project sync、maintenance window、rollback owner 與 post-check evidence。" + "body": "repo-only 清冊已納入 16 個 SSH / network access surface,owner response acceptance、事故型端口 / 防火牆變更證據驗收與 post-incident readback plan 已固定;目前成熟度 64%,14 個事故回讀候選、24 個 reviewer checks、10 條 outcome lanes、34 類 blocked action。下一步仍需 actor、before / after、service / AI provider / monitoring impact、operator notification、cross-project sync、restoration evidence、recurrence guard、maintenance window、rollback owner 與 post-check evidence,readback accepted 與 runtime gate 仍全部為 0。" }, "k8sGitops": { "title": "K8s / ArgoCD GitOps", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 0ef3576cc..fb2d8257a 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -17942,7 +17942,7 @@ }, "sshNetwork": { "title": "SSH / network / firewall", - "body": "repo-only 清冊已納入 16 個 SSH / network access surface,且 owner response acceptance 與事故型端口 / 防火牆變更證據驗收只讀帳本已固定;下一步仍需 change / incident ref、actor、before / after state、service health impact、operator notification、restoration time、cross-project sync、maintenance window、rollback owner 與 post-check evidence。" + "body": "repo-only 清冊已納入 16 個 SSH / network access surface,owner response acceptance、事故型端口 / 防火牆變更證據驗收與 post-incident readback plan 已固定;目前成熟度 64%,14 個事故回讀候選、24 個 reviewer checks、10 條 outcome lanes、34 類 blocked action。下一步仍需 actor、before / after、service / AI provider / monitoring impact、operator notification、cross-project sync、restoration evidence、recurrence guard、maintenance window、rollback owner 與 post-check evidence,readback accepted 與 runtime gate 仍全部為 0。" }, "k8sGitops": { "title": "K8s / ArgoCD GitOps", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 3cb2a7be0..2ae40f7b0 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -2093,7 +2093,7 @@ const highValueConfigControlCoverageSummary = [ const highValueConfigControlCoverageItems: HighValueConfigControlCoverageItem[] = [ { key: 'dockerSystemd', rank: 'P1-1', value: '62%', icon: Server, tone: 'warn' }, - { key: 'sshNetwork', rank: 'P1-2', value: '62%', icon: Network, 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' }, ] @@ -2256,6 +2256,24 @@ const highValueConfigControlCoverageBoundaries = [ 'port_firewall_change_evidence_acceptance_operator_notification_accepted_count=0', 'port_firewall_change_evidence_acceptance_postcheck_evidence_accepted_count=0', 'port_firewall_change_evidence_acceptance_runtime_gate_count=0', + 'ssh_network_post_incident_readback_plan_candidate_count=14', + 'ssh_network_post_incident_readback_plan_write_capable_candidate_count=6', + 'ssh_network_post_incident_readback_plan_policy_or_exposure_candidate_count=5', + 'ssh_network_post_incident_readback_plan_required_readback_field_count=24', + 'ssh_network_post_incident_readback_plan_reviewer_check_count=24', + 'ssh_network_post_incident_readback_plan_outcome_lane_count=10', + 'ssh_network_post_incident_readback_plan_blocked_action_count=34', + 'ssh_network_post_incident_readback_plan_post_incident_readback_received_count=0', + 'ssh_network_post_incident_readback_plan_post_incident_readback_accepted_count=0', + 'ssh_network_post_incident_readback_plan_actor_attribution_accepted_count=0', + 'ssh_network_post_incident_readback_plan_before_after_state_accepted_count=0', + 'ssh_network_post_incident_readback_plan_public_route_impact_accepted_count=0', + 'ssh_network_post_incident_readback_plan_ai_provider_impact_accepted_count=0', + 'ssh_network_post_incident_readback_plan_monitoring_alert_impact_accepted_count=0', + 'ssh_network_post_incident_readback_plan_cross_project_sync_accepted_count=0', + 'ssh_network_post_incident_readback_plan_recurrence_guard_accepted_count=0', + 'ssh_network_post_incident_readback_plan_no_false_green_accepted_count=0', + 'ssh_network_post_incident_readback_plan_runtime_gate_count=0', 'backup_restore_escrow_inventory_surface_count=38', 'backup_restore_escrow_inventory_write_capable_surface_count=27', 'backup_restore_escrow_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 8c72c4e0f..422a96e15 100644 --- a/docs/schemas/iwooos_posture_projection_v1.schema.json +++ b/docs/schemas/iwooos_posture_projection_v1.schema.json @@ -363,7 +363,37 @@ "s4_9_owner_response_metadata_intake_redacted_ref_required", "s4_9_owner_response_metadata_intake_raw_payload_allowed", "s4_9_owner_response_metadata_intake_secret_plaintext_allowed", - "s4_9_owner_response_metadata_intake_action_buttons_allowed" + "s4_9_owner_response_metadata_intake_action_buttons_allowed", + "ssh_network_post_incident_readback_plan_first_layer", + "ssh_network_post_incident_readback_plan_candidate_count", + "ssh_network_post_incident_readback_plan_write_capable_candidate_count", + "ssh_network_post_incident_readback_plan_policy_or_exposure_candidate_count", + "ssh_network_post_incident_readback_plan_health_impact_review_required_candidate_count", + "ssh_network_post_incident_readback_plan_cross_project_sync_required_candidate_count", + "ssh_network_post_incident_readback_plan_recurrence_guard_required_candidate_count", + "ssh_network_post_incident_readback_plan_readback_field_count", + "ssh_network_post_incident_readback_plan_required_readback_field_count", + "ssh_network_post_incident_readback_plan_reviewer_check_count", + "ssh_network_post_incident_readback_plan_outcome_lane_count", + "ssh_network_post_incident_readback_plan_blocked_action_count", + "ssh_network_post_incident_readback_plan_post_incident_readback_received_count", + "ssh_network_post_incident_readback_plan_post_incident_readback_accepted_count", + "ssh_network_post_incident_readback_plan_actor_attribution_accepted_count", + "ssh_network_post_incident_readback_plan_before_after_state_accepted_count", + "ssh_network_post_incident_readback_plan_service_dependency_accepted_count", + "ssh_network_post_incident_readback_plan_public_route_impact_accepted_count", + "ssh_network_post_incident_readback_plan_ai_provider_impact_accepted_count", + "ssh_network_post_incident_readback_plan_monitoring_alert_impact_accepted_count", + "ssh_network_post_incident_readback_plan_operator_notification_accepted_count", + "ssh_network_post_incident_readback_plan_cross_project_sync_accepted_count", + "ssh_network_post_incident_readback_plan_restoration_evidence_accepted_count", + "ssh_network_post_incident_readback_plan_postcheck_readback_accepted_count", + "ssh_network_post_incident_readback_plan_recurrence_guard_accepted_count", + "ssh_network_post_incident_readback_plan_no_false_green_accepted_count", + "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" ], "properties": { "route_path": { @@ -1521,6 +1551,126 @@ "ai_provider_model_routing_coverage_percent": { "type": "integer", "const": 64 + }, + "ssh_network_post_incident_readback_plan_first_layer": { + "type": "boolean", + "const": true + }, + "ssh_network_post_incident_readback_plan_candidate_count": { + "type": "integer", + "const": 14 + }, + "ssh_network_post_incident_readback_plan_write_capable_candidate_count": { + "type": "integer", + "const": 6 + }, + "ssh_network_post_incident_readback_plan_policy_or_exposure_candidate_count": { + "type": "integer", + "const": 5 + }, + "ssh_network_post_incident_readback_plan_health_impact_review_required_candidate_count": { + "type": "integer", + "const": 14 + }, + "ssh_network_post_incident_readback_plan_cross_project_sync_required_candidate_count": { + "type": "integer", + "const": 14 + }, + "ssh_network_post_incident_readback_plan_recurrence_guard_required_candidate_count": { + "type": "integer", + "const": 14 + }, + "ssh_network_post_incident_readback_plan_readback_field_count": { + "type": "integer", + "const": 30 + }, + "ssh_network_post_incident_readback_plan_required_readback_field_count": { + "type": "integer", + "const": 24 + }, + "ssh_network_post_incident_readback_plan_reviewer_check_count": { + "type": "integer", + "const": 24 + }, + "ssh_network_post_incident_readback_plan_outcome_lane_count": { + "type": "integer", + "const": 10 + }, + "ssh_network_post_incident_readback_plan_blocked_action_count": { + "type": "integer", + "const": 34 + }, + "ssh_network_post_incident_readback_plan_post_incident_readback_received_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_post_incident_readback_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_actor_attribution_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_before_after_state_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_service_dependency_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_public_route_impact_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_ai_provider_impact_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_monitoring_alert_impact_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_operator_notification_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_cross_project_sync_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_restoration_evidence_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_postcheck_readback_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_recurrence_guard_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_no_false_green_accepted_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_runtime_gate_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_action_button_count": { + "type": "integer", + "const": 0 + }, + "ssh_network_post_incident_readback_plan_coverage_percent_after_readback_plan": { + "type": "integer", + "const": 64 + }, + "ssh_firewall_network_access_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 b9687479b..ecad00a2a 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -90,6 +90,8 @@ 固定數字為 `change_evidence_candidate_count=14`、`write_capable_change_evidence_candidate_count=6`、`policy_or_exposure_candidate_count=5`、`change_evidence_field_count=40`、`required_evidence_field_count=21`、`reviewer_check_count=21`、`outcome_lane_count=9`、`blocked_action_count=28`、`change_evidence_received_count=0`、`change_evidence_accepted_count=0`、`service_health_impact_accepted_count=0`、`operator_notification_accepted_count=0`、`firewall_change_authorized_count=0`、`port_close_authorized_count=0`、`port_open_authorized_count=0`、`runtime_gate_count=0`。此更新讓 `ssh_firewall_network_access` 從 `58%` 推進到 `62%`;它補齊端口 / 防火牆變更與事故回補的 actor、before / after state、service dependency、customer impact、service health impact、operator notification、cross-project sync、rollback 與 post-check evidence 驗收規則,不代表 SSH、live firewall read、firewall change、port close / open、route smoke、host restart、production write 或 runtime gate 已授權。 +2026-06-15 再新增 `docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md` 與 `docs/security/ssh-network-post-incident-readback-plan.snapshot.json`,把同一批端口 / 防火牆 / NodePort / NetworkPolicy / WireGuard / deploy SSH / sudo / alert action surface 補成事故後回讀計畫。固定 `readback_candidate_count=14`、`write_capable_readback_candidate_count=6`、`policy_or_exposure_readback_candidate_count=5`、`required_readback_field_count=24`、`reviewer_check_count=24`、`outcome_lane_count=10`、`blocked_action_count=34`,並要求 actor attribution、before / after state、service / public route / AI provider / monitoring impact、operator notification、cross-project sync、restoration evidence、post-check、recurrence guard 與 no-false-green attestation。此更新讓 `ssh_firewall_network_access` 從 `62%` 推進到 `64%`;但 post-incident readback received / accepted、actor attribution accepted、before / after accepted、impact accepted、notification accepted、cross-project sync accepted、restoration accepted、recurrence guard accepted、runtime gate 與 action button 仍全部為 `0 / false`。 + ## 1.7a 2026-06-15 AI provider / model routing owner response acceptance 只讀帳本 已新增 `docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md` 與 `docs/security/ai-provider-owner-response-acceptance.snapshot.json`,將 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 帳本。 @@ -263,6 +265,7 @@ python3 scripts/security/iwooos-config-control-guard.py --root . | Backup / restore / escrow owner response acceptance backfill | `100%` | 已將 `backup_restore_owner_response_acceptance_v1` 補強為 38 個 candidate、27 個 write-capable、23 個 owner 必填欄位、22 個 reviewer checks、9 條 outcome lanes、31 類 blocked action;backup / restore / credential 成熟度 `62% -> 64%` | | 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` | | owner response 收件 | `0%` | 尚未收到或接受任何 owner response | | live evidence collection | `0%` | 未 SSH、未 live probe、未 active scan | | runtime gate | `0%` | 未開啟任何執行期閘門 | @@ -285,6 +288,8 @@ python3 scripts/security/iwooos-config-control-guard.py --root . 2026-06-15 再新增 `port_firewall_change_evidence_acceptance_v1`,把 14 個端口、防火牆、NodePort、NetworkPolicy、WireGuard、deploy SSH、sudo 與 alert action surface 轉成 `change_evidence_candidate_count=14`、`write_capable_change_evidence_candidate_count=6`、`policy_or_exposure_candidate_count=5`、`required_evidence_field_count=21`、`reviewer_check_count=21`、`outcome_lane_count=9`、`blocked_action_count=28` 的 change evidence acceptance 只讀帳本;同日再補事故型欄位,要求 severity、service health impact、operator notification、restoration time 與 break-glass backfill。此更新讓 `ssh_firewall_network_access` 從 `58%` 推進到 `62%`,但 change evidence received / accepted、actor identified、before / after state、service health impact accepted、operator notification accepted、cross-project sync、post-check evidence、firewall change、port close / open、NetworkPolicy apply、NodePort change、WireGuard change、route smoke、host restart、runtime gate 與 action button 仍全部為 `0`。 +2026-06-15 再新增 `ssh_network_post_incident_readback_plan_v1`,將同一批端口 / 防火牆事故 surface 轉成 `readback_candidate_count=14`、`write_capable_readback_candidate_count=6`、`policy_or_exposure_readback_candidate_count=5`、`required_readback_field_count=24`、`reviewer_check_count=24`、`outcome_lane_count=10`、`blocked_action_count=34` 的事故後回讀計畫。此更新讓 `ssh_firewall_network_access` 從 `62%` 推進到 `64%`,但 post-incident readback received / accepted、actor attribution、before / after state、service / public route / AI provider / monitoring impact、operator notification、cross-project sync、restoration evidence、post-check、recurrence guard、no-false-green、runtime gate 與 action button 仍全部為 `0`。 + ## 10. P1-3 Backup / restore / escrow / retention 清冊更新 `backup_restore_escrow_inventory_v1` 已把 backup orchestration、service backup scripts、restic retention、offsite sync、credential escrow、Velero restore drill、backup health alert 與 cold-start / DR runbook 納入 repo-only 清冊,共 `38` 個 surface、`15` 個 backup script surface、`8` 個 offsite / escrow surface、`5` 個 Velero surface 與 `27` 個 write-capable surface。此更新只讓 `backup_restore_credential` 從 `52%` 推進到 `58%`;owner response、live evidence、restore drill acceptance、offsite sync acceptance、credential escrow acceptance、retention change acceptance、runtime gate 與 action button 仍全部為 `0`。 diff --git a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md index e6fb55e9c..c59581156 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -57,6 +57,8 @@ 2026-06-15 再新增 `docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md` 與 `docs/security/port-firewall-change-evidence-acceptance.snapshot.json`,將 14 個端口 / 防火牆 / NodePort / NetworkPolicy / WireGuard / deploy SSH / sudo / alert action surface 轉成變更證據驗收只讀帳本。固定 `candidates=14`、`write_capable=6`、`policy_or_exposure=5`、`evidence_fields=40`、`required_evidence_fields=21`、`reviewer_checks=21`、`outcome_lanes=9`、`blocked_actions=28`,並納入事故嚴重度、服務健康影響、通知證據、恢復時間與 break-glass 回補欄位,讓 SSH / network 類別成熟度從 `58%` 推進到 `62%`;但 change evidence received / accepted、actor identified、before / after state、service health impact accepted、operator notification accepted、cross-project sync、post-check evidence、firewall / port 變更、route smoke、host restart、host write、runtime gate 仍全部為 `0 / false`。 +2026-06-15 再新增 `docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md` 與 `docs/security/ssh-network-post-incident-readback-plan.snapshot.json`,把 14 個端口 / 防火牆事故 surface 補成 post-incident readback plan。固定 `readback_candidates=14`、`write_capable=6`、`policy_or_exposure=5`、`readback_fields=30`、`required_readback_fields=24`、`reviewer_checks=24`、`outcome_lanes=10`、`blocked_actions=34`,並要求 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,讓 SSH / network 類別成熟度從 `62%` 推進到 `64%`;但 readback received / accepted、actor attribution accepted、before / after accepted、impact accepted、notification accepted、cross-project sync accepted、restoration accepted、recurrence guard accepted、host write、runtime gate 仍全部為 `0 / false`。 + ### 0.3a 2026-06-15 K8s / ArgoCD GitOps 變更證據驗收 `k8s_argocd_change_evidence_acceptance_v1` 已把 `awoooi_prod`、`argocd`、`velero`、`monitoring` 四個 scan group 轉成 GitOps 變更證據驗收只讀帳本。固定 `candidates=4`、`c0=3`、`write_capable=4`、`required_evidence_fields=18`、`reviewer_checks=18`、`outcome_lanes=8`、`blocked_actions=28`,讓 K8s / ArgoCD 類別成熟度從 `62%` 推進到 `64%`。 @@ -275,6 +277,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 | 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%` | +| SSH / firewall / network 事故後回讀計畫 | `100%` | 已新增 `ssh_network_post_incident_readback_plan_v1`,14 個 readback candidate、24 個必填欄位、24 個 reviewer checks、10 條 outcome lanes、34 類 blocked action;成熟度 `62% -> 64%`,readback accepted 與 runtime gate 仍為 `0` | | K8s / ArgoCD GitOps 變更證據驗收 | `100%` | 已新增 `k8s_argocd_change_evidence_acceptance_v1`,4 個 candidate、3 個 C0、4 個 write-capable、18 個 reviewer checks、8 條 outcome lanes、28 類 blocked action;成熟度 `62% -> 64%` | | Public / Admin / API runtime config 變更證據驗收 | `100%` | 已新增 `public_runtime_config_change_evidence_acceptance_v1` 與 `public_frontend_sensitive_surface_guard_v1`;6 個 candidate、5 個 C0、21 個 reviewer checks、8 條 outcome lanes、32 類 blocked action,另掃 225 個前端檔案、12 類禁字、違規 0;成熟度 `62% -> 66%`;raw namespace / repo slug / 內部狀態碼 / 內部協作內容外洩列為拒收或隔離條件 | | Package / Docker supply-chain repo-only baseline | `100%` | 已新增 `package_supply_chain_baseline_v1`,盤點 `package_json=6`、`pyproject=4`、`requirements=2`、`dockerfiles=2`、`compose=6`、`gaps=5`;不 install、不掃 CVE、不改 image、不部署 | diff --git a/docs/security/IWOOOS-POSTURE-PROJECTION.md b/docs/security/IWOOOS-POSTURE-PROJECTION.md index 0222d8494..b251b468c 100644 --- a/docs/security/IWOOOS-POSTURE-PROJECTION.md +++ b/docs/security/IWOOOS-POSTURE-PROJECTION.md @@ -100,6 +100,7 @@ IwoooS 首版只讀取或對齊以下已提交 evidence: 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`。 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`。 56b. 5 個 CD / Runner / Secret 注入變更證據驗收候選,顯示 CD pipeline、程式碼審查、部署通知、執行器證明與 repository secret name parity / injection owner 的 metadata-only 收件規則;C0 candidate `4`、write-capable candidate `5`、local workflow file `33`、referenced secret name `42`、runner label `5`、reviewer check `19`、outcome lane `8`、blocked action `32`,讓 secret metadata 類別成熟度從 `66%` 推進到 `68%`,讓 Gitea workflow / runner 類別成熟度從 `70%` 推進到 `72%`;workflow diff、runner attestation、secret name parity、secret injection route、deploy marker readback、guard result、postcheck evidence、runtime approval package、workflow modification、runner change、repo secret change、secret rotation、Gitea action dispatch、production deploy、runtime gate 與 action button 仍全部為 `0`。 56c. 8 個 AI provider / model routing owner response acceptance 候選,顯示 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 收件規則;write-capable candidate `5`、paid-provider candidate `5`、data-egress candidate `6`、owner field `24`、reviewer check `24`、outcome lane `10`、blocked action `38`,讓 AI provider / model routing 類別成熟度從 `60%` 推進到 `64%`;owner response、fallback order、dry-run、benchmark、cost review、privacy review、prompt redaction、quality gate、provider switch、external provider call、paid provider call、prompt send、live endpoint probe、secret collection、SDK install、shadow / canary、runtime gate 與 action button 仍全部為 `0`。 diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index 76d355720..2b6fb614a 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -40,6 +40,12 @@ 2026-06-15 追加 Frontend public sensitive surface guard:`public_frontend_sensitive_surface_guard_v1` 固定掃描 `files=225`、`patterns=12`、`allowlisted=2`、`violations=0`、`env_violation=0`、`runtime=0`,並接入 `security-mirror-progress-guard.py`。此更新讓 `public_admin_api_runtime_config` 只讀治理成熟度 `64% -> 66%`,高價值配置平均成熟度 `69% -> 70%`;仍不是 production bundle scan accepted、desktop / mobile production smoke accepted、owner response accepted、route / CORS / env / auth / webhook 變更、frontend / API deploy 或 runtime gate。 +## 0.00aaaab 2026-06-15 SSH / Network / Firewall 事故後回讀計畫 + +本輪把 SSH / Firewall / Network Access 從端口 / 防火牆變更證據驗收再補一層 post-incident readback plan:`ssh_network_post_incident_readback_plan_v1` 固定 `candidates=14`、`write_capable=6`、`policy_or_exposure=5`、`required_readback_fields=24`、`reviewer_checks=24`、`outcome_lanes=10`、`blocked_actions=34`,並讓 `ssh_firewall_network_access` 只讀治理成熟度 `62% -> 64%`,高價值配置平均成熟度仍維持 `70%`。這是 metadata-only 事故後回讀計畫,不是 post-incident readback accepted、actor attribution accepted、before / after accepted、service / public route / AI provider / monitoring impact accepted、operator notification accepted、cross-project sync accepted、restoration evidence accepted、recurrence guard accepted、firewall change、port close / open、route smoke、host restart、production write 或 runtime gate。 + +同步邊界:IwoooS headline 維持 `64%`,active runtime gate 維持 `0`;readback received / accepted、actor、before / after、impact、通知、跨專案同步、恢復證據、防再發與 no-false-green accepted 全部仍為 `0 / false`。本段只更新文件、snapshot、guard、投影契約與前端 marker,不碰 Nginx、firewall、iptables、ufw、Docker、systemd、主機、provider endpoint 或 live route。 + ## 0.00aaaa 2026-06-15 CD / Runner / Secret 注入變更證據驗收 本輪把 CD pipeline、程式碼審查、部署通知、執行器證明與 repository secret name parity / injection owner 從 workflow / secret name owner response 再補一層變更證據驗收只讀帳本:`cd_runner_secret_injection_change_evidence_acceptance_v1` 固定 `candidates=5`、`c0=4`、`c1=1`、`write_capable=5`、`workflow_files=33`、`referenced_secret_names=42`、`runner_labels=5`、`required_evidence_fields=19`、`reviewer_checks=19`、`outcome_lanes=8`、`blocked_actions=32`,並讓 `secret_metadata` 只讀治理成熟度 `66% -> 68%`、`gitea_workflow_runner_source_control` 只讀治理成熟度 `70% -> 72%`,高價值配置平均只讀成熟度仍維持 `68%`。這是 metadata-only 收件驗收,不是 workflow diff accepted、runner attestation accepted、secret parity accepted、secret injection route accepted、deploy marker readback accepted、guard result accepted、post-check accepted、runtime approval package、workflow modification、runner change、repo secret change、secret rotation、Gitea action dispatch、production deploy 或 runtime gate。 diff --git a/docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md b/docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md new file mode 100644 index 000000000..7b6201fd8 --- /dev/null +++ b/docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md @@ -0,0 +1,191 @@ +# IwoooS SSH / network / firewall post-incident readback plan + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-15 | +| 狀態 | `post_incident_readback_plan_ready_no_runtime_action` | +| 工具 | `scripts/security/ssh-network-post-incident-readback-plan.py` | +| Snapshot | `docs/security/ssh-network-post-incident-readback-plan.snapshot.json` | +| Source acceptance | `docs/security/port-firewall-change-evidence-acceptance.snapshot.json` | +| runtime gate | `0` | + +## 1. 目的 + +本文件承接端口 / 防火牆變更證據驗收帳本,補上事故後回讀計畫。未來若再次發生端口被關、firewall / NetworkPolicy / NodePort / WireGuard policy 被改動、deploy SSH 斷線、AI provider route 異常、public route 或 monitoring 路徑受影響,IwoooS 必須先收齊「誰改、何時改、改前改後狀態、影響哪些服務、是否同步相關產品、怎麼恢復、怎麼防再發」的脫敏證據。 + +這不是 SSH 授權、不是 live firewall read、不是 firewall / port change、不是 route smoke、不是 host restart,也不是 runtime gate。它只建立 post-incident readback 的欄位、reviewer checks、分流與拒收條件,避免把「服務後來恢復」誤判成「事故原因、責任、影響與防再發都已驗收」。 + +## 2. 摘要 + +| 指標 | 目前值 | 說明 | +|------|--------|------| +| readback candidate | `14` | 承接端口 / 防火牆 / NodePort / NetworkPolicy / WireGuard / deploy SSH / sudo / alert action surface | +| write-capable readback candidate | `6` | 可能影響 deploy SSH、monitoring deploy、sudoers 或 alert action catalog 的 surface | +| policy / exposure readback candidate | `5` | NetworkPolicy、NodePort、WireGuard 與 exposure 相關 surface | +| health impact review required | `14` | 全部都必須交代 service / AI provider / monitoring / product impact | +| cross-project sync required | `14` | 全部都必須交代跨產品 / owner / Session 同步 ref | +| recurrence guard required | `14` | 全部都必須提出防再發 guard 或 change freeze rule | +| readback field | `30` | readback 欄位總數 | +| required readback field | `24` | owner / reviewer 必填欄位 | +| reviewer check | `24` | actor、before / after、health impact、通知、同步、恢復、防再發與 no-false-green 檢查 | +| outcome lane | `10` | waiting、補 actor、補 before-after、補 health impact、隔離、拒收、review、ledger-only、防再發回補、runtime gate | +| blocked action | `34` | SSH、firewall、port、route smoke、reload、restart、secret、active scan、provider switch、prompt send、production write 等 | +| post-incident readback received / accepted | `0 / 0` | 尚未收到或驗收 | +| no-false-green accepted | `0` | 不把 route 200、service up 或 UI 可見當事故驗收 | +| runtime gate / action button | `0 / 0` | 不提供操作入口 | + +## 3. Readback Candidate 範圍 + +| Candidate | 驗收焦點 | +|-----------|----------| +| `ssh_network_post_incident_readback:ansible_inventory_ssh_targets` | 主機存取異動、端口影響、維護窗口、rollback 與 post-check | +| `ssh_network_post_incident_readback:gitea_cd_deploy_ssh` | deploy SSH 可達性、回復證據、rollback owner 與跨專案通知 | +| `ssh_network_post_incident_readback:gitea_cd_dev_ssh` | dev / prod 邊界、端口 policy、owner decision 與防再發 | +| `ssh_network_post_incident_readback:deploy_alerts_ssh_path` | alert deploy path、通知鏈路、受影響產品與恢復 readback | +| `ssh_network_post_incident_readback:monitoring_discover_docker_ssh` | monitoring discovery 可達性、read-only window 與 false-green 風險 | +| `ssh_network_post_incident_readback:monitoring_exporter_deploy_ssh` | exporter deploy access、firewall owner、post-check 與 rollback | +| `ssh_network_post_incident_readback:backup_config_ssh_capture` | backup access、restore validation、service dependency 與 notification | +| `ssh_network_post_incident_readback:host_ops_sudoers_wrapper` | sudo 授權邊界、break-glass、回復責任與 forbidden command proof | +| `ssh_network_post_incident_readback:k8s_prod_network_policy` | ingress / egress policy、route impact、metrics / alert 與回滾 | +| `ssh_network_post_incident_readback:argocd_metrics_network_policy` | metrics scrape、NodePort exposure、source whitelist 與 monitoring impact | +| `ssh_network_post_incident_readback:argocd_metrics_nodeport` | NodePort exposure、firewall owner、rollback 與 public/admin route 影響 | +| `ssh_network_post_incident_readback:velero_metrics_nodeport` | backup metrics exposure、access policy 與 restore readiness 影響 | +| `ssh_network_post_incident_readback:wireguard_mesh_runbook` | mesh cutover、firewall rule owner、canary / rollback 與 maintenance window | +| `ssh_network_post_incident_readback:alert_rules_ssh_actions` | alert action catalog、read/write/admin 分級、cooldown 與 post-check | + +## 4. 必填 Readback 欄位 + +1. `change_or_incident_ref` +2. `actor_attribution_ref` +3. `incident_detected_at_ref` +4. `change_window_ref` +5. `affected_port_or_policy_ref` +6. `before_state_ref` +7. `after_state_ref` +8. `service_dependency_ref` +9. `public_route_impact_ref` +10. `ai_provider_impact_ref` +11. `monitoring_alert_impact_ref` +12. `customer_or_product_impact_ref` +13. `operator_notification_ref` +14. `cross_project_sync_ref` +15. `restoration_evidence_ref` +16. `postcheck_readback_ref` +17. `recurrence_guard_ref` +18. `maintenance_window` +19. `rollback_owner` +20. `followup_owner` +21. `redacted_evidence_refs` +22. `no_secret_value_attestation` +23. `no_raw_firewall_dump_attestation` +24. `no_false_green_attestation` + +## 5. Reviewer Checks + +1. `source_change_evidence_current` +2. `incident_ref_present` +3. `actor_not_anonymous` +4. `before_after_state_present` +5. `port_policy_redacted` +6. `service_dependency_present` +7. `public_route_impact_present` +8. `ai_provider_impact_present` +9. `monitoring_alert_impact_present` +10. `customer_product_impact_present` +11. `operator_notification_present` +12. `cross_project_sync_present` +13. `restoration_evidence_present` +14. `postcheck_independent` +15. `recurrence_guard_present` +16. `emergency_classification_present` +17. `maintenance_window_present` +18. `rollback_owner_present` +19. `no_false_green_route_200` +20. `raw_firewall_dump_absent` +21. `secret_or_key_value_absent` +22. `hidden_impact_absent` +23. `counts_transition_safe` +24. `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 或 restoration evidence 時要求補件 | +| `request_health_impact_supplement` | 缺 service / AI provider / monitoring / product impact 時要求補件 | +| `quarantine_raw_payload` | 收到 raw firewall dump、secret 或 key material 時只能隔離 | +| `reject_unattributed_incident` | 無 actor、無 affected scope、無 rollback 或無 notification 的事故回讀不得驗收 | +| `ready_for_post_incident_review` | metadata 合格後,只能進 reviewer review | +| `incident_readback_only_update` | 只允許更新只讀 ledger,不得反向視為已批准操作 | +| `recurrence_guard_backfill_required` | 需補防再發 guard、owner review 與 change freeze | +| `waiting_runtime_gate` | 即使 readback accepted,runtime gate 仍需獨立人工批准 | + +## 7. 禁止動作 + +1. `ssh_read` +2. `ssh_write` +3. `live_firewall_read` +4. `firewall_change` +5. `port_change` +6. `port_close` +7. `port_open` +8. `network_policy_apply` +9. `nodeport_change` +10. `wireguard_change` +11. `sudo_action` +12. `deploy_ssh_action` +13. `route_smoke` +14. `public_gateway_reload` +15. `nginx_reload` +16. `host_restart` +17. `docker_restart` +18. `systemd_restart` +19. `secret_value_collection` +20. `ssh_key_collection` +21. `raw_firewall_dump_storage` +22. `raw_key_material_storage` +23. `mark_readback_accepted_without_reviewer_record` +24. `mark_incident_resolved_without_postcheck` +25. `hide_cross_project_impact` +26. `treat_route_200_as_all_green` +27. `treat_break_glass_as_approval` +28. `close_management_port_without_owner` +29. `open_runtime_gate` +30. `add_action_button` +31. `production_write` +32. `active_scan` +33. `provider_switch` +34. `prompt_send` + +## 8. 指令 + +產生 committed snapshot: + +```bash +python3 scripts/security/ssh-network-post-incident-readback-plan.py \ + --root . \ + --source-change-evidence-report docs/security/port-firewall-change-evidence-acceptance.snapshot.json \ + --output docs/security/ssh-network-post-incident-readback-plan.snapshot.json \ + --generated-at 2026-06-15T19:16:00+08:00 +``` + +驗證 guard: + +```bash +python3 scripts/security/security-mirror-progress-guard.py --root . +``` + +## 9. 完成度 + +| 工作 | 完成度 | 說明 | +|------|--------|------| +| post-incident readback plan artifact | `100%` | 14 份候選、snapshot、文件與 guard 已固定 | +| post-incident readback received / accepted | `0%` | 尚未收到,尚未驗收 | +| actor / before-after / impact evidence | `0%` | 尚未收到 owner-provided evidence | +| service / AI provider / monitoring impact | `0%` | 尚未收到脫敏 impact refs | +| cross-project sync / notification evidence | `0%` | 尚未收到同步與通知證據 | +| recurrence guard / no-false-green accepted | `0%` | 尚未驗收防再發或 no-false-green | +| SSH / firewall / port / route / restart action | `0%` | 未授權且未執行 | +| runtime gate / production write | `0%` | 未授權且未執行 | diff --git a/docs/security/high-value-config-control-coverage.snapshot.json b/docs/security/high-value-config-control-coverage.snapshot.json index 280ffd239..c0ad1e011 100644 --- a/docs/security/high-value-config-control-coverage.snapshot.json +++ b/docs/security/high-value-config-control-coverage.snapshot.json @@ -412,9 +412,9 @@ "action_buttons_allowed": false, "category_id": "ssh_firewall_network_access", "control_tier": "C1", - "coverage_percent": 62, - "coverage_status": "incident_change_evidence_acceptance_ready_needs_network_owner_evidence", - "current_gap": "owner response acceptance 帳本已固定 16 個 SSH / network acceptance candidate,端口 / 防火牆事故型變更證據驗收帳本已固定 14 個 change evidence candidate;仍缺 owner-provided change / incident evidence、actor、before / after state、service health impact、operator notification、cross-project sync、maintenance window、rollback owner 與 post-check evidence。", + "coverage_percent": 64, + "coverage_status": "post_incident_readback_plan_ready_needs_network_owner_evidence", + "current_gap": "owner response acceptance、端口 / 防火牆事故型變更證據驗收與 post-incident readback plan 都已固定;仍缺 owner-provided change / incident evidence、actor、before / after state、service / AI provider / monitoring impact、operator notification、cross-project sync、restoration evidence、recurrence guard、maintenance window、rollback owner 與 post-check evidence。", "evidence_refs": [ "docs/HARD_RULES.md", "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md", @@ -425,10 +425,12 @@ "docs/security/SSH-NETWORK-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/ssh-network-owner-response-acceptance.snapshot.json", "docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md", - "docs/security/port-firewall-change-evidence-acceptance.snapshot.json" + "docs/security/port-firewall-change-evidence-acceptance.snapshot.json", + "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/ssh-network-post-incident-readback-plan.snapshot.json" ], "label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort", - "next_owner_action": "補端口 / 防火牆變更的 change / incident ref、actor role / team、affected scope、before / after state、service dependency、customer impact、service health impact、operator notification、cross-project sync、rollback owner 與 post-check 指標。", + "next_owner_action": "補端口 / 防火牆事故回讀包:change / incident ref、actor role / team、affected scope、before / after state、service dependency、public route impact、AI provider impact、monitoring alert impact、operator notification、cross-project sync、restoration evidence、recurrence guard、rollback owner 與 post-check 指標。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -639,8 +641,8 @@ "websocket_route_change_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-06-11T21:30:00+08:00", - "git_commit": "403b29df", + "generated_at": "2026-06-15T19:40:00+08:00", + "git_commit": "3d0c3cc8", "lowest_coverage_categories": [ { "category_id": "docker_compose_systemd_host_config", @@ -649,13 +651,6 @@ "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": "ssh_firewall_network_access", - "coverage_percent": 62, - "current_gap": "owner response acceptance 帳本已固定 16 個 SSH / network acceptance candidate,端口 / 防火牆事故型變更證據驗收帳本已固定 14 個 change evidence candidate;仍缺 owner-provided change / incident evidence、actor、before / after state、service health impact、operator notification、cross-project sync、maintenance window、rollback owner 與 post-check evidence。", - "label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort", - "next_owner_action": "補端口 / 防火牆變更的 change / incident ref、actor role / team、affected scope、before / after state、service dependency、customer impact、service health impact、operator notification、cross-project sync、rollback owner 與 post-check 指標。" - }, { "category_id": "k8s_production_gitops", "coverage_percent": 64, @@ -669,6 +664,13 @@ "current_gap": "已固定 owner response acceptance、restore recovery backfill、remote delete guard、retention runway、credential recovery metadata-only 與 backup health no-false-green 只讀帳本;restore drill、offsite sync、credential escrow、retention change、live evidence 與 owner response 仍全部為 0。", "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": "ssh_firewall_network_access", + "coverage_percent": 64, + "current_gap": "owner response acceptance、端口 / 防火牆事故型變更證據驗收與 post-incident readback plan 都已固定;仍缺 owner-provided change / incident evidence、actor、before / after state、service / AI provider / monitoring impact、operator notification、cross-project sync、restoration evidence、recurrence guard、maintenance window、rollback owner 與 post-check evidence。", + "label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort", + "next_owner_action": "補端口 / 防火牆事故回讀包:change / incident ref、actor role / team、affected scope、before / after state、service dependency、public route impact、AI provider impact、monitoring alert impact、operator notification、cross-project sync、restoration evidence、recurrence guard、rollback owner 與 post-check 指標。" } ], "next_collection_order": [ diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json index e0da037a9..228c6ad49 100644 --- a/docs/security/iwooos-posture-projection.snapshot.json +++ b/docs/security/iwooos-posture-projection.snapshot.json @@ -8426,7 +8426,9 @@ "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", "docs/security/public-frontend-sensitive-surface-guard.snapshot.json", "docs/security/AI-PROVIDER-OWNER-RESPONSE-ACCEPTANCE.md", - "docs/security/ai-provider-owner-response-acceptance.snapshot.json" + "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" ], "status": "draft", "summary": { @@ -9058,7 +9060,37 @@ "ai_provider_owner_response_acceptance_secret_value_collection_allowed_count": 0, "ai_provider_owner_response_acceptance_runtime_gate_count": 0, "ai_provider_owner_response_acceptance_coverage_percent_after_acceptance": 64, - "ai_provider_model_routing_coverage_percent": 64 + "ai_provider_model_routing_coverage_percent": 64, + "ssh_network_post_incident_readback_plan_first_layer": true, + "ssh_network_post_incident_readback_plan_candidate_count": 14, + "ssh_network_post_incident_readback_plan_write_capable_candidate_count": 6, + "ssh_network_post_incident_readback_plan_policy_or_exposure_candidate_count": 5, + "ssh_network_post_incident_readback_plan_health_impact_review_required_candidate_count": 14, + "ssh_network_post_incident_readback_plan_cross_project_sync_required_candidate_count": 14, + "ssh_network_post_incident_readback_plan_recurrence_guard_required_candidate_count": 14, + "ssh_network_post_incident_readback_plan_readback_field_count": 30, + "ssh_network_post_incident_readback_plan_required_readback_field_count": 24, + "ssh_network_post_incident_readback_plan_reviewer_check_count": 24, + "ssh_network_post_incident_readback_plan_outcome_lane_count": 10, + "ssh_network_post_incident_readback_plan_blocked_action_count": 34, + "ssh_network_post_incident_readback_plan_post_incident_readback_received_count": 0, + "ssh_network_post_incident_readback_plan_post_incident_readback_accepted_count": 0, + "ssh_network_post_incident_readback_plan_actor_attribution_accepted_count": 0, + "ssh_network_post_incident_readback_plan_before_after_state_accepted_count": 0, + "ssh_network_post_incident_readback_plan_service_dependency_accepted_count": 0, + "ssh_network_post_incident_readback_plan_public_route_impact_accepted_count": 0, + "ssh_network_post_incident_readback_plan_ai_provider_impact_accepted_count": 0, + "ssh_network_post_incident_readback_plan_monitoring_alert_impact_accepted_count": 0, + "ssh_network_post_incident_readback_plan_operator_notification_accepted_count": 0, + "ssh_network_post_incident_readback_plan_cross_project_sync_accepted_count": 0, + "ssh_network_post_incident_readback_plan_restoration_evidence_accepted_count": 0, + "ssh_network_post_incident_readback_plan_postcheck_readback_accepted_count": 0, + "ssh_network_post_incident_readback_plan_recurrence_guard_accepted_count": 0, + "ssh_network_post_incident_readback_plan_no_false_green_accepted_count": 0, + "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 }, "topology_atlas_lenses": [ { diff --git a/docs/security/ssh-network-post-incident-readback-plan.snapshot.json b/docs/security/ssh-network-post-incident-readback-plan.snapshot.json new file mode 100644 index 000000000..5ec92fe66 --- /dev/null +++ b/docs/security/ssh-network-post-incident-readback-plan.snapshot.json @@ -0,0 +1,3070 @@ +{ + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "boundaries": { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "firewall_change_authorized": false, + "host_restart_authorized": false, + "live_firewall_read_authorized": false, + "network_policy_apply_authorized": false, + "nodeport_change_authorized": false, + "not_authorization": true, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "secret_value_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "wireguard_change_authorized": false + }, + "generated_at": "2026-06-15T19:16:00+08:00", + "git_commit": "3d0c3cc8", + "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 或 restoration evidence 時要求補件。" + }, + { + "lane_id": "request_health_impact_supplement", + "meaning": "缺 service / AI provider / monitoring / product impact 時要求補件。" + }, + { + "lane_id": "quarantine_raw_payload", + "meaning": "收到 raw firewall dump、secret 或 key material 時只能隔離。" + }, + { + "lane_id": "reject_unattributed_incident", + "meaning": "無 actor、無 affected scope、無 rollback 或無 notification 的事故回讀不得驗收。" + }, + { + "lane_id": "ready_for_post_incident_review", + "meaning": "metadata 合格後,只能進 reviewer review。" + }, + { + "lane_id": "incident_readback_only_update", + "meaning": "只允許更新只讀 ledger,不得反向視為已批准操作。" + }, + { + "lane_id": "recurrence_guard_backfill_required", + "meaning": "需補防再發 guard、owner review 與 change freeze。" + }, + { + "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, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "ssh_target_inventory", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "110_111_112_120_121_188", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:ansible_inventory_ssh_targets", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:ansible_inventory_ssh_targets", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "ansible_inventory_ssh_targets", + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "ci_deploy_ssh", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "k8s_ssh_host", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:gitea_cd_deploy_ssh", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:gitea_cd_deploy_ssh", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "gitea_cd_deploy_ssh", + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "ci_deploy_ssh", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "192.168.0.120", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:gitea_cd_dev_ssh", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:gitea_cd_dev_ssh", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "gitea_cd_dev_ssh", + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "ci_deploy_ssh", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "192.168.0.110", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:deploy_alerts_ssh_path", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:deploy_alerts_ssh_path", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "deploy_alerts_ssh_path", + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "ssh_discovery_script", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "110_188_docker_hosts", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:monitoring_discover_docker_ssh", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:monitoring_discover_docker_ssh", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "monitoring_discover_docker_ssh", + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "monitoring_ssh_deploy_script", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "192.168.0.188", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:monitoring_exporter_deploy_ssh", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:monitoring_exporter_deploy_ssh", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "monitoring_exporter_deploy_ssh", + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "ssh_backup_capture", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "110_188_120_121_cluster", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:backup_config_ssh_capture", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:backup_config_ssh_capture", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "backup_config_ssh_capture", + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "sudoers_policy", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "host_ops_minimal_sudo", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:host_ops_sudoers_wrapper", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:host_ops_sudoers_wrapper", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "host_ops_sudoers_wrapper", + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "k8s_network_policy", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "awoooi_prod_namespace", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": true, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:k8s_prod_network_policy", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:k8s_prod_network_policy", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "k8s_prod_network_policy", + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "k8s_network_policy", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "argocd_namespace", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": true, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:argocd_metrics_network_policy", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:argocd_metrics_network_policy", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "argocd_metrics_network_policy", + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "k8s_nodeport_service", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "argocd_nodeport_30882_30883", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": true, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:argocd_metrics_nodeport", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:argocd_metrics_nodeport", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "argocd_metrics_nodeport", + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "k8s_nodeport_service", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "velero_nodeport_30885", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": true, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:velero_metrics_nodeport", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:velero_metrics_nodeport", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "velero_metrics_nodeport", + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "wireguard_runbook", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "110_111_120_121_gcp_a_gcp_b", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": true, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:wireguard_mesh_runbook", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:wireguard_mesh_runbook", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "wireguard_mesh_runbook", + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "active_scan_authorized": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_port_or_policy_ref": null, + "after_state_ref": null, + "ai_provider_impact_accepted": false, + "ai_provider_impact_ref": null, + "before_after_state_accepted": false, + "before_state_ref": null, + "blocked_actions": [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send" + ], + "change_or_incident_ref": null, + "change_window_ref": null, + "config_kind": "alert_ssh_action_rules", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_or_product_impact_ref": null, + "expected_scope": "ssh_mcp_action_catalog", + "firewall_change_authorized": false, + "followup_owner": "pending_post_incident_readback", + "host_restart_authorized": false, + "incident_detected_at_ref": null, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_post_incident_readback", + "maintenance_window_accepted": false, + "monitoring_alert_impact_accepted": false, + "monitoring_alert_impact_ref": null, + "network_policy_apply_authorized": false, + "no_false_green_accepted": false, + "nodeport_change_authorized": 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_health_impact_supplement", + "quarantine_raw_payload", + "reject_unattributed_incident", + "ready_for_post_incident_review", + "incident_readback_only_update", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "policy_or_exposure_surface": false, + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "post_incident_readback_accepted": false, + "post_incident_readback_received": false, + "postcheck_readback_accepted": false, + "postcheck_readback_ref": null, + "production_write_authorized": false, + "prompt_send_authorized": false, + "provider_switch_authorized": false, + "public_route_impact_accepted": false, + "public_route_impact_ref": null, + "readback_candidate_id": "ssh_network_post_incident_readback:alert_rules_ssh_actions", + "readback_fields": [ + "readback_candidate_id", + "source_change_evidence_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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, + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "restoration_evidence_accepted": false, + "restoration_evidence_ref": null, + "reviewer_checks": [ + "source_change_evidence_current", + "incident_ref_present", + "actor_not_anonymous", + "before_after_state_present", + "port_policy_redacted", + "service_dependency_present", + "public_route_impact_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "customer_product_impact_present", + "operator_notification_present", + "cross_project_sync_present", + "restoration_evidence_present", + "postcheck_independent", + "recurrence_guard_present", + "emergency_classification_present", + "maintenance_window_present", + "rollback_owner_present", + "no_false_green_route_200", + "raw_firewall_dump_absent", + "secret_or_key_value_absent", + "hidden_impact_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_dependency_accepted": false, + "service_dependency_ref": null, + "source_change_evidence_candidate_id": "port_firewall_change_evidence:alert_rules_ssh_actions", + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_post_incident_readback", + "surface_id": "alert_rules_ssh_actions", + "wireguard_change_authorized": false, + "write_capable_surface": true + } + ], + "required_readback_fields": [ + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation" + ], + "reviewer_checks": [ + { + "check_id": "source_change_evidence_current", + "instruction": "來源 change evidence snapshot 必須是目前版本。" + }, + { + "check_id": "incident_ref_present", + "instruction": "必須有可追溯 incident / change ref。" + }, + { + "check_id": "actor_not_anonymous", + "instruction": "必須標示 actor role / team,不接受匿名端口關閉。" + }, + { + "check_id": "before_after_state_present", + "instruction": "必須有變更前與恢復後狀態 ref。" + }, + { + "check_id": "port_policy_redacted", + "instruction": "端口、policy、host 只收脫敏 ref 或 alias,不保存 raw dump。" + }, + { + "check_id": "service_dependency_present", + "instruction": "必須列出受影響服務、agent、public route、monitoring 或 deploy path。" + }, + { + "check_id": "public_route_impact_present", + "instruction": "必須列出 public route / admin route / callback 影響 ref。" + }, + { + "check_id": "ai_provider_impact_present", + "instruction": "若影響 Ollama / provider health,需列出脫敏 impact ref。" + }, + { + "check_id": "monitoring_alert_impact_present", + "instruction": "必須列出 alert / SRE / dashboard 影響與 false-green 風險。" + }, + { + "check_id": "customer_product_impact_present", + "instruction": "需標示產品或使用者影響,不得只寫已恢復。" + }, + { + "check_id": "operator_notification_present", + "instruction": "必須有受影響 owner / Session / product 的通知 ref。" + }, + { + "check_id": "cross_project_sync_present", + "instruction": "跨專案同步 ref 必須存在,避免單點修改。" + }, + { + "check_id": "restoration_evidence_present", + "instruction": "必須有恢復時間與恢復證據 ref。" + }, + { + "check_id": "postcheck_independent", + "instruction": "post-check 需獨立於原操作人與 UI 卡片。" + }, + { + "check_id": "recurrence_guard_present", + "instruction": "必須提出防再發 guard、change freeze 或 owner review。" + }, + { + "check_id": "emergency_classification_present", + "instruction": "緊急破窗需標示分類與事後補件責任。" + }, + { + "check_id": "maintenance_window_present", + "instruction": "後續任何 port / firewall 操作都需維護窗口。" + }, + { + "check_id": "rollback_owner_present", + "instruction": "rollback owner 與回復 plan 必須同時存在。" + }, + { + "check_id": "no_false_green_route_200", + "instruction": "不得只用 route 200 / service up 當成事故已驗收。" + }, + { + "check_id": "raw_firewall_dump_absent", + "instruction": "不得保存 raw firewall dump、raw iptables、raw nftables 或 raw ACL。" + }, + { + "check_id": "secret_or_key_value_absent", + "instruction": "不得包含 secret、SSH key、token、cookie、私鑰或 partial secret。" + }, + { + "check_id": "hidden_impact_absent", + "instruction": "不得隱藏 AI provider、registry、monitoring、deploy 或 product route 影響。" + }, + { + "check_id": "counts_transition_safe", + "instruction": "只有 reviewer record 能更新 accepted count,且不得同時開 runtime gate。" + }, + { + "check_id": "runtime_stays_zero", + "instruction": "readback plan 不得觸發任何 SSH、firewall、route smoke、restart 或 production write。" + } + ], + "schema_version": "ssh_network_post_incident_readback_plan_v1", + "source_paths": [ + "docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/port-firewall-change-evidence-acceptance.snapshot.json", + "docs/security/SSH-NETWORK-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/ssh-network-owner-response-acceptance.snapshot.json" + ], + "source_schema_version": "port_firewall_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, + "ai_provider_impact_accepted_count": 0, + "before_after_state_accepted_count": 0, + "blocked_action_count": 34, + "coverage_percent_after_readback_plan": 64, + "cross_project_sync_accepted_count": 0, + "cross_project_sync_required_candidate_count": 14, + "health_impact_review_required_candidate_count": 14, + "monitoring_alert_impact_accepted_count": 0, + "no_false_green_accepted_count": 0, + "operator_notification_accepted_count": 0, + "outcome_lane_count": 10, + "policy_or_exposure_readback_candidate_count": 5, + "post_incident_readback_accepted_count": 0, + "post_incident_readback_received_count": 0, + "postcheck_readback_accepted_count": 0, + "public_route_impact_accepted_count": 0, + "readback_candidate_count": 14, + "readback_field_count": 30, + "recurrence_guard_accepted_count": 0, + "recurrence_guard_required_candidate_count": 14, + "required_readback_field_count": 24, + "restoration_evidence_accepted_count": 0, + "reviewer_check_count": 24, + "runtime_gate_count": 0, + "service_dependency_accepted_count": 0, + "write_capable_readback_candidate_count": 6 + } +} diff --git a/scripts/security/high-value-config-control-coverage.py b/scripts/security/high-value-config-control-coverage.py index 11ee8cde5..9cb7003eb 100644 --- a/scripts/security/high-value-config-control-coverage.py +++ b/scripts/security/high-value-config-control-coverage.py @@ -175,8 +175,8 @@ CONTROL_STATUS_BY_CATEGORY = { "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。", }, "ssh_firewall_network_access": { - "coverage_status": "incident_change_evidence_acceptance_ready_needs_network_owner_evidence", - "coverage_percent": 62, + "coverage_status": "post_incident_readback_plan_ready_needs_network_owner_evidence", + "coverage_percent": 64, "evidence_refs": [ "docs/HARD_RULES.md", "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md", @@ -188,9 +188,11 @@ CONTROL_STATUS_BY_CATEGORY = { "docs/security/ssh-network-owner-response-acceptance.snapshot.json", "docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/port-firewall-change-evidence-acceptance.snapshot.json", + "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/ssh-network-post-incident-readback-plan.snapshot.json", ], - "current_gap": "owner response acceptance 帳本已固定 16 個 SSH / network acceptance candidate,端口 / 防火牆事故型變更證據驗收帳本已固定 14 個 change evidence candidate;仍缺 owner-provided change / incident evidence、actor、before / after state、service health impact、operator notification、cross-project sync、maintenance window、rollback owner 與 post-check evidence。", - "next_owner_action": "補端口 / 防火牆變更的 change / incident ref、actor role / team、affected scope、before / after state、service dependency、customer impact、service health impact、operator notification、cross-project sync、rollback owner 與 post-check 指標。", + "current_gap": "owner response acceptance、端口 / 防火牆事故型變更證據驗收與 post-incident readback plan 都已固定;仍缺 owner-provided change / incident evidence、actor、before / after state、service / AI provider / monitoring impact、operator notification、cross-project sync、restoration evidence、recurrence guard、maintenance window、rollback owner 與 post-check evidence。", + "next_owner_action": "補端口 / 防火牆事故回讀包:change / incident ref、actor role / team、affected scope、before / after state、service dependency、public route impact、AI provider impact、monitoring alert impact、operator notification、cross-project sync、restoration evidence、recurrence guard、rollback owner 與 post-check 指標。", }, "ai_provider_model_routing": { "coverage_status": "owner_response_acceptance_ready_needs_provider_owner_evidence", @@ -389,6 +391,7 @@ def build_report(root: Path, generated_at: str | None) -> dict[str, Any]: "alert_chain_no_false_green_backfill_ready_needs_live_evidence_receipt", "change_evidence_acceptance_ready_needs_network_owner_evidence", "incident_change_evidence_acceptance_ready_needs_network_owner_evidence", + "post_incident_readback_plan_ready_needs_network_owner_evidence", "policy_ready_needs_drift_evidence", "inventory_needed", "repo_only_inventory_ready_needs_live_owner_evidence", diff --git a/scripts/security/iwooos-config-control-guard.py b/scripts/security/iwooos-config-control-guard.py index c3bb2b554..bd51afaf2 100644 --- a/scripts/security/iwooos-config-control-guard.py +++ b/scripts/security/iwooos-config-control-guard.py @@ -27,7 +27,7 @@ EXPECTED_CATEGORIES = { "agent_bounty_protocol_runtime": 68, "monitoring_alerting_observability": 68, "docker_compose_systemd_host_config": 62, - "ssh_firewall_network_access": 62, + "ssh_firewall_network_access": 64, "ai_provider_model_routing": 64, "product_surface_runtime_routes": 72, "security_evidence_tooling": 86, @@ -55,6 +55,7 @@ REQUIRED_CONTROL_DOCS = [ "docs/security/HOST-SERVICE-CHANGE-EVIDENCE-ACCEPTANCE.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", "docs/security/BACKUP-RESTORE-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/K8S-ARGOCD-CHANGE-EVIDENCE-ACCEPTANCE.md", @@ -262,6 +263,49 @@ ARTIFACT_SPECS = [ "runtime_gate_count": 0, }, }, + { + "label": "ssh network post incident readback plan", + "path": "docs/security/ssh-network-post-incident-readback-plan.snapshot.json", + "schema": "ssh_network_post_incident_readback_plan_v1", + "status": "post_incident_readback_plan_ready_no_runtime_action", + "list_counts": { + "readback_candidates": 14, + "blocked_actions": 34, + "reviewer_checks": 24, + "outcome_lanes": 10, + "required_readback_fields": 24, + }, + "summary_counts": { + "readback_candidate_count": 14, + "write_capable_readback_candidate_count": 6, + "policy_or_exposure_readback_candidate_count": 5, + "health_impact_review_required_candidate_count": 14, + "cross_project_sync_required_candidate_count": 14, + "recurrence_guard_required_candidate_count": 14, + "readback_field_count": 30, + "required_readback_field_count": 24, + "reviewer_check_count": 24, + "outcome_lane_count": 10, + "blocked_action_count": 34, + "post_incident_readback_received_count": 0, + "post_incident_readback_accepted_count": 0, + "actor_attribution_accepted_count": 0, + "before_after_state_accepted_count": 0, + "service_dependency_accepted_count": 0, + "public_route_impact_accepted_count": 0, + "ai_provider_impact_accepted_count": 0, + "monitoring_alert_impact_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": "backup restore owner response acceptance", "path": "docs/security/backup-restore-owner-response-acceptance.snapshot.json", diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 1cf1f92f3..36724022d 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -163,6 +163,9 @@ def validate(root: Path) -> None: port_firewall_change_evidence_acceptance = load_json( security_dir / "port-firewall-change-evidence-acceptance.snapshot.json" ) + ssh_network_post_incident_readback_plan = load_json( + security_dir / "ssh-network-post-incident-readback-plan.snapshot.json" + ) backup_restore_escrow_inventory = load_json(security_dir / "backup-restore-escrow-inventory.snapshot.json") backup_restore_owner_request_draft = load_json( security_dir / "backup-restore-owner-request-draft.snapshot.json" @@ -3205,12 +3208,12 @@ def validate(root: Path) -> None: assert_equal( "high_value_config_coverage.coverage_categories.ssh_network.coverage_percent", ssh_network_category["coverage_percent"], - 62, + 64, ) assert_equal( "high_value_config_coverage.coverage_categories.ssh_network.coverage_status", ssh_network_category["coverage_status"], - "incident_change_evidence_acceptance_ready_needs_network_owner_evidence", + "post_incident_readback_plan_ready_needs_network_owner_evidence", ) for evidence_ref in [ "docs/security/SSH-NETWORK-ACCESS-INVENTORY.md", @@ -3219,6 +3222,8 @@ def validate(root: Path) -> None: "docs/security/ssh-network-owner-response-acceptance.snapshot.json", "docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/port-firewall-change-evidence-acceptance.snapshot.json", + "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/ssh-network-post-incident-readback-plan.snapshot.json", ]: assert_contains( "high_value_config_coverage.coverage_categories.ssh_network.evidence_refs", @@ -4611,6 +4616,220 @@ def validate(root: Path) -> None: f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.{false_key}", item[false_key], ) + assert_equal( + "ssh_network_post_incident_readback_plan.schema", + ssh_network_post_incident_readback_plan["schema_version"], + "ssh_network_post_incident_readback_plan_v1", + ) + assert_equal( + "ssh_network_post_incident_readback_plan.status", + ssh_network_post_incident_readback_plan["status"], + "post_incident_readback_plan_ready_no_runtime_action", + ) + assert_equal( + "ssh_network_post_incident_readback_plan.source_schema_version", + ssh_network_post_incident_readback_plan["source_schema_version"], + "port_firewall_change_evidence_acceptance_v1", + ) + assert_equal( + "ssh_network_post_incident_readback_plan.source_status", + ssh_network_post_incident_readback_plan["source_status"], + "change_evidence_acceptance_ready_no_runtime_action", + ) + expected_ssh_network_post_incident_readback_summary = { + "readback_candidate_count": 14, + "write_capable_readback_candidate_count": 6, + "policy_or_exposure_readback_candidate_count": 5, + "health_impact_review_required_candidate_count": 14, + "cross_project_sync_required_candidate_count": 14, + "recurrence_guard_required_candidate_count": 14, + "readback_field_count": 30, + "required_readback_field_count": 24, + "reviewer_check_count": 24, + "outcome_lane_count": 10, + "blocked_action_count": 34, + "post_incident_readback_received_count": 0, + "post_incident_readback_accepted_count": 0, + "actor_attribution_accepted_count": 0, + "before_after_state_accepted_count": 0, + "service_dependency_accepted_count": 0, + "public_route_impact_accepted_count": 0, + "ai_provider_impact_accepted_count": 0, + "monitoring_alert_impact_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_ssh_network_post_incident_readback_summary.items(): + assert_equal( + f"ssh_network_post_incident_readback_plan.summary.{key}", + ssh_network_post_incident_readback_plan["summary"][key], + expected, + ) + for key, value in ssh_network_post_incident_readback_plan["boundaries"].items(): + if key == "not_authorization": + assert_true(f"ssh_network_post_incident_readback_plan.boundaries.{key}", value) + else: + assert_false(f"ssh_network_post_incident_readback_plan.boundaries.{key}", value) + assert_equal( + "ssh_network_post_incident_readback_plan.readback_candidates.count", + len(ssh_network_post_incident_readback_plan["readback_candidates"]), + 14, + ) + ssh_network_post_incident_readback_ids = [ + item["readback_candidate_id"] + for item in ssh_network_post_incident_readback_plan["readback_candidates"] + ] + for readback_candidate_id in [ + "ssh_network_post_incident_readback:gitea_cd_deploy_ssh", + "ssh_network_post_incident_readback:deploy_alerts_ssh_path", + "ssh_network_post_incident_readback:argocd_metrics_nodeport", + "ssh_network_post_incident_readback:velero_metrics_nodeport", + "ssh_network_post_incident_readback:wireguard_mesh_runbook", + "ssh_network_post_incident_readback:alert_rules_ssh_actions", + ]: + assert_contains( + "ssh_network_post_incident_readback_plan.readback_candidates", + ssh_network_post_incident_readback_ids, + readback_candidate_id, + ) + assert_equal( + "ssh_network_post_incident_readback_plan.reviewer_checks.count", + len(ssh_network_post_incident_readback_plan["reviewer_checks"]), + 24, + ) + assert_equal( + "ssh_network_post_incident_readback_plan.outcome_lanes.count", + len(ssh_network_post_incident_readback_plan["outcome_lanes"]), + 10, + ) + assert_equal( + "ssh_network_post_incident_readback_plan.blocked_actions.count", + len(ssh_network_post_incident_readback_plan["blocked_actions"]), + 34, + ) + for item in ssh_network_post_incident_readback_plan["readback_candidates"]: + assert_equal( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.readback_fields", + len(item["readback_fields"]), + 30, + ) + assert_equal( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.required_readback_fields", + len(item["required_readback_fields"]), + 24, + ) + assert_equal( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.reviewer_checks", + len(item["reviewer_checks"]), + 24, + ) + assert_equal( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.outcome_lanes", + len(item["outcome_lanes"]), + 10, + ) + assert_equal( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.blocked_actions", + len(item["blocked_actions"]), + 34, + ) + for required_field in [ + "actor_attribution_ref", + "before_state_ref", + "after_state_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "cross_project_sync_ref", + "restoration_evidence_ref", + "recurrence_guard_ref", + "no_false_green_attestation", + ]: + assert_contains( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.required_readback_fields", + item["required_readback_fields"], + required_field, + ) + for reviewer_check in [ + "actor_not_anonymous", + "before_after_state_present", + "ai_provider_impact_present", + "monitoring_alert_impact_present", + "cross_project_sync_present", + "recurrence_guard_present", + "no_false_green_route_200", + "runtime_stays_zero", + ]: + assert_contains( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.reviewer_checks", + item["reviewer_checks"], + reviewer_check, + ) + for blocked_action in [ + "live_firewall_read", + "firewall_change", + "port_close", + "route_smoke", + "host_restart", + "treat_route_200_as_all_green", + "close_management_port_without_owner", + "open_runtime_gate", + ]: + assert_contains( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.blocked_actions", + item["blocked_actions"], + blocked_action, + ) + assert_true( + f"ssh_network_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", + "service_dependency_accepted", + "public_route_impact_accepted", + "ai_provider_impact_accepted", + "monitoring_alert_impact_accepted", + "operator_notification_accepted", + "cross_project_sync_accepted", + "restoration_evidence_accepted", + "postcheck_readback_accepted", + "recurrence_guard_accepted", + "no_false_green_accepted", + "ssh_read_authorized", + "ssh_write_authorized", + "live_firewall_read_authorized", + "firewall_change_authorized", + "port_change_authorized", + "port_close_authorized", + "port_open_authorized", + "network_policy_apply_authorized", + "nodeport_change_authorized", + "wireguard_change_authorized", + "route_smoke_authorized", + "host_restart_authorized", + "secret_value_collection_allowed", + "runtime_gate", + "production_write_authorized", + "active_scan_authorized", + "provider_switch_authorized", + "prompt_send_authorized", + "action_buttons_allowed", + ]: + assert_false( + f"ssh_network_post_incident_readback_plan.{item['readback_candidate_id']}.{false_key}", + item[false_key], + ) assert_equal( "backup_restore_escrow_inventory.schema", backup_restore_escrow_inventory["schema_version"], @@ -6761,6 +6980,8 @@ def validate(root: Path) -> None: "docs/security/SSH-NETWORK-ACCESS-INVENTORY.md", "docs/security/port-firewall-change-evidence-acceptance.snapshot.json", "docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/ssh-network-post-incident-readback-plan.snapshot.json", + "docs/security/SSH-NETWORK-POST-INCIDENT-READBACK-PLAN.md", "docs/schemas/ssh_network_access_inventory_v1.schema.json", "docs/security/backup-restore-escrow-inventory.snapshot.json", "docs/security/BACKUP-RESTORE-ESCROW-INVENTORY.md", @@ -6955,6 +7176,35 @@ def validate(root: Path) -> None: "port_firewall_change_evidence_acceptance_runtime_gate_count": 0, "port_firewall_change_evidence_acceptance_action_button_count": 0, "port_firewall_change_evidence_acceptance_coverage_percent_after_acceptance": 62, + "ssh_network_post_incident_readback_plan_first_layer": True, + "ssh_network_post_incident_readback_plan_candidate_count": 14, + "ssh_network_post_incident_readback_plan_write_capable_candidate_count": 6, + "ssh_network_post_incident_readback_plan_policy_or_exposure_candidate_count": 5, + "ssh_network_post_incident_readback_plan_health_impact_review_required_candidate_count": 14, + "ssh_network_post_incident_readback_plan_cross_project_sync_required_candidate_count": 14, + "ssh_network_post_incident_readback_plan_recurrence_guard_required_candidate_count": 14, + "ssh_network_post_incident_readback_plan_readback_field_count": 30, + "ssh_network_post_incident_readback_plan_required_readback_field_count": 24, + "ssh_network_post_incident_readback_plan_reviewer_check_count": 24, + "ssh_network_post_incident_readback_plan_outcome_lane_count": 10, + "ssh_network_post_incident_readback_plan_blocked_action_count": 34, + "ssh_network_post_incident_readback_plan_post_incident_readback_received_count": 0, + "ssh_network_post_incident_readback_plan_post_incident_readback_accepted_count": 0, + "ssh_network_post_incident_readback_plan_actor_attribution_accepted_count": 0, + "ssh_network_post_incident_readback_plan_before_after_state_accepted_count": 0, + "ssh_network_post_incident_readback_plan_service_dependency_accepted_count": 0, + "ssh_network_post_incident_readback_plan_public_route_impact_accepted_count": 0, + "ssh_network_post_incident_readback_plan_ai_provider_impact_accepted_count": 0, + "ssh_network_post_incident_readback_plan_monitoring_alert_impact_accepted_count": 0, + "ssh_network_post_incident_readback_plan_operator_notification_accepted_count": 0, + "ssh_network_post_incident_readback_plan_cross_project_sync_accepted_count": 0, + "ssh_network_post_incident_readback_plan_restoration_evidence_accepted_count": 0, + "ssh_network_post_incident_readback_plan_postcheck_readback_accepted_count": 0, + "ssh_network_post_incident_readback_plan_recurrence_guard_accepted_count": 0, + "ssh_network_post_incident_readback_plan_no_false_green_accepted_count": 0, + "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, "k8s_argocd_change_evidence_acceptance_first_layer": True, "k8s_argocd_change_evidence_acceptance_candidate_count": 4, "k8s_argocd_change_evidence_acceptance_c0_candidate_count": 3, @@ -16763,7 +17013,7 @@ def validate(root: Path) -> None: assert_text_contains( "iwooos_page.high_value_config_control_coverage_ssh_network_percent", iwooos_projection_page, - "{ key: 'sshNetwork', rank: 'P1-2', value: '62%'", + "{ key: 'sshNetwork', rank: 'P1-2', value: '64%'", ) assert_text_contains( "iwooos_page.high_value_config_control_coverage_ai_provider_percent", @@ -16937,6 +17187,24 @@ def validate(root: Path) -> None: "port_firewall_change_evidence_acceptance_cross_project_sync_accepted_count=0", "port_firewall_change_evidence_acceptance_postcheck_evidence_accepted_count=0", "port_firewall_change_evidence_acceptance_runtime_gate_count=0", + "ssh_network_post_incident_readback_plan_candidate_count=14", + "ssh_network_post_incident_readback_plan_write_capable_candidate_count=6", + "ssh_network_post_incident_readback_plan_policy_or_exposure_candidate_count=5", + "ssh_network_post_incident_readback_plan_required_readback_field_count=24", + "ssh_network_post_incident_readback_plan_reviewer_check_count=24", + "ssh_network_post_incident_readback_plan_outcome_lane_count=10", + "ssh_network_post_incident_readback_plan_blocked_action_count=34", + "ssh_network_post_incident_readback_plan_post_incident_readback_received_count=0", + "ssh_network_post_incident_readback_plan_post_incident_readback_accepted_count=0", + "ssh_network_post_incident_readback_plan_actor_attribution_accepted_count=0", + "ssh_network_post_incident_readback_plan_before_after_state_accepted_count=0", + "ssh_network_post_incident_readback_plan_public_route_impact_accepted_count=0", + "ssh_network_post_incident_readback_plan_ai_provider_impact_accepted_count=0", + "ssh_network_post_incident_readback_plan_monitoring_alert_impact_accepted_count=0", + "ssh_network_post_incident_readback_plan_cross_project_sync_accepted_count=0", + "ssh_network_post_incident_readback_plan_recurrence_guard_accepted_count=0", + "ssh_network_post_incident_readback_plan_no_false_green_accepted_count=0", + "ssh_network_post_incident_readback_plan_runtime_gate_count=0", "backup_restore_escrow_inventory_surface_count=38", "backup_restore_escrow_inventory_write_capable_surface_count=27", "backup_restore_escrow_inventory_runtime_gate_count=0", @@ -17420,12 +17688,12 @@ def validate(root: Path) -> None: assert_text_contains( "web_messages.zh-TW.iwooos.highValueConfigControlCoverage.items.sshNetwork.body", web_messages_zh["iwooos"]["highValueConfigControlCoverage"]["items"]["sshNetwork"]["body"], - "16 個 SSH / network access surface", + "14 個事故回讀候選、24 個 reviewer checks、10 條 outcome lanes、34 類 blocked action", ) assert_text_contains( "web_messages.en.iwooos.highValueConfigControlCoverage.items.sshNetwork.body", web_messages_en["iwooos"]["highValueConfigControlCoverage"]["items"]["sshNetwork"]["body"], - "16 個 SSH / network access surface", + "14 個事故回讀候選、24 個 reviewer checks、10 條 outcome lanes、34 類 blocked action", ) assert_text_contains( "web_messages.zh-TW.iwooos.highValueConfigControlCoverage.items.backupRestore.body", diff --git a/scripts/security/ssh-network-post-incident-readback-plan.py b/scripts/security/ssh-network-post-incident-readback-plan.py new file mode 100644 index 000000000..2fcae996b --- /dev/null +++ b/scripts/security/ssh-network-post-incident-readback-plan.py @@ -0,0 +1,382 @@ +#!/usr/bin/env python3 +""" +IwoooS SSH / network / firewall post-incident readback 只讀計畫產生器。 + +本工具讀取端口 / 防火牆變更證據驗收 snapshot,建立事故後回讀計畫: +誰改、何時改、改前改後、影響哪些服務 / AI provider / public route / +monitoring、是否同步相關產品、如何恢復、如何防再發。它不 SSH、不讀 live +firewall、不改 port、不做 route smoke、不重啟服務、不打 provider endpoint, +也不把事故恢復誤判成 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", + "config_kind", + "control_tier", + "expected_scope", + "write_capable_surface", + "policy_or_exposure_surface", + "change_or_incident_ref", + "actor_attribution_ref", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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", + "incident_detected_at_ref", + "change_window_ref", + "affected_port_or_policy_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "public_route_impact_ref", + "ai_provider_impact_ref", + "monitoring_alert_impact_ref", + "customer_or_product_impact_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_firewall_dump_attestation", + "no_false_green_attestation", +] + +REVIEWER_CHECKS = [ + {"check_id": "source_change_evidence_current", "instruction": "來源 change evidence snapshot 必須是目前版本。"}, + {"check_id": "incident_ref_present", "instruction": "必須有可追溯 incident / change ref。"}, + {"check_id": "actor_not_anonymous", "instruction": "必須標示 actor role / team,不接受匿名端口關閉。"}, + {"check_id": "before_after_state_present", "instruction": "必須有變更前與恢復後狀態 ref。"}, + {"check_id": "port_policy_redacted", "instruction": "端口、policy、host 只收脫敏 ref 或 alias,不保存 raw dump。"}, + {"check_id": "service_dependency_present", "instruction": "必須列出受影響服務、agent、public route、monitoring 或 deploy path。"}, + {"check_id": "public_route_impact_present", "instruction": "必須列出 public route / admin route / callback 影響 ref。"}, + {"check_id": "ai_provider_impact_present", "instruction": "若影響 Ollama / provider health,需列出脫敏 impact ref。"}, + {"check_id": "monitoring_alert_impact_present", "instruction": "必須列出 alert / SRE / dashboard 影響與 false-green 風險。"}, + {"check_id": "customer_product_impact_present", "instruction": "需標示產品或使用者影響,不得只寫已恢復。"}, + {"check_id": "operator_notification_present", "instruction": "必須有受影響 owner / Session / product 的通知 ref。"}, + {"check_id": "cross_project_sync_present", "instruction": "跨專案同步 ref 必須存在,避免單點修改。"}, + {"check_id": "restoration_evidence_present", "instruction": "必須有恢復時間與恢復證據 ref。"}, + {"check_id": "postcheck_independent", "instruction": "post-check 需獨立於原操作人與 UI 卡片。"}, + {"check_id": "recurrence_guard_present", "instruction": "必須提出防再發 guard、change freeze 或 owner review。"}, + {"check_id": "emergency_classification_present", "instruction": "緊急破窗需標示分類與事後補件責任。"}, + {"check_id": "maintenance_window_present", "instruction": "後續任何 port / firewall 操作都需維護窗口。"}, + {"check_id": "rollback_owner_present", "instruction": "rollback owner 與回復 plan 必須同時存在。"}, + {"check_id": "no_false_green_route_200", "instruction": "不得只用 route 200 / service up 當成事故已驗收。"}, + {"check_id": "raw_firewall_dump_absent", "instruction": "不得保存 raw firewall dump、raw iptables、raw nftables 或 raw ACL。"}, + {"check_id": "secret_or_key_value_absent", "instruction": "不得包含 secret、SSH key、token、cookie、私鑰或 partial secret。"}, + {"check_id": "hidden_impact_absent", "instruction": "不得隱藏 AI provider、registry、monitoring、deploy 或 product route 影響。"}, + {"check_id": "counts_transition_safe", "instruction": "只有 reviewer record 能更新 accepted count,且不得同時開 runtime gate。"}, + {"check_id": "runtime_stays_zero", "instruction": "readback plan 不得觸發任何 SSH、firewall、route smoke、restart 或 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 或 restoration evidence 時要求補件。"}, + {"lane_id": "request_health_impact_supplement", "meaning": "缺 service / AI provider / monitoring / product impact 時要求補件。"}, + {"lane_id": "quarantine_raw_payload", "meaning": "收到 raw firewall dump、secret 或 key material 時只能隔離。"}, + {"lane_id": "reject_unattributed_incident", "meaning": "無 actor、無 affected scope、無 rollback 或無 notification 的事故回讀不得驗收。"}, + {"lane_id": "ready_for_post_incident_review", "meaning": "metadata 合格後,只能進 reviewer review。"}, + {"lane_id": "incident_readback_only_update", "meaning": "只允許更新只讀 ledger,不得反向視為已批准操作。"}, + {"lane_id": "recurrence_guard_backfill_required", "meaning": "需補防再發 guard、owner review 與 change freeze。"}, + {"lane_id": "waiting_runtime_gate", "meaning": "即使 readback accepted,runtime gate 仍需獨立人工批准。"}, +] + +BLOCKED_ACTIONS = [ + "ssh_read", + "ssh_write", + "live_firewall_read", + "firewall_change", + "port_change", + "port_close", + "port_open", + "network_policy_apply", + "nodeport_change", + "wireguard_change", + "sudo_action", + "deploy_ssh_action", + "route_smoke", + "public_gateway_reload", + "nginx_reload", + "host_restart", + "docker_restart", + "systemd_restart", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_readback_accepted_without_reviewer_record", + "mark_incident_resolved_without_postcheck", + "hide_cross_project_impact", + "treat_route_200_as_all_green", + "treat_break_glass_as_approval", + "close_management_port_without_owner", + "open_runtime_gate", + "add_action_button", + "production_write", + "active_scan", + "provider_switch", + "prompt_send", +] + + +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 is_policy_or_exposure(source: dict[str, Any]) -> bool: + return source.get("config_kind") in { + "k8s_network_policy", + "k8s_nodeport_service", + "wireguard_runbook", + } + + +def build_candidate(source: dict[str, Any]) -> dict[str, Any]: + surface_id = source["surface_id"] + return { + "readback_candidate_id": f"ssh_network_post_incident_readback:{surface_id}", + "status": "waiting_post_incident_readback", + "source_change_evidence_candidate_id": source["change_evidence_candidate_id"], + "surface_id": surface_id, + "config_kind": source["config_kind"], + "control_tier": source["control_tier"], + "expected_scope": source.get("expected_scope"), + "write_capable_surface": source["write_capable_surface"], + "policy_or_exposure_surface": is_policy_or_exposure(source), + "change_or_incident_ref": None, + "actor_attribution_ref": None, + "incident_detected_at_ref": None, + "change_window_ref": None, + "affected_port_or_policy_ref": None, + "before_state_ref": None, + "after_state_ref": None, + "service_dependency_ref": None, + "public_route_impact_ref": None, + "ai_provider_impact_ref": None, + "monitoring_alert_impact_ref": None, + "customer_or_product_impact_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, + "service_dependency_accepted": False, + "public_route_impact_accepted": False, + "ai_provider_impact_accepted": False, + "monitoring_alert_impact_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_firewall_read_authorized": False, + "firewall_change_authorized": False, + "port_change_authorized": False, + "port_close_authorized": False, + "port_open_authorized": False, + "network_policy_apply_authorized": False, + "nodeport_change_authorized": False, + "wireguard_change_authorized": False, + "route_smoke_authorized": False, + "host_restart_authorized": False, + "secret_value_collection_allowed": False, + "active_scan_authorized": False, + "provider_switch_authorized": False, + "prompt_send_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"]] + policy_or_exposure = [item for item in readback_candidates if item["policy_or_exposure_surface"]] + + return { + "schema_version": "ssh_network_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/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/port-firewall-change-evidence-acceptance.snapshot.json", + "docs/security/SSH-NETWORK-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/ssh-network-owner-response-acceptance.snapshot.json", + ], + "summary": { + "readback_candidate_count": len(readback_candidates), + "write_capable_readback_candidate_count": len(write_capable), + "policy_or_exposure_readback_candidate_count": len(policy_or_exposure), + "health_impact_review_required_candidate_count": len(readback_candidates), + "cross_project_sync_required_candidate_count": len(readback_candidates), + "recurrence_guard_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, + "service_dependency_accepted_count": 0, + "public_route_impact_accepted_count": 0, + "ai_provider_impact_accepted_count": 0, + "monitoring_alert_impact_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_firewall_read_authorized": False, + "firewall_change_authorized": False, + "port_change_authorized": False, + "port_close_authorized": False, + "port_open_authorized": False, + "network_policy_apply_authorized": False, + "nodeport_change_authorized": False, + "wireguard_change_authorized": False, + "route_smoke_authorized": False, + "host_restart_authorized": False, + "secret_value_collection_allowed": False, + "active_scan_authorized": False, + "provider_switch_authorized": False, + "prompt_send_authorized": 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/port-firewall-change-evidence-acceptance.snapshot.json", + ) + parser.add_argument( + "--output", + default="docs/security/ssh-network-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( + "SSH_NETWORK_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())