From 471054b8f4c65d2794a881cb277a5dd22c1988f4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 Jun 2026 01:40:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(iwooos):=20=E6=96=B0=E5=A2=9E=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E9=98=B2=E7=81=AB=E7=89=86=E8=AE=8A=E6=9B=B4=E8=AD=89?= =?UTF-8?q?=E6=93=9A=E9=A9=97=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/messages/en.json | 2 +- apps/web/messages/zh-TW.json | 2 +- apps/web/src/app/[locale]/iwooos/page.tsx | 18 +- .../HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md | 10 +- .../IWOOOS-CONFIG-CONTROL-INVENTORY.md | 7 +- docs/security/IWOOOS-POSTURE-PROJECTION.md | 2 +- ...ORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md | 161 + .../SECURITY-SUPPLY-CHAIN-PROGRESS.md | 10 +- ...alue-config-control-coverage.snapshot.json | 22 +- .../iwooos-posture-projection.snapshot.json | 18 + ...l-change-evidence-acceptance.snapshot.json | 2861 +++++++++++++++++ ...-04-15-MASTER-ai-autonomous-flywheel-v2.md | 12 + .../high-value-config-control-coverage.py | 11 +- ...ort-firewall-change-evidence-acceptance.py | 410 +++ .../security-mirror-progress-guard.py | 246 +- 15 files changed, 3766 insertions(+), 26 deletions(-) create mode 100644 docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md create mode 100644 docs/security/port-firewall-change-evidence-acceptance.snapshot.json create mode 100644 scripts/security/port-firewall-change-evidence-acceptance.py diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index da65c94a8..91a7391b5 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -17815,7 +17815,7 @@ }, "sshNetwork": { "title": "SSH / network / firewall", - "body": "repo-only 清冊已納入 16 個 SSH / network access surface,且 owner response acceptance 只讀帳本已固定 16 個候選;下一步仍需 owner response、live access state、allowed source CIDR、host key pinning、port impact、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 validation plan。" + "body": "repo-only 清冊已納入 16 個 SSH / network access surface,且 owner response acceptance 與端口 / 防火牆變更證據驗收只讀帳本已固定;下一步仍需 change / incident ref、actor、before / after state、service impact、cross-project sync、maintenance window、rollback owner 與 post-check evidence。" }, "backupRestore": { "title": "備份 / 還原 / 金庫", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index da65c94a8..91a7391b5 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -17815,7 +17815,7 @@ }, "sshNetwork": { "title": "SSH / network / firewall", - "body": "repo-only 清冊已納入 16 個 SSH / network access surface,且 owner response acceptance 只讀帳本已固定 16 個候選;下一步仍需 owner response、live access state、allowed source CIDR、host key pinning、port impact、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 validation plan。" + "body": "repo-only 清冊已納入 16 個 SSH / network access surface,且 owner response acceptance 與端口 / 防火牆變更證據驗收只讀帳本已固定;下一步仍需 change / incident ref、actor、before / after state、service impact、cross-project sync、maintenance window、rollback owner 與 post-check evidence。" }, "backupRestore": { "title": "備份 / 還原 / 金庫", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index a51ed782d..6b70de36a 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: '54%', icon: Server, tone: 'warn' }, - { key: 'sshNetwork', rank: 'P1-2', value: '58%', icon: Network, tone: 'warn' }, + { key: 'sshNetwork', rank: 'P1-2', value: '60%', icon: Network, tone: 'warn' }, { key: 'backupRestore', rank: 'P1-3', value: '62%', icon: Database, tone: 'warn' }, { key: 'monitoring', rank: 'P1-4', value: '62%', icon: Radar, tone: 'warn' }, ] @@ -2136,6 +2136,19 @@ const highValueConfigControlCoverageBoundaries = [ 'ssh_network_owner_response_acceptance_firewall_owner_accepted_count=0', 'ssh_network_owner_response_acceptance_port_policy_accepted_count=0', 'ssh_network_owner_response_acceptance_wireguard_cutover_accepted_count=0', + 'port_firewall_change_evidence_acceptance_candidate_count=14', + 'port_firewall_change_evidence_acceptance_write_capable_candidate_count=6', + 'port_firewall_change_evidence_acceptance_policy_or_exposure_candidate_count=5', + 'port_firewall_change_evidence_acceptance_required_evidence_field_count=16', + 'port_firewall_change_evidence_acceptance_reviewer_check_count=16', + 'port_firewall_change_evidence_acceptance_outcome_lane_count=8', + 'port_firewall_change_evidence_acceptance_blocked_action_count=24', + 'port_firewall_change_evidence_acceptance_received_count=0', + 'port_firewall_change_evidence_acceptance_accepted_count=0', + 'port_firewall_change_evidence_acceptance_actor_identified_count=0', + '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', 'backup_restore_escrow_inventory_surface_count=38', 'backup_restore_escrow_inventory_write_capable_surface_count=27', 'backup_restore_escrow_inventory_runtime_gate_count=0', @@ -2159,6 +2172,9 @@ const highValueConfigControlCoverageBoundaries = [ 'ssh_write_authorized=false', 'sudo_action_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', diff --git a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md index c2504e870..3940c1119 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -64,6 +64,12 @@ 固定數字為 `acceptance_candidate_count=9`、`write_capable_acceptance_candidate_count=3`、`live_evidence_required_candidate_count=8`、`acceptance_field_count=28`、`required_owner_field_count=12`、`reviewer_check_count=14`、`outcome_lane_count=7`、`blocked_action_count=20`、`owner_response_received_count=0`、`owner_response_accepted_count=0`、`live_host_read_authorized_count=0`、`docker_compose_action_authorized_count=0`、`systemctl_action_authorized_count=0`、`repair_bot_execution_authorized_count=0`、`ansible_apply_authorized_count=0`、`runtime_gate_count=0`。此更新讓 `docker_compose_systemd_host_config` 從 `50%` 推進到 `54%`,也讓高價值配置平均只讀成熟度從 `67%` 推進到 `68%`;它不代表 live host read、restart、repair-bot、Ansible、sudo、host write 或 runtime gate 已授權。 +## 1.7 2026-06-15 端口 / 防火牆變更證據驗收只讀帳本 + +已新增 `docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md` 與 `docs/security/port-firewall-change-evidence-acceptance.snapshot.json`,將 SSH / Firewall / Network Access owner response acceptance 裡的端口、防火牆、NodePort、NetworkPolicy、WireGuard、deploy SSH、sudo 與 alert action surface 轉成 change evidence acceptance 只讀帳本。 + +固定數字為 `change_evidence_candidate_count=14`、`write_capable_change_evidence_candidate_count=6`、`policy_or_exposure_candidate_count=5`、`change_evidence_field_count=32`、`required_evidence_field_count=16`、`reviewer_check_count=16`、`outcome_lane_count=8`、`blocked_action_count=24`、`change_evidence_received_count=0`、`change_evidence_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%` 推進到 `60%`;它只補齊端口 / 防火牆變更的 actor、before / after state、service dependency、customer impact、cross-project sync、rollback 與 post-check evidence 驗收規則,不代表 SSH、live firewall read、firewall change、port close / open、route smoke、host restart、production write 或 runtime gate 已授權。 + ## 2. 覆蓋摘要 | 指標 | 目前值 | 說明 | @@ -84,7 +90,7 @@ | 優先 | 類別 | 目前成熟度 | 下一步 | |------|------|------------|--------| | P1-1 | Docker Compose / systemd / host service config | `54%` | repo-only 清冊已納入 9 個 surface,owner request draft 與 owner response acceptance ledger 已完成;仍缺 owner response、110 / 188 live hash、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence | -| P1-2 | SSH / sudoers / known_hosts / firewall / WireGuard / NodePort | `58%` | repo-only 清冊已納入 16 個 SSH / network access surface,owner request draft 與 owner response acceptance ledger 已完成;仍缺 owner response、live access state、allowed source CIDR、host key pinning、port impact、firewall owner、maintenance window、rollback owner 與 validation plan | +| P1-2 | SSH / sudoers / known_hosts / firewall / WireGuard / NodePort | `60%` | repo-only 清冊已納入 16 個 SSH / network access surface,owner request draft、owner response acceptance 與端口 / 防火牆變更證據驗收 ledger 已完成;仍缺 owner-provided change / incident ref、actor、before / after state、impact、cross-project sync、maintenance window、rollback owner 與 post-check evidence | | P1-3 | Backup / restore / escrow / retention | `62%` | repo-only 清冊已納入 38 個 surface,owner request draft 與 owner response acceptance ledger 已完成;仍缺 owner response、restore drill approval package、offsite / escrow owner、retention owner、rollback owner、validation plan 與 no-secret-value evidence | | P1-4 | Prometheus / Alertmanager / Grafana / SigNoz / Sentry / Langfuse | `62%` | repo-only 清冊已納入 60 個 monitoring / alerting / observability surface,owner request draft 已轉成 60 份草稿;仍缺 owner response、live drift evidence、reload owner、receiver owner、route smoke 與 receipt proof | @@ -199,6 +205,8 @@ python3 scripts/security/high-value-config-control-coverage.py \ 2026-06-15 再新增 `ssh_network_owner_response_acceptance_v1`,把 16 份 request draft 轉成 `acceptance_candidate_count=16`、`write_capable_acceptance_candidate_count=6`、`live_evidence_required_candidate_count=16`、`required_owner_field_count=13`、`reviewer_check_count=15`、`outcome_lane_count=7`、`blocked_action_count=22` 的 owner response acceptance 只讀帳本。此更新讓 `ssh_firewall_network_access` 從 `54%` 推進到 `58%`,但 owner response received / accepted、live access state、host key pinning、port policy、firewall owner、NetworkPolicy / NodePort、WireGuard cutover、SSH、keyscan、known_hosts patch、firewall / port 變更、runtime gate 與 action button 仍全部為 `0`。 +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=16`、`reviewer_check_count=16`、`outcome_lane_count=8`、`blocked_action_count=24` 的 change evidence acceptance 只讀帳本。此更新讓 `ssh_firewall_network_access` 從 `58%` 推進到 `60%`,但 change evidence received / accepted、actor identified、before / after state、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`。 + ## 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 6dccd1e57..74b9fdc51 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -55,6 +55,8 @@ 2026-06-15 已新增 `docs/security/SSH-NETWORK-OWNER-RESPONSE-ACCEPTANCE.md` 與 `docs/security/ssh-network-owner-response-acceptance.snapshot.json`,將 16 份 owner request draft 轉成 owner response acceptance 只讀帳本。固定 `candidates=16`、`write_capable=6`、`live_evidence_required=16`、`owner_fields=13`、`reviewer_checks=15`、`outcome_lanes=7`、`blocked_actions=22`,讓 SSH / network 類別成熟度從 `54%` 推進到 `58%`;但 owner response received / accepted、live access state、host key pinning、port policy、firewall owner、NetworkPolicy / NodePort、WireGuard cutover、SSH、keyscan、known_hosts patch、firewall / port 變更、host write、runtime gate 仍全部為 `0 / false`。 +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=32`、`required_evidence_fields=16`、`reviewer_checks=16`、`outcome_lanes=8`、`blocked_actions=24`,讓 SSH / network 類別成熟度從 `58%` 推進到 `60%`;但 change evidence received / accepted、actor identified、before / after state、cross-project sync、post-check evidence、firewall / port 變更、route smoke、host restart、host write、runtime gate 仍全部為 `0 / false`。 + `backup_restore_owner_request_draft_v1` 已把 backup、restore、offsite、credential escrow、retention、Velero、alert / health 與 DR runbook 的 38 個 surface 轉成人工送件前 owner request draft。固定 `drafts=38`、`write_capable=27`、`live_evidence_required=38`、`owner_fields=14`、`blocked_actions=18`,但 request sent、owner response received / accepted、live backup evidence、backup run、restore run、offsite sync、remote delete、escrow marker write、retention change、host write、runtime gate 仍全部為 `0 / false`。 此更新仍不是 live network truth:live firewall、sudoers、known_hosts、NetworkPolicy、NodePort、WireGuard evidence、network owner、maintenance window、rollback owner 與 owner response received / accepted 全部仍為 `0`,也不得執行 SSH、keyscan、sudo、firewall change、NetworkPolicy apply、NodePort change 或 WireGuard cutover。 @@ -165,7 +167,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 | P1 | PostgreSQL / Redis / MinIO | app config、backup scripts、monitoring config | 188 / 110 / K3s | no plaintext DSN, access boundary, backup, restore, metrics auth | | P1 | Docker Compose / systemd | `docker-compose.yml`、`ops/*/docker-compose.yml`、`scripts/reboot-recovery/*.service`、`docs/security/HOST-SERVICE-OWNER-REQUEST-DRAFT.md`、`docs/security/HOST-SERVICE-OWNER-RESPONSE-ACCEPTANCE.md` | 110 / 188 / agent-bounty hosts | live hash metadata、port / volume / env diff、maintenance / restart window、rollback owner、post-check plan、disable switch;不得 restart / apply | | P1 | SSH / sudoers / known_hosts | Ansible inventory、ops scripts、runner scripts | host owners | owner request draft 已固定;下一步只收脫敏 live access state、known_hosts / host-key policy、target whitelist 與 rollback owner | -| P1 | Firewall / WireGuard / NodePort / VIP | K8s service / network policy、Kali / wg-easy docs | network owner | owner request draft 已固定;下一步只收 allowed source CIDR、maintenance window、rollback owner 與 validation plan;no unreviewed port exposure | +| P1 | Firewall / WireGuard / NodePort / VIP | K8s service / network policy、Kali / wg-easy docs、`docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md` | network owner | owner request draft、owner response acceptance 與 change evidence acceptance 已固定;下一步只收 actor、before / after state、impact、cross-project sync、maintenance window、rollback owner 與 post-check evidence;no unreviewed port exposure | | P1 | AI provider / model routing | `apps/api/src/services/ai_providers/*`、Ollama runbooks、Nginx proxy | AI owner | dry-run、benchmark、cost / privacy review、fallback order gate | | P1 | Kali 112 scanner config | `docs/security/KALI-112-MAINTENANCE-WINDOW-DRAFT.md`、Kali snapshots | Kali owner | maintenance window、no active scan、no `/execute`、hardening dry-run | | P2 | AWOOOI / AwoooP / IwoooS frontend runtime config | `apps/web/next.config.js`、`apps/web/src/lib/config.ts`、i18n | web owner | NEXT_PUBLIC public-domain only、no internal transcript, desktop/mobile smoke | @@ -226,6 +228,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 | Docker / systemd owner response acceptance | `100%` | 已新增 `host_service_owner_response_acceptance_v1`,9 個 candidate、3 個 write-capable、8 個需 live evidence、14 個 reviewer checks、7 條 outcome lanes、20 類 blocked action;成熟度 `50% -> 54%` | | 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、16 個 reviewer checks、8 條 outcome lanes、24 類 blocked action;成熟度 `58% -> 60%` | | Backup / restore / escrow owner request draft | `100%` | 已將 38 個 backup / restore / escrow surface 轉成 owner request draft;request sent / received / accepted、backup run、restore run、offsite sync、remote delete、escrow marker write、retention change 仍為 0 | | CI blocking / workflow gate | `0%` | 本階段刻意不修改 `.gitea/workflows`,避免初期資安流程摩擦過大 | | owner-provided live Nginx file compare | `70%` | 工具可吃 owner 匯出的 live conf 檔比較;本階段不主動 SSH 取得 | @@ -242,7 +245,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 4. P0:把 workflow / runner / secret name owner response 與高價值配置 C0 gate 串成同一個 IwoooS 狀態。 5. P0:把 agent-bounty-protocol compose / MCP / A2A / treasury 高價值配置欄位接入同一個 owner packet queue;不啟用 runtime。 6. P1:向 owner 收 110 / 188 Docker Compose 與 systemd 脫敏 live hash metadata、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence;不主動 SSH、不重啟、不跑 repair-bot。 -7. P1:向 owner 收 SSH / firewall / WireGuard / NodePort 脫敏 live access state、allowed source CIDR、maintenance window、rollback owner 與 validation plan;不主動 keyscan、不改 firewall、不開關端口。 +7. P1:向 owner 收 SSH / firewall / WireGuard / NodePort 脫敏 live access state、allowed source CIDR、change / incident ref、actor、before / after state、cross-project sync、maintenance window、rollback owner 與 validation plan;不主動 keyscan、不改 firewall、不開關端口。 8. P1:向 owner 收 backup / restore / offsite / escrow 非敏感 evidence id、最新備份狀態、restore drill plan、maintenance window、rollback owner 與 validation plan;驗收前 backup run、restore drill、offsite sync、remote delete、escrow marker write、retention change 全部維持 `0 / false`。 9. P1:把 Prometheus / Alertmanager / Grafana / SigNoz / Sentry / Langfuse owner request draft 接入 AwoooP 只讀狀態;驗收前 reload、receiver route change、silence change、Telegram send 與 alert chain smoke 全部維持 `0 / false`。 10. P1:補 Kali 112、111、168 維護窗口 owner 欄位,仍不做 upgrade / restart / scan。 diff --git a/docs/security/IWOOOS-POSTURE-PROJECTION.md b/docs/security/IWOOOS-POSTURE-PROJECTION.md index 50ce07390..383566aa2 100644 --- a/docs/security/IWOOOS-POSTURE-PROJECTION.md +++ b/docs/security/IWOOOS-POSTURE-PROJECTION.md @@ -97,7 +97,7 @@ IwoooS 首版只讀取或對齊以下已提交 evidence: 53. 4 個 rollout risk read-only items,顯示風險來源部署 marker、`AWOOOI_ROLLOUT_RISK=1`、ArgoCD `Degraded` / `OutOfSync`、API health / smoke 已通過與執行期閘門仍為 0;這只是部署風險可見性,不代表 ArgoCD sync、kubectl、主機重啟、修復、部署或 runtime gate 已授權。 54. 14 類 high-value config control coverage statuses,顯示 Nginx、DNS / TLS、K8s、secret、workflow、backup、agent-bounty runtime、monitoring、Docker / systemd、SSH / network、AI provider、產品 route 與 security evidence 的全域配置控管覆蓋矩陣;平均只讀成熟度 `68%`、C0 類別 `8`、需 live evidence 類別 `6`、owner response received / accepted 與 runtime gate 仍為 `0`,不代表 reload、sync、scan、secret rotation、payout 或主機操作授權。 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 已授權。 -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`、reviewer check `15`、outcome lane `7`、blocked action `22`,讓 SSH / network 類別成熟度從 `54%` 推進到 `58%`;owner response、live evidence、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0`,不代表 SSH、sudo、firewall、NetworkPolicy、NodePort、WireGuard 或 known_hosts patch 已授權。 +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 `16`、outcome lane `8`、blocked action `24`,讓 SSH / network 類別成熟度從 `58%` 推進到 `60%`;owner response、change evidence、actor、before / after state、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 已授權。 57. 38 個 Backup / restore / escrow / retention repo-only inventory surfaces,顯示 backup orchestration、service backup scripts、restic retention、offsite sync、credential escrow、Velero restore drill、backup health alert 與 cold-start / DR runbook 的第一層清冊;write-capable surface `27`、restore drill surface `4`、offsite / escrow surface `8`,owner response、live evidence、restore drill、offsite sync、credential escrow、retention change、runtime gate 與 action button 仍全部為 `0`,不代表 backup、restore、offsite sync、remote delete、restic prune、escrow marker write、rclone config 或 Velero restore 已授權。 58. 60 個 Monitoring / alerting / observability repo-only inventory surfaces,顯示 Prometheus、Alertmanager、Grafana、SigNoz、Sentry、Langfuse、OTEL、Telegram / notification policy、deploy / reload scripts 與 alert chain smoke scripts 的第一層清冊;write-capable surface `11`、alert rule surface `13`、deploy / reload surface `6`,owner response、live evidence、reload owner、receiver owner、route smoke、runtime gate 與 action button 仍全部為 `0`,不代表 Prometheus reload、Alertmanager reload、Grafana import、SigNoz apply、Sentry deploy、Telegram send、live alert fire 或 alert chain smoke 已授權。 59. 12 個 Public Gateway Preflight repo-only gates,顯示 Nginx public gateway reload / route change 前必備的 owner、live conf、rendered diff、`nginx -t`、public / admin / WebSocket route smoke、ACME / TLS owner check、maintenance window 與 rollback owner;source config `3`、route impact `14`、repo-only ready gate `2`,owner acceptance、live conf、rendered diff、`nginx -t` evidence、route smoke、runtime gate 與 action button 仍全部為 `0`,不代表 SSH、live conf read、Nginx reload、route change、DNS / TLS probe 或 certbot renew 已授權。 diff --git a/docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md b/docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md new file mode 100644 index 000000000..b9f1fbeeb --- /dev/null +++ b/docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md @@ -0,0 +1,161 @@ +# IwoooS 端口 / 防火牆變更證據驗收 + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-15 | +| 狀態 | `change_evidence_acceptance_ready_no_runtime_action` | +| 工具 | `scripts/security/port-firewall-change-evidence-acceptance.py` | +| Snapshot | `docs/security/port-firewall-change-evidence-acceptance.snapshot.json` | +| Source acceptance | `docs/security/ssh-network-owner-response-acceptance.snapshot.json` | +| runtime gate | `0` | + +## 1. 目的 + +本文件承接 SSH / Firewall / Network Access owner response acceptance,把端口關閉、端口開放、防火牆規則、NodePort、NetworkPolicy、WireGuard 與 host access 類變更轉成 evidence acceptance 只讀帳本。 + +這層專門補上事故型控管缺口:未來若發生端口被關閉、agent route 斷線、公開入口不可達、monitoring exporter 不通或 NodePort / firewall policy 被改動,必須先收集「誰改、為什麼、影響哪裡、怎麼回復、怎麼驗證、是否已同步其他產品」的脫敏證據,不能只靠 UI 卡片或口頭說明。 + +這不是 SSH 授權、不是 live firewall read、不是 firewall change、不是 port close / open、不是 route smoke、不是 host restart,也不是 runtime gate。 + +## 2. 摘要 + +| 指標 | 目前值 | 說明 | +|------|--------|------| +| source acceptance candidate | `16` | 來源為既有 SSH / network owner response acceptance | +| change evidence candidate | `14` | 聚焦端口、防火牆、NodePort、NetworkPolicy、WireGuard、deploy SSH 與 sudo / alert action surface | +| write-capable change evidence candidate | `6` | CI deploy SSH、monitoring deploy、sudoers、alert action catalog | +| policy / exposure candidate | `5` | NetworkPolicy、NodePort、WireGuard exposure 相關候選 | +| change evidence field | `32` | evidence 欄位總數 | +| required evidence field | `16` | change / incident evidence 必填欄位 | +| reviewer check | `16` | actor、scope、before/after、impact、rollback、post-check 與 no-runtime 檢查 | +| outcome lane | `8` | waiting、quarantine、reject、supplement、review、incident backfill、ledger-only、runtime gate | +| blocked action | `24` | SSH、firewall、port、NodePort、NetworkPolicy、WireGuard、route smoke、reload、restart、secret、runtime gate 等 | +| change evidence received / accepted | `0 / 0` | 尚未收到或驗收 | +| firewall / port change authorized | `0 / 0` | 不改防火牆,不開關端口 | +| runtime gate / action button | `0 / 0` | 不提供操作入口 | + +## 3. Evidence Candidate 範圍 + +| Candidate | 類型 | 範圍 | 驗收焦點 | +|-----------|------|------|----------| +| `port_firewall_change_evidence:ansible_inventory_ssh_targets` | SSH target inventory | `110_111_112_120_121_188` | host access 變更、端口影響、維護窗口、rollback | +| `port_firewall_change_evidence:gitea_cd_deploy_ssh` | CI deploy SSH | `k8s_ssh_host` | deploy access 斷線、回滾 owner、post-check | +| `port_firewall_change_evidence:gitea_cd_dev_ssh` | CI deploy SSH | `192.168.0.120` | dev/prod 邊界、端口 policy、host access impact | +| `port_firewall_change_evidence:deploy_alerts_ssh_path` | CI deploy SSH | `192.168.0.110` | alert deploy path、port close impact、通知鏈路 | +| `port_firewall_change_evidence:monitoring_discover_docker_ssh` | SSH discovery script | `110_188_docker_hosts` | monitoring discovery 可達性、read-only window | +| `port_firewall_change_evidence:monitoring_exporter_deploy_ssh` | monitoring SSH deploy | `192.168.0.188` | exporter deploy access、firewall owner、post-check | +| `port_firewall_change_evidence:backup_config_ssh_capture` | SSH backup capture | `110_188_120_121_cluster` | backup access、restore validation、service dependency | +| `port_firewall_change_evidence:host_ops_sudoers_wrapper` | sudoers policy | `host_ops_minimal_sudo` | sudo 授權邊界、firewall recovery 權限、break-glass | +| `port_firewall_change_evidence:k8s_prod_network_policy` | K8s NetworkPolicy | `awoooi_prod_namespace` | ingress / egress policy、route smoke plan | +| `port_firewall_change_evidence:argocd_metrics_network_policy` | K8s NetworkPolicy | `argocd_namespace` | metrics scrape、NodePort exposure、source whitelist | +| `port_firewall_change_evidence:argocd_metrics_nodeport` | K8s NodePort | `argocd_nodeport_30882_30883` | NodePort exposure、firewall owner、rollback | +| `port_firewall_change_evidence:velero_metrics_nodeport` | K8s NodePort | `velero_nodeport_30885` | backup metrics exposure、access policy | +| `port_firewall_change_evidence:wireguard_mesh_runbook` | WireGuard runbook | `110_111_120_121_gcp_a_gcp_b` | mesh cutover、firewall rule owner、canary / rollback | +| `port_firewall_change_evidence:alert_rules_ssh_actions` | alert SSH action rules | `ssh_mcp_action_catalog` | alert action catalog、read/write/admin 分級、cooldown | + +## 4. 必填 Evidence 欄位 + +1. `change_or_incident_ref` +2. `actor_role_or_team` +3. `decision` +4. `decision_reason` +5. `affected_scope` +6. `affected_ports_or_paths_ref` +7. `before_state_ref` +8. `after_state_ref` +9. `service_dependency_ref` +10. `customer_impact_ref` +11. `maintenance_window` +12. `rollback_owner` +13. `rollback_plan_ref` +14. `validation_plan` +15. `postcheck_evidence_refs` +16. `cross_project_sync_ref` + +## 5. Reviewer Checks + +1. `change_ref_present` +2. `actor_role_traceable` +3. `decision_reason_present` +4. `affected_scope_matches_surface` +5. `ports_or_paths_redacted` +6. `before_after_state_refs` +7. `firewall_diff_metadata_only` +8. `dependency_impact_present` +9. `customer_impact_review` +10. `cross_project_sync_present` +11. `maintenance_window_present` +12. `rollback_owner_present` +13. `postcheck_evidence_present` +14. `secret_or_key_value_absent` +15. `no_runtime_authorization` +16. `counts_transition_safe` + +## 6. Outcome Lanes + +| Lane | 說明 | +|------|------| +| `waiting_change_evidence` | 尚未收到端口 / 防火牆變更證據;所有 accepted / runtime count 維持 0 | +| `quarantine_raw_firewall_dump` | 收到 raw firewall dump、secret 或 key material 時只能隔離 | +| `reject_unattributed_change` | 無 actor、無 owner、無 affected scope 或無 rollback 的變更不得驗收 | +| `request_impact_supplement` | 缺 before/after、impact、dependency、post-check 或 cross-project sync 時要求補件 | +| `ready_for_network_review` | metadata 合格後,只能進 network / firewall reviewer review | +| `incident_backfill_only` | 事故回補只能更新只讀 ledger,不得反向視為已批准操作 | +| `owner_review_only_update` | 只允許更新 reviewer ledger,不改 firewall、port、route 或 host | +| `waiting_runtime_gate` | 即使證據 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. `secret_value_collection` +18. `ssh_key_collection` +19. `raw_firewall_dump_storage` +20. `raw_key_material_storage` +21. `mark_change_evidence_accepted_without_reviewer_record` +22. `open_runtime_gate` +23. `add_action_button` +24. `production_write` + +## 8. 指令 + +產生 committed snapshot: + +```bash +python3 scripts/security/port-firewall-change-evidence-acceptance.py \ + --root . \ + --source-acceptance-report docs/security/ssh-network-owner-response-acceptance.snapshot.json \ + --output docs/security/port-firewall-change-evidence-acceptance.snapshot.json \ + --generated-at 2026-06-15T00:36:00+08:00 +``` + +驗證 guard: + +```bash +python3 scripts/security/security-mirror-progress-guard.py --root . +``` + +## 9. 完成度 + +| 工作 | 完成度 | 說明 | +|------|--------|------| +| port / firewall change evidence acceptance ledger artifact | `100%` | 14 份候選、snapshot、文件與 guard 已固定 | +| change evidence received / accepted | `0%` | 尚未收到或驗收 | +| actor / impact / before-after evidence | `0%` | 尚未收到 owner-provided evidence | +| cross-project sync evidence | `0%` | 尚未收到同步證據 | +| firewall / port / NetworkPolicy / NodePort / WireGuard change | `0%` | 未授權且未執行 | +| runtime gate / production write | `0%` | 未授權且未執行 | diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index adb4fd859..32d63570c 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -3,16 +3,22 @@ | 項目 | 內容 | |------|------| | 日期 | 2026-06-15 | -| 狀態 | IwoooS 64% 只讀治理推進中;P2-145 owner response acceptance gate 已完成正式驗證;P1 Docker / systemd / host service owner response acceptance 只讀帳本已本地完成;S4.9 owner response gate 仍是第一優先 | +| 狀態 | IwoooS 64% 只讀治理推進中;端口 / 防火牆變更證據驗收只讀帳本已本地完成;P2-145 owner response acceptance gate 已完成正式驗證;S4.9 owner response gate 仍是第一優先 | | 本階段完成 | 資安供應鏈 contract manifest + Source Control Approval Board + Draft Reconcile Plan + Ref Detail Diff + Ref Truth Classification + Source Control Ref Truth Owner Response 收件包 + GitHub Primary Readiness Gate + GitHub Primary Rollback ADR + GitHub Target Owner Decision Response 收件包 + Gitea 認證清冊匯出請求 + Gitea 認證清冊匯入驗收契約 + Gitea 清冊覆蓋 Owner Attestation + Gitea Owner Attestation Approval Lane 對齊 + Gitea Owner Attestation Response 收件包 + Workflow / Secret Name Inventory + Workflow / Secret Name Local Evidence + Workflow / Secret Name Redacted Export Request + Workflow / Secret Name Owner Response 收件包 + Source Control Owner Response Validation Rollup + Kali 112 live integration status + Security Finding contract + Kali scan scope approval package + Security Approval Queue + S3 人工批准 Gate + S3 人工決策紀錄 + S3 人工審查封包 + S3 人工決策狀態轉移 + S3 後續 runtime gate 準備契約 + 鏡像 readiness index + 鏡像接收計畫 + 鏡像事件信封 + 鏡像路由矩陣 + 鏡像驗收契約 + 鏡像隔離契約 + 鏡像 dry-run 報告契約 + 鏡像狀態彙整契約 + IwoooS 前端態勢入口 + IwoooS posture projection contract + IwoooS 既有前端資安頁面整合 + IwoooS 覆蓋與邊界矩陣 + IwoooS 只讀資安處理旅程 + IwoooS owner evidence readiness board + IwoooS host coverage view + IwoooS host action gate matrix + IwoooS host evidence readiness board + IwoooS host evidence collection order + IwoooS host evidence intake preflight + IwoooS host evidence review outcome lanes + IwoooS host evidence review handoff packets + IwoooS host evidence reviewer checklist + IwoooS host evidence reviewer outcome lanes + IwoooS host owner decision candidate packets + IwoooS host owner decision review checklist + IwoooS host owner decision review outcome lanes + IwoooS host owner decision record draft packets + IwoooS host owner decision record draft review checklist + IwoooS host owner decision record draft review outcome lanes + IwoooS host owner decision record write-up packets + IwoooS host owner decision record write-up review checklist + IwoooS host owner decision record write-up review outcome lanes + IwoooS host owner decision record formal candidate packets + IwoooS host owner decision record formal candidate review checklist + IwoooS host owner decision record formal candidate review outcome lanes + IwoooS host owner decision record formal record queue packets + IwoooS host owner decision record formal record queue review checklist + IwoooS host owner decision record formal record queue review outcome lanes + IwoooS host owner decision record human handoff readiness packets + IwoooS host owner decision record human handoff readiness review checklist + IwoooS host owner decision record human handoff readiness review outcome lanes + IwoooS host owner decision record human record owner review candidate packets + IwoooS host owner decision record human record owner review candidate checklist + IwoooS host owner decision record human record owner review candidate outcome lanes + IwoooS host owner decision record human record owner review preparation packets + IwoooS host owner decision record human record owner review preparation checklist + IwoooS progress acceleration lanes + IwoooS owner response next-action focus + IwoooS S4.9 owner response preflight + IwoooS S4.9 owner response request templates + IwoooS progress hold movement gates + IwoooS AwoooP read-only landing readiness + IwoooS AwoooP cross-session handoff packets + AwoooP 首頁 IwoooS 資安鏡像候選 + AwoooP 工作鏈路 IwoooS 資安鏡像候選 + AwoooP 審批佇列 IwoooS owner response 只讀焦點 | | 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP 執行監控 IwoooS 執行狀態只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 + IwoooS GitHub 主要來源就緒度只讀狀態板 + AwoooP 工作鏈路 GitHub 主要來源就緒度只讀工作項 + AwoooP 合約儀表板 GitHub 主要來源就緒度合約只讀候選 + AwoooP 審批佇列 GitHub 主要來源就緒度審批邊界 + AwoooP 首頁 GitHub 主要來源就緒度只讀摘要 + AwoooP 租戶管理 GitHub 主要來源就緒度租戶範圍 + AwoooP 執行監控 GitHub 主要來源就緒度執行邊界 + IwoooS / AwoooP 資安可視區塊繁體中文呈現防護檢查 + AwoooP 執行詳情 / 審批詳情繁體中文呈現防護檢查 + AwoooP 首頁負責人回覆驗收總覽 + AwoooP 工作鏈路負責人回覆驗收只讀工作項 + AwoooP 合約儀表板負責人回覆驗收契約只讀候選 + AwoooP 審批佇列負責人回覆驗收只讀審查邊界 + AwoooP 租戶管理負責人回覆驗收租戶範圍 + AwoooP 執行監控負責人回覆驗收執行邊界 + AwoooP 執行詳情負責人回覆驗收詳情邊界 + AwoooP 審批決策負責人回覆驗收審批邊界 + IwoooS AwoooP 資安入口覆蓋狀態板 + IwoooS 階段式資安收斂節奏圖 + IwoooS 下一步人工收件作戰板 + IwoooS 人工回覆安全驗收閘道 + IwoooS 人工回覆審查結果分流 + IwoooS 人工決策準備佇列 + IwoooS 人工決策紀錄草稿防誤用 + IwoooS 人工決策正式紀錄負責人指派確認準備包 + IwoooS 人工決策正式紀錄負責人指派確認清單 + IwoooS 人工決策正式紀錄負責人指派確認結果分流 + IwoooS 人工決策正式紀錄負責人指派決策準備包 + IwoooS 人工決策正式紀錄負責人指派決策檢查清單 + IwoooS S4.9 負責人回覆封套欄位 + IwoooS S4.9 負責人回覆封套送件前檢查 + IwoooS S4.9 負責人回覆封套送件前結果分流 + IwoooS S4.9 負責人回覆送件請求草稿 + IwoooS S4.9 負責人回覆送件鏈路摘要 + IwoooS 低摩擦分階段收斂主控 + IwoooS 低摩擦下一步行動邊界 + IwoooS 64% 進度移動訊號驗收條 + IwoooS 第一個進度解鎖路徑 + IwoooS 第一解鎖證據包 + IwoooS 第一解鎖證據包預檢分流 + IwoooS 第一解鎖證據包補件路徑 + IwoooS 第一解鎖證據包補件送審前檢查 + IwoooS 第一解鎖證據包補件送審結果分流 + IwoooS 第一解鎖證據包 reviewer 指派準備包 + IwoooS 第一解鎖證據包 reviewer 指派前檢查 + IwoooS 第一解鎖證據包 reviewer 指派前檢查結果分流 + IwoooS 正式只讀 landing 與 Kali 112 只讀證據進度重估 | | 本階段追加補充 | IwoooS 目前具體工作地圖 + IwoooS 目前具體交付清單 + IwoooS 目前阻塞與解除條件 + IwoooS 三軸進度與全產品套用範圍 + IwoooS 全產品分階段套用台帳 + IwoooS 全產品 rollout 波次驗收門檻 + IwoooS 全產品 rollout 驗收結果分流 + IwoooS 全產品證據接線地圖 + IwoooS 全產品證據接線預檢 + IwoooS 全產品證據接線預檢結果分流 + IwoooS 全產品預檢補件回收台帳 + IwoooS 全產品補件重試門檻 + IwoooS 全產品重試結果分流 + IwoooS 全產品人工審查候選準備 + IwoooS 全產品人工審查候選預檢 + IwoooS 全產品人工審查候選預檢結果分流 + IwoooS 全產品人工審查候選預檢補件回收台帳 + IwoooS 全產品人工審查候選預檢補件重試門檻 + IwoooS 全產品只讀套用快照 + P2-145 owner response acceptance gate 正式驗證完成 | -| P0 追加 | IwoooS P0 配置控管優先序前台正式驗證完成;Nginx public gateway、DNS / TLS / certbot、K8s / ArgoCD / production manifests、Workflow / runner / secret metadata、Public / admin / API runtime config、agent-bounty runtime / treasury 六類先列為即時風險配置;高價值配置 Gate 已補上 `k8s/nginx/**`、`scripts/ops/**/*cert*`、`scripts/ops/**/*tls*`,sample 從 `matched=0 / C0=0` 收斂到 `matched=3 / C0=2`;Gate 預設工作樹 preflight 已可讀取 staged / unstaged / untracked,本地 smoke 對臨時 `k8s/nginx/*` 檔命中 C0;Owner Packet snapshot 已同步為 `packets=3 / c0=2`,Coverage snapshot 已同步最新 patterns;IwoooS / AwoooP 前台 Owner Packet 摘要已正式驗證 `packet=3 / c0=2`,feature commit `e999c16b`、deploy marker `16c6b983`、Gitea code-review `2973` / CD `2972` success;IwoooS posture projection snapshot / schema / guard 已同步 `packet=3 / c0=2`,不再保留舊 `1 / 0` 口徑;高價值配置 Owner Packet 收件預檢已新增 `checks=9 / lanes=5 / required_fields=27 / blocked_requests=16`;高價值配置 Owner Request 草稿包已新增 `drafts=3 / handoff_fields=11 / forbidden_payloads=12 / sent=0`;Public Gateway live conf 匯出請求包已新增 `requests=3 / c0=2 / redaction_rules=8 / received=0`;Public Gateway redacted export 收件預檢已新增 `candidates=3 / c0=2 / checks=10 / rejection_guards=12 / received=0 / accepted=0`;Public Gateway rendered diff / nginx gate 草稿已新增 `candidates=3 / c0=2 / stages=7 / blocked=14 / rendered_diff=0 / runtime=0`;Public Gateway owner response acceptance 只讀帳本已新增 `candidates=3 / c0=2 / fields=12 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;DNS / TLS / certbot Owner Confirmation Request 已新增 `requests=4 / c0=4 / fields=9 / questions=5 / guards=12 / received=0 / accepted=0`;K8s / ArgoCD manifest repo-only 清冊已新增 `files=49 / c0=36 / yaml=45 / kinds=20 / blocked=13 / runtime=0`;K8s / ArgoCD Owner Request Draft 已新增 `drafts=4 / c0=3 / fields=11 / sent=0 / runtime=0`;K8s / ArgoCD owner response acceptance 只讀帳本已新增 `candidates=4 / c0=3 / fields=11 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;Backup / Restore / Escrow owner response acceptance 只讀帳本已新增 `candidates=38 / write_capable=27 / fields=14 / checks=13 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;SSH / Firewall / Network Access owner response acceptance 只讀帳本已新增 `candidates=16 / write_capable=6 / fields=13 / checks=15 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;owner response / live evidence / runtime gate / action buttons 仍全部為 0 | +| P0 追加 | IwoooS P0 配置控管優先序前台正式驗證完成;Nginx public gateway、DNS / TLS / certbot、K8s / ArgoCD / production manifests、Workflow / runner / secret metadata、Public / admin / API runtime config、agent-bounty runtime / treasury 六類先列為即時風險配置;高價值配置 Gate 已補上 `k8s/nginx/**`、`scripts/ops/**/*cert*`、`scripts/ops/**/*tls*`,sample 從 `matched=0 / C0=0` 收斂到 `matched=3 / C0=2`;Gate 預設工作樹 preflight 已可讀取 staged / unstaged / untracked,本地 smoke 對臨時 `k8s/nginx/*` 檔命中 C0;Owner Packet snapshot 已同步為 `packets=3 / c0=2`,Coverage snapshot 已同步最新 patterns;IwoooS / AwoooP 前台 Owner Packet 摘要已正式驗證 `packet=3 / c0=2`,feature commit `e999c16b`、deploy marker `16c6b983`、Gitea code-review `2973` / CD `2972` success;IwoooS posture projection snapshot / schema / guard 已同步 `packet=3 / c0=2`,不再保留舊 `1 / 0` 口徑;高價值配置 Owner Packet 收件預檢已新增 `checks=9 / lanes=5 / required_fields=27 / blocked_requests=16`;高價值配置 Owner Request 草稿包已新增 `drafts=3 / handoff_fields=11 / forbidden_payloads=12 / sent=0`;Public Gateway live conf 匯出請求包已新增 `requests=3 / c0=2 / redaction_rules=8 / received=0`;Public Gateway redacted export 收件預檢已新增 `candidates=3 / c0=2 / checks=10 / rejection_guards=12 / received=0 / accepted=0`;Public Gateway rendered diff / nginx gate 草稿已新增 `candidates=3 / c0=2 / stages=7 / blocked=14 / rendered_diff=0 / runtime=0`;Public Gateway owner response acceptance 只讀帳本已新增 `candidates=3 / c0=2 / fields=12 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;DNS / TLS / certbot Owner Confirmation Request 已新增 `requests=4 / c0=4 / fields=9 / questions=5 / guards=12 / received=0 / accepted=0`;K8s / ArgoCD manifest repo-only 清冊已新增 `files=49 / c0=36 / yaml=45 / kinds=20 / blocked=13 / runtime=0`;K8s / ArgoCD Owner Request Draft 已新增 `drafts=4 / c0=3 / fields=11 / sent=0 / runtime=0`;K8s / ArgoCD owner response acceptance 只讀帳本已新增 `candidates=4 / c0=3 / fields=11 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;Backup / Restore / Escrow owner response acceptance 只讀帳本已新增 `candidates=38 / write_capable=27 / fields=14 / checks=13 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;SSH / Firewall / Network Access owner response acceptance 只讀帳本已新增 `candidates=16 / write_capable=6 / fields=13 / checks=15 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;端口 / 防火牆變更證據驗收只讀帳本已新增 `candidates=14 / write_capable=6 / policy_or_exposure=5 / evidence_fields=16 / checks=16 / lanes=8 / blocked=24 / accepted=0 / runtime=0`;owner response / live evidence / runtime gate / action buttons 仍全部為 0 | | P0 agent-bounty 追加 | agent-bounty-protocol Owner Request Draft 已新增 `drafts=11 / control=4 / surface=7 / write_capable=8 / treasury=4 / mcp_a2a=5 / fields=22 / forbidden_inputs=25 / blocked=28 / sent=0 / runtime=0`;這是 repo / refs、deployment、data classification、MCP / A2A、cron / daemon、admin / treasury、webhook / traffic 的人工送件前草稿,不是 owner response、repo push、refs sync、workflow 修改、secret 收集、deploy、compose restart、DB migration、claim / submit、payout / withdrawal、cron / daemon、external send、host write 或 runtime gate | | P1 追加 | Docker / systemd / Host Service Owner Request Draft 已新增 `drafts=9 / write_capable=3 / fields=12 / blocked=14 / sent=0 / runtime=0`;SSH / Firewall / Network Access Owner Request Draft 已新增 `drafts=16 / write_capable=6 / fields=13 / blocked=16 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Request Draft 已新增 `drafts=38 / write_capable=27 / fields=14 / blocked=18 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Response Acceptance 已新增 `candidates=38 / write_capable=27 / reviewer_checks=13 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;Monitoring / Alerting / Observability Owner Request Draft 已新增 `drafts=60 / write_capable=11 / fields=14 / blocked=24 / sent=0 / runtime=0`;上述全部仍是人工送件前草稿或只讀 acceptance 帳本,不是 owner response、live evidence、reload、restart、backup、restore、Telegram send、alert smoke、host write 或 runtime gate | | 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary | | P0 主控板 | `docs/workplans/2026-06-04-iwooos-security-governance-p0.md` | +## 0.00aa 2026-06-15 端口 / 防火牆變更證據驗收 + +本輪把 SSH / Firewall / Network Access 從 owner response acceptance 再補一層 change evidence acceptance 只讀帳本:`port_firewall_change_evidence_acceptance_v1` 固定 `candidates=14`、`write_capable=6`、`policy_or_exposure=5`、`required_evidence_fields=16`、`reviewer_checks=16`、`outcome_lanes=8`、`blocked_actions=24`,並讓 `ssh_firewall_network_access` 只讀治理成熟度 `58% -> 60%`,高價值配置平均只讀成熟度維持 `68%`。這是 metadata-only 事故 / 變更證據驗收,不是 change evidence received / accepted、live firewall read、SSH、firewall change、port close / open、NetworkPolicy apply、NodePort change、WireGuard change、route smoke、host restart、production write 或 runtime gate。 + +同步邊界:IwoooS headline 維持 `64%`,active runtime gate 維持 `0`;change evidence / actor / before-after / impact / cross-project sync / post-check / runtime gate / action buttons 全部仍為 `0 / false`。本段只更新文件、snapshot、guard、覆蓋矩陣與前端 marker,不碰 Nginx、firewall、iptables、ufw、Docker、systemd、主機或 live route。 + ## 0.00a 2026-06-14 Docker / systemd / host service owner response acceptance 本輪把 Docker / systemd / host service 從 owner request draft 推進到 owner response acceptance 只讀帳本:`host_service_owner_response_acceptance_v1` 固定 `candidates=9`、`write_capable=3`、`live_evidence_required=8`、`owner_fields=12`、`reviewer_checks=14`、`outcome_lanes=7`、`blocked_actions=20`,並讓 `docker_compose_systemd_host_config` 只讀治理成熟度 `50% -> 54%`,高價值配置平均只讀成熟度 `67% -> 68%`。這是 metadata-only 收件驗收,不是 request sent、owner response received / accepted、live host read、SSH、Docker Compose、systemctl、repair-bot、Ansible、sudo、host write、production write 或 runtime gate。 diff --git a/docs/security/high-value-config-control-coverage.snapshot.json b/docs/security/high-value-config-control-coverage.snapshot.json index aad4f4b61..67d936222 100644 --- a/docs/security/high-value-config-control-coverage.snapshot.json +++ b/docs/security/high-value-config-control-coverage.snapshot.json @@ -393,9 +393,9 @@ "action_buttons_allowed": false, "category_id": "ssh_firewall_network_access", "control_tier": "C1", - "coverage_percent": 58, - "coverage_status": "owner_response_acceptance_ledger_ready_needs_network_owner", - "current_gap": "owner response acceptance 帳本已固定 16 個 SSH / network acceptance candidate;仍缺 owner response、live access state、allowed source CIDR、host key pinning、port impact、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 validation plan。", + "coverage_percent": 60, + "coverage_status": "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、impact、cross-project sync、maintenance window、rollback owner 與 post-check evidence。", "evidence_refs": [ "docs/HARD_RULES.md", "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md", @@ -404,10 +404,12 @@ "docs/security/SSH-NETWORK-OWNER-REQUEST-DRAFT.md", "docs/security/ssh-network-owner-request-draft.snapshot.json", "docs/security/SSH-NETWORK-OWNER-RESPONSE-ACCEPTANCE.md", - "docs/security/ssh-network-owner-response-acceptance.snapshot.json" + "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" ], "label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort", - "next_owner_action": "補 owner-provided live hash / disposition、host key pinning、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 post-check 指標。", + "next_owner_action": "補端口 / 防火牆變更的 change / incident ref、actor role / team、affected scope、before / after state、service dependency、customer impact、cross-project sync、rollback owner 與 post-check 指標。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -590,8 +592,8 @@ "websocket_route_change_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-06-14T23:59:00+08:00", - "git_commit": "22876ee1", + "generated_at": "2026-06-15T00:37:00+08:00", + "git_commit": "9c0648ac", "lowest_coverage_categories": [ { "category_id": "docker_compose_systemd_host_config", @@ -602,10 +604,10 @@ }, { "category_id": "ssh_firewall_network_access", - "coverage_percent": 58, - "current_gap": "owner response acceptance 帳本已固定 16 個 SSH / network acceptance candidate;仍缺 owner response、live access state、allowed source CIDR、host key pinning、port impact、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 validation plan。", + "coverage_percent": 60, + "current_gap": "owner response acceptance 帳本已固定 16 個 SSH / network acceptance candidate,端口 / 防火牆變更證據驗收帳本已固定 14 個 change evidence candidate;仍缺 owner-provided change / incident evidence、actor、before / after state、impact、cross-project sync、maintenance window、rollback owner 與 post-check evidence。", "label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort", - "next_owner_action": "補 owner-provided live hash / disposition、host key pinning、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 post-check 指標。" + "next_owner_action": "補端口 / 防火牆變更的 change / incident ref、actor role / team、affected scope、before / after state、service dependency、customer impact、cross-project sync、rollback owner 與 post-check 指標。" }, { "category_id": "ai_provider_model_routing", diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json index 10c3cbd29..cd1429a14 100644 --- a/docs/security/iwooos-posture-projection.snapshot.json +++ b/docs/security/iwooos-posture-projection.snapshot.json @@ -45,6 +45,8 @@ "docs/security/SSH-NETWORK-OWNER-REQUEST-DRAFT.md", "docs/security/ssh-network-owner-response-acceptance.snapshot.json", "docs/security/SSH-NETWORK-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/port-firewall-change-evidence-acceptance.snapshot.json", + "docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.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", @@ -325,6 +327,22 @@ "ssh_network_owner_response_acceptance_runtime_gate_count": 0, "ssh_network_owner_response_acceptance_action_button_count": 0, "ssh_network_owner_response_acceptance_coverage_percent_after_acceptance": 58, + "port_firewall_change_evidence_acceptance_first_layer": true, + "port_firewall_change_evidence_acceptance_candidate_count": 14, + "port_firewall_change_evidence_acceptance_write_capable_candidate_count": 6, + "port_firewall_change_evidence_acceptance_policy_or_exposure_candidate_count": 5, + "port_firewall_change_evidence_acceptance_required_evidence_field_count": 16, + "port_firewall_change_evidence_acceptance_reviewer_check_count": 16, + "port_firewall_change_evidence_acceptance_outcome_lane_count": 8, + "port_firewall_change_evidence_acceptance_blocked_action_count": 24, + "port_firewall_change_evidence_acceptance_received_count": 0, + "port_firewall_change_evidence_acceptance_accepted_count": 0, + "port_firewall_change_evidence_acceptance_actor_identified_count": 0, + "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, + "port_firewall_change_evidence_acceptance_action_button_count": 0, + "port_firewall_change_evidence_acceptance_coverage_percent_after_acceptance": 60, "backup_restore_escrow_inventory_first_layer": true, "backup_restore_escrow_inventory_surface_count": 38, "backup_restore_escrow_inventory_source_exists_count": 38, diff --git a/docs/security/port-firewall-change-evidence-acceptance.snapshot.json b/docs/security/port-firewall-change-evidence-acceptance.snapshot.json new file mode 100644 index 000000000..bddefb118 --- /dev/null +++ b/docs/security/port-firewall-change-evidence-acceptance.snapshot.json @@ -0,0 +1,2861 @@ +{ + "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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "change_evidence_candidates": [ + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:ansible_inventory_ssh_targets", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "ssh_target_inventory", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "110_111_112_120_121_188", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:ansible_inventory_ssh_targets", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "ansible_inventory_ssh_targets", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:gitea_cd_deploy_ssh", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "ci_deploy_ssh", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "k8s_ssh_host", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:gitea_cd_deploy_ssh", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "gitea_cd_deploy_ssh", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:gitea_cd_dev_ssh", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "ci_deploy_ssh", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "192.168.0.120", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:gitea_cd_dev_ssh", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "gitea_cd_dev_ssh", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:deploy_alerts_ssh_path", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "ci_deploy_ssh", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "192.168.0.110", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:deploy_alerts_ssh_path", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "deploy_alerts_ssh_path", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:monitoring_discover_docker_ssh", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "ssh_discovery_script", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "110_188_docker_hosts", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:monitoring_discover_docker_ssh", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "monitoring_discover_docker_ssh", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:monitoring_exporter_deploy_ssh", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "monitoring_ssh_deploy_script", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "192.168.0.188", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:monitoring_exporter_deploy_ssh", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "monitoring_exporter_deploy_ssh", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:backup_config_ssh_capture", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "ssh_backup_capture", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "110_188_120_121_cluster", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:backup_config_ssh_capture", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "backup_config_ssh_capture", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:host_ops_sudoers_wrapper", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "sudoers_policy", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "host_ops_minimal_sudo", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:host_ops_sudoers_wrapper", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "host_ops_sudoers_wrapper", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": true + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:k8s_prod_network_policy", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "k8s_network_policy", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "awoooi_prod_namespace", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:k8s_prod_network_policy", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "k8s_prod_network_policy", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:argocd_metrics_network_policy", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "k8s_network_policy", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "argocd_namespace", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:argocd_metrics_network_policy", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "argocd_metrics_network_policy", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:argocd_metrics_nodeport", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "k8s_nodeport_service", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "argocd_nodeport_30882_30883", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:argocd_metrics_nodeport", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "argocd_metrics_nodeport", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:velero_metrics_nodeport", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "k8s_nodeport_service", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "velero_nodeport_30885", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:velero_metrics_nodeport", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "velero_metrics_nodeport", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:wireguard_mesh_runbook", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "wireguard_runbook", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "110_111_120_121_gcp_a_gcp_b", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:wireguard_mesh_runbook", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "wireguard_mesh_runbook", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": false + }, + { + "action_buttons_allowed": false, + "actor_identified": false, + "actor_role_or_team": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": null, + "affected_scope": "pending_change_evidence", + "affected_scope_accepted": false, + "after_state_accepted": false, + "after_state_ref": null, + "allowlist_or_denylist_ref": null, + "before_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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write" + ], + "break_glass_owner": "pending_change_evidence", + "change_evidence_accepted": false, + "change_evidence_candidate_id": "port_firewall_change_evidence:alert_rules_ssh_actions", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "change_freeze_rule": "pending_change_evidence", + "change_or_incident_ref": null, + "communication_owner": "pending_change_evidence", + "config_kind": "alert_ssh_action_rules", + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "customer_impact_accepted": false, + "customer_impact_ref": null, + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "deploy_ssh_action_authorized": false, + "expected_scope": "ssh_mcp_action_catalog", + "firewall_change_authorized": false, + "firewall_rule_diff_accepted": false, + "firewall_rule_diff_ref": null, + "followup_owner": "pending_change_evidence", + "host_restart_authorized": false, + "host_write_authorized": false, + "impact_supplement_requested": false, + "incident_backfill_only": true, + "live_firewall_read_authorized": false, + "maintenance_window": "pending_change_evidence", + "maintenance_window_accepted": false, + "monitoring_alert_refs": [], + "network_policy_apply_authorized": false, + "nginx_reload_authorized": false, + "nodeport_change_authorized": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_raw_firewall_dump", + "reject_unattributed_change", + "request_impact_supplement", + "ready_for_network_review", + "incident_backfill_only", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "port_change_authorized": false, + "port_close_authorized": false, + "port_open_authorized": false, + "port_policy_accepted": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_refs": [], + "production_write_authorized": false, + "public_gateway_reload_authorized": false, + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + "change_ref_present", + "actor_role_traceable", + "decision_reason_present", + "affected_scope_matches_surface", + "ports_or_paths_redacted", + "before_after_state_refs", + "firewall_diff_metadata_only", + "dependency_impact_present", + "customer_impact_review", + "cross_project_sync_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "secret_or_key_value_absent", + "no_runtime_authorization", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_owner_accepted": false, + "rollback_plan_accepted": false, + "rollback_plan_ref": null, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_value_collection_allowed": false, + "service_dependency_accepted": false, + "service_dependency_ref": null, + "source_acceptance_candidate_id": "ssh_network_owner_response_acceptance:alert_rules_ssh_actions", + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "status": "waiting_change_evidence", + "sudo_action_authorized": false, + "surface_id": "alert_rules_ssh_actions", + "validation_plan": "pending_change_evidence", + "validation_plan_accepted": false, + "wireguard_change_authorized": false, + "write_capable_surface": true + } + ], + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "execution_boundaries": { + "action_buttons_allowed": false, + "change_evidence_acceptance_authorized": false, + "deploy_ssh_action_authorized": false, + "firewall_change_authorized": false, + "host_restart_authorized": false, + "host_write_authorized": false, + "live_firewall_read_authorized": false, + "live_host_read_authorized": false, + "network_policy_apply_authorized": false, + "nginx_reload_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, + "public_gateway_reload_authorized": false, + "route_smoke_authorized": false, + "runtime_execution_authorized": false, + "secret_value_collection_allowed": false, + "ssh_key_collection_allowed": false, + "ssh_read_authorized": false, + "ssh_write_authorized": false, + "sudo_action_authorized": false, + "wireguard_change_authorized": false + }, + "generated_at": "2026-06-15T00:36:00+08:00", + "git_commit": "9c0648ac", + "next_steps": [ + "等待 owner-provided change / incident evidence;未收到前不得更新 accepted count。", + "收到證據後先檢查 actor、affected scope、before / after state、impact、rollback、post-check 與 cross-project sync。", + "metadata 合格也只能進 network / firewall reviewer review;端口、防火牆、NetworkPolicy、NodePort、WireGuard 與 route smoke 仍需獨立人工批准。" + ], + "outcome_lanes": [ + { + "lane_id": "waiting_change_evidence", + "meaning": "尚未收到端口 / 防火牆變更證據;所有 accepted / runtime count 維持 0。" + }, + { + "lane_id": "quarantine_raw_firewall_dump", + "meaning": "收到 raw firewall dump、secret 或 key material 時只能隔離。" + }, + { + "lane_id": "reject_unattributed_change", + "meaning": "無 actor、無 owner、無 affected scope 或無 rollback 的變更不得驗收。" + }, + { + "lane_id": "request_impact_supplement", + "meaning": "缺 before/after、impact、dependency、post-check 或 cross-project sync 時要求補件。" + }, + { + "lane_id": "ready_for_network_review", + "meaning": "metadata 合格後,只能進 network / firewall reviewer review。" + }, + { + "lane_id": "incident_backfill_only", + "meaning": "事故回補只能更新只讀 ledger,不得反向視為已批准操作。" + }, + { + "lane_id": "owner_review_only_update", + "meaning": "只允許更新 reviewer ledger,不改 firewall、port、route 或 host。" + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "即使證據 accepted,runtime gate 仍需獨立人工批准。" + } + ], + "required_evidence_fields": [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref" + ], + "reviewer_checks": [ + { + "check_id": "change_ref_present", + "instruction": "必須有可追溯的 change / incident ref。" + }, + { + "check_id": "actor_role_traceable", + "instruction": "必須標示 actor role / team,不接受匿名端口變更。" + }, + { + "check_id": "decision_reason_present", + "instruction": "decision 與 decision reason 必須同時存在。" + }, + { + "check_id": "affected_scope_matches_surface", + "instruction": "affected scope 必須能對回既有 SSH / network surface。" + }, + { + "check_id": "ports_or_paths_redacted", + "instruction": "端口、路徑、host alias 只能收脫敏摘要或 owner-provided ref。" + }, + { + "check_id": "before_after_state_refs", + "instruction": "需有變更前後狀態 ref,不能只有口頭說明。" + }, + { + "check_id": "firewall_diff_metadata_only", + "instruction": "firewall diff 僅收 metadata ref,不保存 raw firewall dump。" + }, + { + "check_id": "dependency_impact_present", + "instruction": "必須列出受影響服務、agent、監控、公開入口或後台路徑。" + }, + { + "check_id": "customer_impact_review", + "instruction": "若造成服務異常,需有 customer / product impact ref。" + }, + { + "check_id": "cross_project_sync_present", + "instruction": "需標示已同步受影響產品 / Session / owner,不得單點改動。" + }, + { + "check_id": "maintenance_window_present", + "instruction": "未來變更需有維護窗口;事故回補也需標記 break-glass。" + }, + { + "check_id": "rollback_owner_present", + "instruction": "rollback owner 與 rollback plan 必須同時存在。" + }, + { + "check_id": "postcheck_evidence_present", + "instruction": "post-check evidence 必須覆蓋 API / route / agent / monitoring。" + }, + { + "check_id": "secret_or_key_value_absent", + "instruction": "不得包含 secret、SSH key、token、cookie 或私鑰內容。" + }, + { + "check_id": "no_runtime_authorization", + "instruction": "驗收證據不等於允許 firewall / port / route 變更。" + }, + { + "check_id": "counts_transition_safe", + "instruction": "只有 reviewer record 能更新 accepted count,且不得同時開 runtime gate。" + } + ], + "schema_version": "port_firewall_change_evidence_acceptance_v1", + "source_acceptance_schema_version": "ssh_network_owner_response_acceptance_v1", + "source_acceptance_status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "status": "change_evidence_acceptance_ready_no_runtime_action", + "summary": { + "action_button_count": 0, + "actor_identified_count": 0, + "affected_scope_accepted_count": 0, + "after_state_accepted_count": 0, + "before_state_accepted_count": 0, + "blocked_action_count": 24, + "change_evidence_accepted_count": 0, + "change_evidence_candidate_count": 14, + "change_evidence_field_count": 32, + "change_evidence_quarantined_count": 0, + "change_evidence_received_count": 0, + "change_evidence_rejected_count": 0, + "cross_project_sync_accepted_count": 0, + "customer_impact_accepted_count": 0, + "deploy_ssh_action_authorized_count": 0, + "firewall_change_authorized_count": 0, + "firewall_rule_diff_accepted_count": 0, + "host_restart_authorized_count": 0, + "host_write_authorized_count": 0, + "impact_supplement_requested_count": 0, + "live_firewall_read_authorized_count": 0, + "maintenance_window_accepted_count": 0, + "network_policy_apply_authorized_count": 0, + "nginx_reload_authorized_count": 0, + "nodeport_change_authorized_count": 0, + "outcome_lane_count": 8, + "policy_or_exposure_candidate_count": 5, + "port_change_authorized_count": 0, + "port_close_authorized_count": 0, + "port_open_authorized_count": 0, + "port_policy_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "public_gateway_reload_authorized_count": 0, + "required_evidence_field_count": 16, + "reviewer_check_count": 16, + "rollback_owner_accepted_count": 0, + "rollback_plan_accepted_count": 0, + "route_smoke_authorized_count": 0, + "runtime_gate_count": 0, + "secret_value_collection_allowed_count": 0, + "service_dependency_accepted_count": 0, + "source_acceptance_candidate_count": 16, + "ssh_key_collection_allowed_count": 0, + "ssh_read_authorized_count": 0, + "ssh_write_authorized_count": 0, + "sudo_action_authorized_count": 0, + "validation_plan_accepted_count": 0, + "wireguard_change_authorized_count": 0, + "write_capable_change_evidence_candidate_count": 6 + } +} diff --git a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md index 5ed5bcd24..15ed9a94c 100644 --- a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md +++ b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md @@ -4888,6 +4888,18 @@ Trigger commit `f5cd37b7` 與 deploy marker `0ba92357` 已把 governance UI 的 **裁決:** 這是 owner response acceptance 只讀帳本,不是 owner response received / accepted、live gateway truth、rendered diff ready、`nginx -t`、Nginx reload、DNS / TLS probe、certbot renew、route smoke、host write、active scan、production write 或 runtime gate;IwoooS headline 仍維持 `64%`,active runtime gate 仍 `0`。 +### 2026-06-15 00:36 (台北) — §3.2 / §5 — 新增端口 / 防火牆變更證據驗收只讀帳本 — 把 port close / firewall change 事故證據納入可驗收 guard artifact + +**觸發**:110 端口關閉曾造成多個服務異常,顯示 SSH / network owner response acceptance 仍不足以追溯「誰改了端口 / 防火牆、為什麼、影響哪些服務、如何回復、如何驗證、是否同步其他專案」。需要補一層端口 / 防火牆變更證據驗收帳本,防止未來把 incident evidence、port list 或 UI 可見性誤判成 firewall / port 操作授權。 + +**已推進:** +- 新增 `scripts/security/port-firewall-change-evidence-acceptance.py`,讀取 SSH / network owner response acceptance snapshot,產生 14 份 port / firewall change evidence candidate。 +- 新增 `docs/security/port-firewall-change-evidence-acceptance.snapshot.json`,固定 `change_evidence_candidate_count=14`、`write_capable_change_evidence_candidate_count=6`、`policy_or_exposure_candidate_count=5`、`required_evidence_field_count=16`、`reviewer_check_count=16`、`outcome_lane_count=8`、`blocked_action_count=24`。 +- 新增 `docs/security/PORT-FIREWALL-CHANGE-EVIDENCE-ACCEPTANCE.md`,說明 change evidence 欄位、reviewer checks、outcome lanes、blocked actions、完成度與 0 / false 邊界。 +- 高價值配置 coverage、IwoooS 配置控管總清單、供應鏈進度、posture source paths 與前端 evidence marker 已同步;`ssh_firewall_network_access` 只讀治理成熟度從 `58%` 推進到 `60%`,但整體平均仍 `68%`,IwoooS headline 仍 `64%`,runtime gate 仍為 `0`。 + +**裁決:** 這是端口 / 防火牆變更的只讀證據驗收帳本,不是 change evidence received / accepted、live firewall read、SSH、firewall change、port close / open、NetworkPolicy apply、NodePort change、WireGuard change、route smoke、host restart、production write 或 runtime gate;所有執行仍需獨立人工批准。 + ### 2026-06-14 23:58 (台北) — §3.2 / §5 — 新增 Public Gateway Rendered Diff Acceptance 只讀帳本 — 把 Nginx diff / test / smoke evidence 驗收固定成 guard artifact **觸發**:使用者指出 Nginx 常被亂變動,單靠 owner response acceptance 仍不足以防止未來把 rendered diff、`nginx -t` readback 或 route smoke evidence 誤判成 reload / route change 授權。需要新增 evidence acceptance ledger,讓 owner-provided redacted live conf、rendered diff ref、nginx test evidence ref、route smoke matrix、TLS / ACME impact、maintenance window、rollback owner 與 post-check evidence 有固定驗收路徑。 diff --git a/scripts/security/high-value-config-control-coverage.py b/scripts/security/high-value-config-control-coverage.py index 18730bd87..2fe897e7c 100644 --- a/scripts/security/high-value-config-control-coverage.py +++ b/scripts/security/high-value-config-control-coverage.py @@ -156,8 +156,8 @@ CONTROL_STATUS_BY_CATEGORY = { "next_owner_action": "補 owner-provided live hash / disposition、compose / systemd owner、maintenance / restart window、rollback owner、post-check plan 與 disable switch。", }, "ssh_firewall_network_access": { - "coverage_status": "owner_response_acceptance_ledger_ready_needs_network_owner", - "coverage_percent": 58, + "coverage_status": "change_evidence_acceptance_ready_needs_network_owner_evidence", + "coverage_percent": 60, "evidence_refs": [ "docs/HARD_RULES.md", "docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md", @@ -167,9 +167,11 @@ CONTROL_STATUS_BY_CATEGORY = { "docs/security/ssh-network-owner-request-draft.snapshot.json", "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", ], - "current_gap": "owner response acceptance 帳本已固定 16 個 SSH / network acceptance candidate;仍缺 owner response、live access state、allowed source CIDR、host key pinning、port impact、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 validation plan。", - "next_owner_action": "補 owner-provided live hash / disposition、host key pinning、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 post-check 指標。", + "current_gap": "owner response acceptance 帳本已固定 16 個 SSH / network acceptance candidate,端口 / 防火牆變更證據驗收帳本已固定 14 個 change evidence candidate;仍缺 owner-provided change / incident evidence、actor、before / after state、impact、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、cross-project sync、rollback owner 與 post-check 指標。", }, "ai_provider_model_routing": { "coverage_status": "policy_ready_needs_dry_run_pack", @@ -329,6 +331,7 @@ def build_report(root: Path, generated_at: str | None) -> dict[str, Any]: "owner_response_acceptance_ledger_ready_needs_runtime_evidence", "owner_response_acceptance_ledger_ready_needs_restore_drill_owner", "owner_response_acceptance_ledger_ready_needs_network_owner", + "change_evidence_acceptance_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/port-firewall-change-evidence-acceptance.py b/scripts/security/port-firewall-change-evidence-acceptance.py new file mode 100644 index 000000000..b80e9bd45 --- /dev/null +++ b/scripts/security/port-firewall-change-evidence-acceptance.py @@ -0,0 +1,410 @@ +#!/usr/bin/env python3 +""" +IwoooS 端口 / 防火牆變更證據驗收只讀帳本產生器。 + +本工具讀取 SSH / Firewall / Network Access owner response acceptance +snapshot,建立未來端口關閉、端口開放、防火牆規則、NodePort、 +NetworkPolicy 或 WireGuard 變更的 evidence acceptance ledger。它不 SSH、 +不讀 live firewall、不改端口、不套用規則、不做 route smoke、不修復主機, +也不把 incident evidence 誤判成 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)) + +SOURCE_CONFIG_KINDS = { + "ssh_target_inventory", + "ci_deploy_ssh", + "ssh_discovery_script", + "monitoring_ssh_deploy_script", + "ssh_backup_capture", + "sudoers_policy", + "k8s_network_policy", + "k8s_nodeport_service", + "wireguard_runbook", + "alert_ssh_action_rules", +} + +CHANGE_EVIDENCE_FIELDS = [ + "change_evidence_candidate_id", + "source_acceptance_candidate_id", + "surface_id", + "config_kind", + "control_tier", + "write_capable_surface", + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_host_or_route_aliases", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "firewall_rule_diff_ref", + "allowlist_or_denylist_ref", + "service_dependency_ref", + "customer_impact_ref", + "monitoring_alert_refs", + "cross_project_sync_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "communication_owner", + "break_glass_owner", + "change_freeze_rule", + "reviewer_outcome", + "followup_owner", + "not_approval", +] + +REQUIRED_EVIDENCE_FIELDS = [ + "change_or_incident_ref", + "actor_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "affected_ports_or_paths_ref", + "before_state_ref", + "after_state_ref", + "service_dependency_ref", + "customer_impact_ref", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "validation_plan", + "postcheck_evidence_refs", + "cross_project_sync_ref", +] + +REVIEWER_CHECKS = [ + {"check_id": "change_ref_present", "instruction": "必須有可追溯的 change / incident ref。"}, + {"check_id": "actor_role_traceable", "instruction": "必須標示 actor role / team,不接受匿名端口變更。"}, + {"check_id": "decision_reason_present", "instruction": "decision 與 decision reason 必須同時存在。"}, + {"check_id": "affected_scope_matches_surface", "instruction": "affected scope 必須能對回既有 SSH / network surface。"}, + {"check_id": "ports_or_paths_redacted", "instruction": "端口、路徑、host alias 只能收脫敏摘要或 owner-provided ref。"}, + {"check_id": "before_after_state_refs", "instruction": "需有變更前後狀態 ref,不能只有口頭說明。"}, + {"check_id": "firewall_diff_metadata_only", "instruction": "firewall diff 僅收 metadata ref,不保存 raw firewall dump。"}, + {"check_id": "dependency_impact_present", "instruction": "必須列出受影響服務、agent、監控、公開入口或後台路徑。"}, + {"check_id": "customer_impact_review", "instruction": "若造成服務異常,需有 customer / product impact ref。"}, + {"check_id": "cross_project_sync_present", "instruction": "需標示已同步受影響產品 / Session / owner,不得單點改動。"}, + {"check_id": "maintenance_window_present", "instruction": "未來變更需有維護窗口;事故回補也需標記 break-glass。"}, + {"check_id": "rollback_owner_present", "instruction": "rollback owner 與 rollback plan 必須同時存在。"}, + {"check_id": "postcheck_evidence_present", "instruction": "post-check evidence 必須覆蓋 API / route / agent / monitoring。"}, + {"check_id": "secret_or_key_value_absent", "instruction": "不得包含 secret、SSH key、token、cookie 或私鑰內容。"}, + {"check_id": "no_runtime_authorization", "instruction": "驗收證據不等於允許 firewall / port / route 變更。"}, + {"check_id": "counts_transition_safe", "instruction": "只有 reviewer record 能更新 accepted count,且不得同時開 runtime gate。"}, +] + +OUTCOME_LANES = [ + {"lane_id": "waiting_change_evidence", "meaning": "尚未收到端口 / 防火牆變更證據;所有 accepted / runtime count 維持 0。"}, + {"lane_id": "quarantine_raw_firewall_dump", "meaning": "收到 raw firewall dump、secret 或 key material 時只能隔離。"}, + {"lane_id": "reject_unattributed_change", "meaning": "無 actor、無 owner、無 affected scope 或無 rollback 的變更不得驗收。"}, + {"lane_id": "request_impact_supplement", "meaning": "缺 before/after、impact、dependency、post-check 或 cross-project sync 時要求補件。"}, + {"lane_id": "ready_for_network_review", "meaning": "metadata 合格後,只能進 network / firewall reviewer review。"}, + {"lane_id": "incident_backfill_only", "meaning": "事故回補只能更新只讀 ledger,不得反向視為已批准操作。"}, + {"lane_id": "owner_review_only_update", "meaning": "只允許更新 reviewer ledger,不改 firewall、port、route 或 host。"}, + {"lane_id": "waiting_runtime_gate", "meaning": "即使證據 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", + "secret_value_collection", + "ssh_key_collection", + "raw_firewall_dump_storage", + "raw_key_material_storage", + "mark_change_evidence_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + "production_write", +] + + +def git_short_sha(root: Path) -> str: + try: + result = subprocess.run( + ["git", "rev-parse", "--short", "HEAD"], + cwd=root, + check=True, + capture_output=True, + text=True, + ) + return result.stdout.strip() + except Exception: + return "unknown" + + +def load_json(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def build_candidate(source: dict[str, Any]) -> dict[str, Any]: + surface_id = source["surface_id"] + return { + "change_evidence_candidate_id": f"port_firewall_change_evidence:{surface_id}", + "status": "waiting_change_evidence", + "source_acceptance_candidate_id": source["acceptance_candidate_id"], + "surface_id": surface_id, + "config_kind": source["config_kind"], + "control_tier": source["control_tier"], + "write_capable_surface": source["write_capable_surface"], + "expected_scope": source["expected_scope"], + "change_or_incident_ref": None, + "actor_role_or_team": "pending_change_evidence", + "decision": "pending_change_evidence", + "decision_reason": "pending_change_evidence", + "affected_scope": "pending_change_evidence", + "affected_host_or_route_aliases": [], + "affected_ports_or_paths_ref": None, + "before_state_ref": None, + "after_state_ref": None, + "firewall_rule_diff_ref": None, + "allowlist_or_denylist_ref": None, + "service_dependency_ref": None, + "customer_impact_ref": None, + "monitoring_alert_refs": [], + "cross_project_sync_ref": None, + "maintenance_window": "pending_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_plan_ref": None, + "validation_plan": "pending_change_evidence", + "postcheck_evidence_refs": [], + "communication_owner": "pending_change_evidence", + "break_glass_owner": "pending_change_evidence", + "change_freeze_rule": "pending_change_evidence", + "reviewer_outcome": "waiting_change_evidence", + "followup_owner": "pending_change_evidence", + "change_evidence_fields": CHANGE_EVIDENCE_FIELDS, + "required_evidence_fields": REQUIRED_EVIDENCE_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, + "change_evidence_received": False, + "change_evidence_accepted": False, + "change_evidence_rejected": False, + "change_evidence_quarantined": False, + "impact_supplement_requested": False, + "incident_backfill_only": True, + "actor_identified": False, + "affected_scope_accepted": False, + "before_state_accepted": False, + "after_state_accepted": False, + "firewall_rule_diff_accepted": False, + "port_policy_accepted": False, + "service_dependency_accepted": False, + "customer_impact_accepted": False, + "cross_project_sync_accepted": False, + "maintenance_window_accepted": False, + "rollback_owner_accepted": False, + "rollback_plan_accepted": False, + "validation_plan_accepted": False, + "postcheck_evidence_accepted": False, + "host_write_authorized": 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, + "sudo_action_authorized": False, + "deploy_ssh_action_authorized": False, + "route_smoke_authorized": False, + "public_gateway_reload_authorized": False, + "nginx_reload_authorized": False, + "host_restart_authorized": False, + "secret_value_collection_allowed": False, + "ssh_key_collection_allowed": False, + "runtime_gate": False, + "runtime_execution_authorized": False, + "production_write_authorized": False, + "action_buttons_allowed": 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 = [ + item + for item in source_report.get("acceptance_candidates", []) + if item.get("config_kind") in SOURCE_CONFIG_KINDS + ] + change_candidates = [build_candidate(item) for item in source_candidates] + write_capable = [item for item in change_candidates if item["write_capable_surface"]] + policy_or_exposure = [ + item + for item in change_candidates + if item["config_kind"] in {"k8s_network_policy", "k8s_nodeport_service", "wireguard_runbook"} + ] + + return { + "schema_version": "port_firewall_change_evidence_acceptance_v1", + "generated_at": report_time, + "git_commit": git_short_sha(root), + "source_acceptance_schema_version": source_report.get("schema_version"), + "source_acceptance_status": source_report.get("status"), + "status": "change_evidence_acceptance_ready_no_runtime_action", + "summary": { + "source_acceptance_candidate_count": source_report.get("summary", {}).get("acceptance_candidate_count", 0), + "change_evidence_candidate_count": len(change_candidates), + "write_capable_change_evidence_candidate_count": len(write_capable), + "policy_or_exposure_candidate_count": len(policy_or_exposure), + "change_evidence_field_count": len(CHANGE_EVIDENCE_FIELDS), + "required_evidence_field_count": len(REQUIRED_EVIDENCE_FIELDS), + "reviewer_check_count": len(REVIEWER_CHECKS), + "outcome_lane_count": len(OUTCOME_LANES), + "blocked_action_count": len(BLOCKED_ACTIONS), + "change_evidence_received_count": 0, + "change_evidence_accepted_count": 0, + "change_evidence_rejected_count": 0, + "change_evidence_quarantined_count": 0, + "impact_supplement_requested_count": 0, + "actor_identified_count": 0, + "affected_scope_accepted_count": 0, + "before_state_accepted_count": 0, + "after_state_accepted_count": 0, + "firewall_rule_diff_accepted_count": 0, + "port_policy_accepted_count": 0, + "service_dependency_accepted_count": 0, + "customer_impact_accepted_count": 0, + "cross_project_sync_accepted_count": 0, + "maintenance_window_accepted_count": 0, + "rollback_owner_accepted_count": 0, + "rollback_plan_accepted_count": 0, + "validation_plan_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "host_write_authorized_count": 0, + "ssh_read_authorized_count": 0, + "ssh_write_authorized_count": 0, + "live_firewall_read_authorized_count": 0, + "firewall_change_authorized_count": 0, + "port_change_authorized_count": 0, + "port_close_authorized_count": 0, + "port_open_authorized_count": 0, + "network_policy_apply_authorized_count": 0, + "nodeport_change_authorized_count": 0, + "wireguard_change_authorized_count": 0, + "sudo_action_authorized_count": 0, + "deploy_ssh_action_authorized_count": 0, + "route_smoke_authorized_count": 0, + "public_gateway_reload_authorized_count": 0, + "nginx_reload_authorized_count": 0, + "host_restart_authorized_count": 0, + "secret_value_collection_allowed_count": 0, + "ssh_key_collection_allowed_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + }, + "execution_boundaries": { + "change_evidence_acceptance_authorized": False, + "runtime_execution_authorized": False, + "production_write_authorized": False, + "live_host_read_authorized": False, + "host_write_authorized": 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, + "sudo_action_authorized": False, + "deploy_ssh_action_authorized": False, + "route_smoke_authorized": False, + "public_gateway_reload_authorized": False, + "nginx_reload_authorized": False, + "host_restart_authorized": False, + "secret_value_collection_allowed": False, + "ssh_key_collection_allowed": False, + "action_buttons_allowed": False, + "not_authorization": True, + }, + "change_evidence_fields": CHANGE_EVIDENCE_FIELDS, + "required_evidence_fields": REQUIRED_EVIDENCE_FIELDS, + "reviewer_checks": REVIEWER_CHECKS, + "outcome_lanes": OUTCOME_LANES, + "blocked_actions": BLOCKED_ACTIONS, + "change_evidence_candidates": change_candidates, + "next_steps": [ + "等待 owner-provided change / incident evidence;未收到前不得更新 accepted count。", + "收到證據後先檢查 actor、affected scope、before / after state、impact、rollback、post-check 與 cross-project sync。", + "metadata 合格也只能進 network / firewall reviewer review;端口、防火牆、NetworkPolicy、NodePort、WireGuard 與 route smoke 仍需獨立人工批准。", + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser(description="IwoooS 端口 / 防火牆變更證據驗收只讀帳本產生器") + parser.add_argument("--root", default=".", help="repo root") + parser.add_argument( + "--source-acceptance-report", + default="docs/security/ssh-network-owner-response-acceptance.snapshot.json", + help="ssh-network-owner-response-acceptance.py 輸出的 JSON", + ) + parser.add_argument("--output", help="寫出 JSON 報告") + parser.add_argument("--generated-at", help="固定報告時間,供 committed snapshot 使用") + args = parser.parse_args() + + root = Path(args.root).resolve() + source_report = load_json(root / args.source_acceptance_report) + report = build_report(root, source_report, args.generated_at) + payload = json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + + if args.output: + output = Path(args.output) + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(payload + "\n", encoding="utf-8") + else: + print(payload) + + summary = report["summary"] + print( + "PORT_FIREWALL_CHANGE_EVIDENCE_ACCEPTANCE_OK " + f"candidates={summary['change_evidence_candidate_count']} " + f"write_capable={summary['write_capable_change_evidence_candidate_count']} " + f"policy_or_exposure={summary['policy_or_exposure_candidate_count']} " + f"checks={summary['reviewer_check_count']} " + f"lanes={summary['outcome_lane_count']} " + f"accepted={summary['change_evidence_accepted_count']} " + f"runtime_gate={summary['runtime_gate_count']}", + file=sys.stderr, + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 8118e6923..051b46384 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -111,6 +111,9 @@ def validate(root: Path) -> None: ssh_network_owner_response_acceptance = load_json( security_dir / "ssh-network-owner-response-acceptance.snapshot.json" ) + port_firewall_change_evidence_acceptance = load_json( + security_dir / "port-firewall-change-evidence-acceptance.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" @@ -2855,18 +2858,20 @@ def validate(root: Path) -> None: assert_equal( "high_value_config_coverage.coverage_categories.ssh_network.coverage_percent", ssh_network_category["coverage_percent"], - 58, + 60, ) assert_equal( "high_value_config_coverage.coverage_categories.ssh_network.coverage_status", ssh_network_category["coverage_status"], - "owner_response_acceptance_ledger_ready_needs_network_owner", + "change_evidence_acceptance_ready_needs_network_owner_evidence", ) for evidence_ref in [ "docs/security/SSH-NETWORK-ACCESS-INVENTORY.md", "docs/security/ssh-network-access-inventory.snapshot.json", "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", ]: assert_contains( "high_value_config_coverage.coverage_categories.ssh_network.evidence_refs", @@ -3785,6 +3790,207 @@ def validate(root: Path) -> None: f"ssh_network_owner_response_acceptance.{item['acceptance_candidate_id']}.{false_key}", item[false_key], ) + assert_equal( + "port_firewall_change_evidence_acceptance.schema", + port_firewall_change_evidence_acceptance["schema_version"], + "port_firewall_change_evidence_acceptance_v1", + ) + assert_equal( + "port_firewall_change_evidence_acceptance.status", + port_firewall_change_evidence_acceptance["status"], + "change_evidence_acceptance_ready_no_runtime_action", + ) + assert_equal( + "port_firewall_change_evidence_acceptance.source_acceptance_schema_version", + port_firewall_change_evidence_acceptance["source_acceptance_schema_version"], + "ssh_network_owner_response_acceptance_v1", + ) + assert_equal( + "port_firewall_change_evidence_acceptance.source_acceptance_status", + port_firewall_change_evidence_acceptance["source_acceptance_status"], + "owner_response_acceptance_ledger_ready_no_runtime_action", + ) + expected_port_firewall_change_evidence_summary = { + "source_acceptance_candidate_count": 16, + "change_evidence_candidate_count": 14, + "write_capable_change_evidence_candidate_count": 6, + "policy_or_exposure_candidate_count": 5, + "change_evidence_field_count": 32, + "required_evidence_field_count": 16, + "reviewer_check_count": 16, + "outcome_lane_count": 8, + "blocked_action_count": 24, + "change_evidence_received_count": 0, + "change_evidence_accepted_count": 0, + "change_evidence_rejected_count": 0, + "change_evidence_quarantined_count": 0, + "impact_supplement_requested_count": 0, + "actor_identified_count": 0, + "affected_scope_accepted_count": 0, + "before_state_accepted_count": 0, + "after_state_accepted_count": 0, + "firewall_rule_diff_accepted_count": 0, + "port_policy_accepted_count": 0, + "service_dependency_accepted_count": 0, + "customer_impact_accepted_count": 0, + "cross_project_sync_accepted_count": 0, + "maintenance_window_accepted_count": 0, + "rollback_owner_accepted_count": 0, + "rollback_plan_accepted_count": 0, + "validation_plan_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "host_write_authorized_count": 0, + "ssh_read_authorized_count": 0, + "ssh_write_authorized_count": 0, + "live_firewall_read_authorized_count": 0, + "firewall_change_authorized_count": 0, + "port_change_authorized_count": 0, + "port_close_authorized_count": 0, + "port_open_authorized_count": 0, + "network_policy_apply_authorized_count": 0, + "nodeport_change_authorized_count": 0, + "wireguard_change_authorized_count": 0, + "sudo_action_authorized_count": 0, + "deploy_ssh_action_authorized_count": 0, + "route_smoke_authorized_count": 0, + "public_gateway_reload_authorized_count": 0, + "nginx_reload_authorized_count": 0, + "host_restart_authorized_count": 0, + "secret_value_collection_allowed_count": 0, + "ssh_key_collection_allowed_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + } + for key, expected in expected_port_firewall_change_evidence_summary.items(): + assert_equal( + f"port_firewall_change_evidence_acceptance.summary.{key}", + port_firewall_change_evidence_acceptance["summary"][key], + expected, + ) + for key, value in port_firewall_change_evidence_acceptance["execution_boundaries"].items(): + if key == "not_authorization": + assert_true(f"port_firewall_change_evidence_acceptance.execution_boundaries.{key}", value) + else: + assert_false(f"port_firewall_change_evidence_acceptance.execution_boundaries.{key}", value) + assert_equal( + "port_firewall_change_evidence_acceptance.change_evidence_candidates.count", + len(port_firewall_change_evidence_acceptance["change_evidence_candidates"]), + 14, + ) + port_firewall_change_candidate_ids = [ + item["change_evidence_candidate_id"] + for item in port_firewall_change_evidence_acceptance["change_evidence_candidates"] + ] + for change_evidence_candidate_id in [ + "port_firewall_change_evidence:deploy_alerts_ssh_path", + "port_firewall_change_evidence:host_ops_sudoers_wrapper", + "port_firewall_change_evidence:argocd_metrics_nodeport", + "port_firewall_change_evidence:velero_metrics_nodeport", + "port_firewall_change_evidence:wireguard_mesh_runbook", + "port_firewall_change_evidence:alert_rules_ssh_actions", + ]: + assert_contains( + "port_firewall_change_evidence_acceptance.change_evidence_candidates", + port_firewall_change_candidate_ids, + change_evidence_candidate_id, + ) + assert_equal( + "port_firewall_change_evidence_acceptance.reviewer_checks.count", + len(port_firewall_change_evidence_acceptance["reviewer_checks"]), + 16, + ) + assert_equal( + "port_firewall_change_evidence_acceptance.outcome_lanes.count", + len(port_firewall_change_evidence_acceptance["outcome_lanes"]), + 8, + ) + assert_equal( + "port_firewall_change_evidence_acceptance.blocked_actions.count", + len(port_firewall_change_evidence_acceptance["blocked_actions"]), + 24, + ) + for item in port_firewall_change_evidence_acceptance["change_evidence_candidates"]: + assert_equal( + f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.change_evidence_fields", + len(item["change_evidence_fields"]), + 32, + ) + assert_equal( + f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.required_evidence_fields", + len(item["required_evidence_fields"]), + 16, + ) + assert_equal( + f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.reviewer_checks", + len(item["reviewer_checks"]), + 16, + ) + assert_equal( + f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.outcome_lanes", + len(item["outcome_lanes"]), + 8, + ) + assert_equal( + f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.blocked_actions", + len(item["blocked_actions"]), + 24, + ) + assert_true( + f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.not_approval", + item["not_approval"], + ) + assert_true( + f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.incident_backfill_only", + item["incident_backfill_only"], + ) + for false_key in [ + "change_evidence_received", + "change_evidence_accepted", + "change_evidence_rejected", + "change_evidence_quarantined", + "impact_supplement_requested", + "actor_identified", + "affected_scope_accepted", + "before_state_accepted", + "after_state_accepted", + "firewall_rule_diff_accepted", + "port_policy_accepted", + "service_dependency_accepted", + "customer_impact_accepted", + "cross_project_sync_accepted", + "maintenance_window_accepted", + "rollback_owner_accepted", + "rollback_plan_accepted", + "validation_plan_accepted", + "postcheck_evidence_accepted", + "host_write_authorized", + "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", + "sudo_action_authorized", + "deploy_ssh_action_authorized", + "route_smoke_authorized", + "public_gateway_reload_authorized", + "nginx_reload_authorized", + "host_restart_authorized", + "secret_value_collection_allowed", + "ssh_key_collection_allowed", + "runtime_gate", + "runtime_execution_authorized", + "production_write_authorized", + "action_buttons_allowed", + ]: + assert_false( + f"port_firewall_change_evidence_acceptance.{item['change_evidence_candidate_id']}.{false_key}", + item[false_key], + ) assert_equal( "backup_restore_escrow_inventory.schema", backup_restore_escrow_inventory["schema_version"], @@ -5480,6 +5686,8 @@ def validate(root: Path) -> None: "docs/schemas/host_service_config_inventory_v1.schema.json", "docs/security/ssh-network-access-inventory.snapshot.json", "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/schemas/ssh_network_access_inventory_v1.schema.json", "docs/security/backup-restore-escrow-inventory.snapshot.json", "docs/security/BACKUP-RESTORE-ESCROW-INVENTORY.md", @@ -5592,6 +5800,22 @@ def validate(root: Path) -> None: "ssh_network_owner_response_acceptance_runtime_gate_count": 0, "ssh_network_owner_response_acceptance_action_button_count": 0, "ssh_network_owner_response_acceptance_coverage_percent_after_acceptance": 58, + "port_firewall_change_evidence_acceptance_first_layer": True, + "port_firewall_change_evidence_acceptance_candidate_count": 14, + "port_firewall_change_evidence_acceptance_write_capable_candidate_count": 6, + "port_firewall_change_evidence_acceptance_policy_or_exposure_candidate_count": 5, + "port_firewall_change_evidence_acceptance_required_evidence_field_count": 16, + "port_firewall_change_evidence_acceptance_reviewer_check_count": 16, + "port_firewall_change_evidence_acceptance_outcome_lane_count": 8, + "port_firewall_change_evidence_acceptance_blocked_action_count": 24, + "port_firewall_change_evidence_acceptance_received_count": 0, + "port_firewall_change_evidence_acceptance_accepted_count": 0, + "port_firewall_change_evidence_acceptance_actor_identified_count": 0, + "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, + "port_firewall_change_evidence_acceptance_action_button_count": 0, + "port_firewall_change_evidence_acceptance_coverage_percent_after_acceptance": 60, } for key, expected in expected_ssh_network_projection_summary.items(): assert_equal( @@ -15132,7 +15356,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: '58%'", + "{ key: 'sshNetwork', rank: 'P1-2', value: '60%'", ) assert_text_contains( "iwooos_page.high_value_config_control_coverage_backup_restore_percent", @@ -15188,6 +15412,19 @@ def validate(root: Path) -> None: "ssh_network_owner_response_acceptance_firewall_owner_accepted_count=0", "ssh_network_owner_response_acceptance_port_policy_accepted_count=0", "ssh_network_owner_response_acceptance_wireguard_cutover_accepted_count=0", + "port_firewall_change_evidence_acceptance_candidate_count=14", + "port_firewall_change_evidence_acceptance_write_capable_candidate_count=6", + "port_firewall_change_evidence_acceptance_policy_or_exposure_candidate_count=5", + "port_firewall_change_evidence_acceptance_required_evidence_field_count=16", + "port_firewall_change_evidence_acceptance_reviewer_check_count=16", + "port_firewall_change_evidence_acceptance_outcome_lane_count=8", + "port_firewall_change_evidence_acceptance_blocked_action_count=24", + "port_firewall_change_evidence_acceptance_received_count=0", + "port_firewall_change_evidence_acceptance_accepted_count=0", + "port_firewall_change_evidence_acceptance_actor_identified_count=0", + "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", "backup_restore_escrow_inventory_surface_count=38", "backup_restore_escrow_inventory_write_capable_surface_count=27", "backup_restore_escrow_inventory_runtime_gate_count=0", @@ -15211,6 +15448,9 @@ def validate(root: Path) -> None: "ssh_write_authorized=false", "sudo_action_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",