From bb459d59f905f1226aaf9bf298e6be1b8a84f7f9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 16 Jun 2026 11:42:38 +0800 Subject: [PATCH] =?UTF-8?q?feat(iwooos):=20=E6=96=B0=E5=A2=9E=20CD=20runne?= =?UTF-8?q?r=20secret=20=E4=BA=8B=E6=95=85=E5=9B=9E=E8=AE=80=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/messages/en.json | 4 +- apps/web/messages/zh-TW.json | 4 +- apps/web/src/app/[locale]/iwooos/page.tsx | 41 +- ...T-INJECTION-POST-INCIDENT-READBACK-PLAN.md | 122 ++ .../HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md | 2 + .../IWOOOS-CONFIG-CONTROL-INVENTORY.md | 6 + docs/security/IWOOOS-POSTURE-PROJECTION.md | 9 +- .../SECURITY-SUPPLY-CHAIN-PROGRESS.md | 8 +- ...-post-incident-readback-plan.snapshot.json | 1894 +++++++++++++++++ ...alue-config-control-coverage.snapshot.json | 24 +- .../iwooos-posture-projection.snapshot.json | 61 +- ...t-injection-post-incident-readback-plan.py | 489 +++++ .../high-value-config-control-coverage.py | 22 +- .../security/iwooos-config-control-guard.py | 54 +- .../security-mirror-progress-guard.py | 345 ++- 15 files changed, 3044 insertions(+), 41 deletions(-) create mode 100644 docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md create mode 100644 docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json create mode 100644 scripts/security/cd-runner-secret-injection-post-incident-readback-plan.py diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 8a1bf8556..588453c26 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -17860,7 +17860,7 @@ }, "workflowSecret": { "title": "工作流程 / 執行器 / 機密中繼資料", - "body": "Gitea 工作流程、執行器標籤、部署金鑰、webhook、分支保護、CODEOWNERS 與機密名稱已新增變更證據驗收;目前只收脫敏參照、執行紀錄代號、負責人與回復方案,不收明文值、hash、片段 token 或私鑰,也不修改工作流程、啟用執行器或輪替機密。" + "body": "Gitea 工作流程、執行器標籤、部署金鑰、webhook、分支保護、CODEOWNERS 與機密名稱已新增事故後回讀計畫,固定 5 個候選、33 個必填欄位、30 個審查檢查項、11 條結果分流與 52 類禁止動作。目前只收脫敏參照、執行紀錄代號、負責人與回復方案,不收明文值、hash、片段 token、runner token 或私鑰,也不修改工作流程、啟用執行器、dispatch workflow 或輪替機密。" }, "publicRuntime": { "title": "Public / admin / API runtime config", @@ -17953,7 +17953,7 @@ "items": { "workflowSecret": { "title": "工作流程 / 執行器 / 機密中繼資料", - "body": "持續部署、程式碼審查、部署通知、執行器證明與機密名稱一致性已新增變更證據驗收帳本;機密中繼資料成熟度為 68%,工作流程 / 執行器成熟度為 72%,但工作流程差異、執行器證明、機密名稱一致性、注入路徑、部署標記回讀、防護檢查、回復負責人與後檢證據仍全部為 0。" + "body": "持續部署、程式碼審查、部署通知、執行器證明與機密名稱一致性已新增事故後回讀計畫;機密中繼資料成熟度為 70%,工作流程 / 執行器成熟度為 74%,但事故後回讀 received / accepted、工作流程差異狀態、執行器證明、機密名稱一致性、注入路徑、部署標記回讀、Gitea run readback、log redaction、回復負責人與後檢證據仍全部為 0。" }, "dockerSystemd": { "title": "Docker / systemd 主機服務", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 8a1bf8556..588453c26 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -17860,7 +17860,7 @@ }, "workflowSecret": { "title": "工作流程 / 執行器 / 機密中繼資料", - "body": "Gitea 工作流程、執行器標籤、部署金鑰、webhook、分支保護、CODEOWNERS 與機密名稱已新增變更證據驗收;目前只收脫敏參照、執行紀錄代號、負責人與回復方案,不收明文值、hash、片段 token 或私鑰,也不修改工作流程、啟用執行器或輪替機密。" + "body": "Gitea 工作流程、執行器標籤、部署金鑰、webhook、分支保護、CODEOWNERS 與機密名稱已新增事故後回讀計畫,固定 5 個候選、33 個必填欄位、30 個審查檢查項、11 條結果分流與 52 類禁止動作。目前只收脫敏參照、執行紀錄代號、負責人與回復方案,不收明文值、hash、片段 token、runner token 或私鑰,也不修改工作流程、啟用執行器、dispatch workflow 或輪替機密。" }, "publicRuntime": { "title": "Public / admin / API runtime config", @@ -17953,7 +17953,7 @@ "items": { "workflowSecret": { "title": "工作流程 / 執行器 / 機密中繼資料", - "body": "持續部署、程式碼審查、部署通知、執行器證明與機密名稱一致性已新增變更證據驗收帳本;機密中繼資料成熟度為 68%,工作流程 / 執行器成熟度為 72%,但工作流程差異、執行器證明、機密名稱一致性、注入路徑、部署標記回讀、防護檢查、回復負責人與後檢證據仍全部為 0。" + "body": "持續部署、程式碼審查、部署通知、執行器證明與機密名稱一致性已新增事故後回讀計畫;機密中繼資料成熟度為 70%,工作流程 / 執行器成熟度為 74%,但事故後回讀 received / accepted、工作流程差異狀態、執行器證明、機密名稱一致性、注入路徑、部署標記回讀、Gitea run readback、log redaction、回復負責人與後檢證據仍全部為 0。" }, "dockerSystemd": { "title": "Docker / systemd 主機服務", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 2d0954c5b..f06aa4140 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -2117,8 +2117,8 @@ const highValueConfigControlCoverageBoundaries = [ 'public_gateway_owner_response_acceptance_outcome_lane_count=8', 'public_gateway_owner_response_acceptance_blocked_action_count=28', 'k8s_production_gitops_coverage_percent=66', - 'secret_metadata_coverage_percent=68', - 'gitea_workflow_runner_source_control_coverage_percent=72', + 'secret_metadata_coverage_percent=70', + 'gitea_workflow_runner_source_control_coverage_percent=74', 'public_admin_api_runtime_config_coverage_percent=66', 'ai_provider_model_routing_coverage_percent=64', 'ai_provider_owner_response_acceptance_candidate_count=8', @@ -2188,6 +2188,23 @@ const highValueConfigControlCoverageBoundaries = [ 'cd_runner_secret_injection_change_evidence_acceptance_postcheck_evidence_accepted_count=0', 'cd_runner_secret_injection_change_evidence_acceptance_runtime_approval_package_ready_count=0', 'cd_runner_secret_injection_change_evidence_acceptance_runtime_gate_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_candidate_count=5', + 'cd_runner_secret_injection_post_incident_readback_plan_c0_candidate_count=4', + 'cd_runner_secret_injection_post_incident_readback_plan_write_capable_candidate_count=5', + 'cd_runner_secret_injection_post_incident_readback_plan_required_readback_field_count=33', + 'cd_runner_secret_injection_post_incident_readback_plan_reviewer_check_count=30', + 'cd_runner_secret_injection_post_incident_readback_plan_outcome_lane_count=11', + 'cd_runner_secret_injection_post_incident_readback_plan_blocked_action_count=52', + 'cd_runner_secret_injection_post_incident_readback_plan_received_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_workflow_diff_state_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_runner_attestation_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_secret_name_parity_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_secret_injection_route_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_deploy_marker_readback_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_gitea_action_run_readback_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_log_redaction_readback_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_runtime_gate_count=0', 'k8s_argocd_change_evidence_acceptance_candidate_count=4', 'k8s_argocd_change_evidence_acceptance_c0_candidate_count=3', 'k8s_argocd_change_evidence_acceptance_write_capable_candidate_count=4', @@ -2497,7 +2514,7 @@ const criticalConfigPriorityItems: CriticalConfigPriorityItem[] = [ { key: 'nginxGateway', rank: 'P0-1', state: '92% / readback 0', icon: Server, tone: 'warn' }, { key: 'dnsTls', rank: 'P0-2', state: '78% / probe 0', icon: Route, tone: 'warn' }, { key: 'k8sArgocd', rank: 'P0-3', state: '66% / readback 0', icon: Cloud, tone: 'warn' }, - { key: 'workflowSecret', rank: 'P0-4', state: '68% / 72%', icon: GitBranch, tone: 'warn' }, + { key: 'workflowSecret', rank: 'P0-4', state: '70% / 74%', icon: GitBranch, tone: 'warn' }, { key: 'publicRuntime', rank: 'P0-5', state: '64% / route 0', icon: Network, tone: 'warn' }, { key: 'agentBounty', rank: 'P0-6', state: 'runtime 0', icon: Workflow, tone: 'locked' }, ] @@ -2542,8 +2559,8 @@ const criticalConfigPriorityBoundaries = [ 'public_runtime_config_change_evidence_acceptance_sensitive_string_scan_accepted_count=0', 'public_runtime_config_change_evidence_acceptance_runtime_approval_package_ready_count=0', 'public_runtime_config_change_evidence_acceptance_runtime_gate_count=0', - 'secret_metadata_coverage_percent=68', - 'gitea_workflow_runner_source_control_coverage_percent=72', + 'secret_metadata_coverage_percent=70', + 'gitea_workflow_runner_source_control_coverage_percent=74', 'cd_runner_secret_injection_change_evidence_acceptance_candidate_count=5', 'cd_runner_secret_injection_change_evidence_acceptance_c0_candidate_count=4', 'cd_runner_secret_injection_change_evidence_acceptance_write_capable_candidate_count=5', @@ -2559,6 +2576,20 @@ const criticalConfigPriorityBoundaries = [ 'cd_runner_secret_injection_change_evidence_acceptance_secret_injection_route_accepted_count=0', 'cd_runner_secret_injection_change_evidence_acceptance_runtime_approval_package_ready_count=0', 'cd_runner_secret_injection_change_evidence_acceptance_runtime_gate_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_candidate_count=5', + 'cd_runner_secret_injection_post_incident_readback_plan_c0_candidate_count=4', + 'cd_runner_secret_injection_post_incident_readback_plan_write_capable_candidate_count=5', + 'cd_runner_secret_injection_post_incident_readback_plan_required_readback_field_count=33', + 'cd_runner_secret_injection_post_incident_readback_plan_reviewer_check_count=30', + 'cd_runner_secret_injection_post_incident_readback_plan_outcome_lane_count=11', + 'cd_runner_secret_injection_post_incident_readback_plan_blocked_action_count=52', + 'cd_runner_secret_injection_post_incident_readback_plan_received_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_workflow_diff_state_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_runner_attestation_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_secret_name_parity_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_secret_injection_route_accepted_count=0', + 'cd_runner_secret_injection_post_incident_readback_plan_runtime_gate_count=0', 'k8s_argocd_change_evidence_acceptance_candidate_count=4', 'k8s_argocd_change_evidence_acceptance_c0_candidate_count=3', 'k8s_argocd_change_evidence_acceptance_write_capable_candidate_count=4', diff --git a/docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md b/docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md new file mode 100644 index 000000000..536451071 --- /dev/null +++ b/docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md @@ -0,0 +1,122 @@ +# CD / Runner / Secret injection 事故後回讀只讀計畫 + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-16 | +| 狀態 | `post_incident_readback_plan_ready_no_runtime_action` | +| 工具 | `scripts/security/cd-runner-secret-injection-post-incident-readback-plan.py` | +| Snapshot | `docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json` | +| Source evidence | `docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json` | +| runtime gate | `0` | + +## 1. 目的 + +此計畫補在 CD / runner / secret injection change evidence acceptance 之後,專門處理事故後回讀:workflow / runner / secret injection 相關異常或變更後,owner 必須回讀 actor、時間窗、workflow diff state、runner attestation、secret name parity、secret injection route、step-env secret guard、log redaction、deploy marker、Gitea run、webhook / notification receipt、before / after deploy state、rollback、post-check 與防再發。 + +它只處理 metadata-only evidence ref,不呼叫 Gitea / GitHub API、不讀 secret store、不讀 secret value、不修改 workflow、不啟用 runner、不 rotate secret、不 dispatch workflow、不觸發部署,也不把 CD success、deploy marker、workflow success、route `200`、runner online、AwoooP approval 或 UI 可見狀態當成 runtime 授權。 + +## 2. 固定範圍 + +| 指標 | 數值 | 解讀 | +|------|------|------| +| `readback_candidate_count` | `5` | CD pipeline、Code Review、Deploy alerts、Runner attestation、Secret parity / injection owner 五類候選 | +| `c0_readback_candidate_count` | `4` | CD、Code Review、Runner、Secret parity 為 C0 | +| `c1_readback_candidate_count` | `1` | Deploy alerts / monitoring route 為 C1 | +| `write_capable_readback_candidate_count` | `5` | 五類都可能影響 workflow、runner、secret injection、通知或部署路徑 | +| `secret_sensitive_readback_candidate_count` | `5` | 五類都必須檢查 secret value / hash / partial token / runner token 不可出現 | +| `runner_or_workflow_readback_candidate_count` | `5` | 五類都必須回讀 workflow / runner 邊界 | +| `deploy_or_run_readback_required_candidate_count` | `5` | 五類都需要 deploy marker 或 Gitea run readback / 不適用理由 | +| `required_readback_field_count` | `33` | 事故後回讀必填欄位 | +| `reviewer_check_count` | `30` | reviewer 必檢規則 | +| `outcome_lane_count` | `11` | 收件結果分流 | +| `blocked_action_count` | `52` | 明確禁止動作 | + +## 3. 必填事故後回讀欄位 + +每筆事故後回讀至少需要: + +1. `incident_or_change_ref` +2. `actor_attribution_ref` +3. `change_time_window_ref` +4. `change_intent_or_break_glass_ref` +5. `workflow_diff_state_ref` +6. `runner_attestation_state_ref` +7. `runner_executor_host_readback_ref` +8. `runner_workspace_cleanup_readback_ref` +9. `runner_permission_scope_ref` +10. `secret_name_parity_state_ref` +11. `secret_injection_route_state_ref` +12. `step_env_secret_guard_result_ref` +13. `log_redaction_readback_ref` +14. `deploy_marker_readback_ref` +15. `gitea_action_run_readback_ref` +16. `webhook_delivery_state_ref` +17. `deploy_key_branch_protection_codeowners_ref` +18. `notification_delivery_receipt_ref` +19. `before_after_deploy_state_ref` +20. `affected_route_or_service_state_ref` +21. `cross_project_sync_ref` +22. `rollback_validation_ref` +23. `postcheck_evidence_ref` +24. `post_change_monitoring_ref` +25. `recurrence_guard_ref` +26. `maintenance_window` +27. `rollback_owner` +28. `followup_owner` +29. `redacted_evidence_refs` +30. `no_secret_value_attestation` +31. `no_raw_workflow_payload_attestation` +32. `no_unredacted_log_attestation` +33. `no_false_green_attestation` + +以上欄位都只能保存脫敏 ref、commit、artifact pointer、run id、job id、ticket 或 hash。不得貼 secret value、secret hash、masked token、partial token、runner token、webhook secret、private key、deploy key private material、cookie、authorization header、完整 credential URL、未脫敏 action log 或未脫敏截圖。 + +## 4. Reviewer checks + +Reviewer 必須確認: + +- 來源 change evidence acceptance snapshot 是目前版本。 +- incident / change ref、actor、時間窗、intent / break-glass reason 都存在。 +- workflow diff state 只以 ref 呈現,不保存 raw workflow payload。 +- runner label、executor、host alias、workspace cleanup、permission scope 與 hosted runner 風險可追溯。 +- secret name parity、secret injection route、step-env secret guard 與 log redaction readback 完整。 +- deploy marker 與 Gitea run readback 只能作證據,不代表 runtime approval。 +- webhook delivery、deploy key、branch protection、CODEOWNERS、notification receipt 與跨專案同步影響已標示。 +- rollback validation、post-check、post-change monitoring 與 recurrence guard 已明確列出。 +- 不把 CD success、deploy marker、workflow success、route `200`、runner online、UI 可見或 AwoooP approval 當驗收。 + +## 5. Outcome lanes + +| Lane | 說明 | +|------|------| +| `waiting_post_incident_readback` | 尚未收到事故後回讀包 | +| `request_actor_or_time_supplement` | 缺 actor、時間窗、intent 或 break-glass reason | +| `request_workflow_runner_supplement` | 缺 workflow diff、runner attestation、executor / host、workspace cleanup 或 permission scope | +| `request_secret_injection_supplement` | 缺 secret name parity、injection route、step-env guard 或 log redaction readback | +| `request_deploy_run_supplement` | 缺 deploy marker、Gitea run readback、before / after deploy state 或 post-check | +| `request_webhook_notification_supplement` | 缺 webhook delivery、notification receipt、SRE route owner 或 cross-project sync | +| `quarantine_sensitive_payload` | 收到敏感值、runner token、webhook secret、private key、未脫敏 log 或截圖時隔離 | +| `reject_false_green_claim` | 把 CD success、deploy marker、workflow success、route `200`、runner online、UI 可見或 AwoooP approval 當驗收時拒收 | +| `ready_for_cd_runner_secret_post_incident_review` | metadata 合格後進 reviewer review | +| `recurrence_guard_backfill_required` | 需補防再發 guard、owner review、change freeze、automation block 或 runner isolation plan | +| `waiting_runtime_gate` | 即使 readback accepted,runtime gate 仍需獨立人工批准 | + +## 6. 禁止動作 + +此計畫明確禁止修改 workflow、未批准 dispatch workflow、啟用 / 安裝 / 重啟 runner、修改 runner label、使用 runner admin token、啟用 GitHub hosted runner、收集 secret value / hash / partial token / runner token / webhook secret / deploy key private material、保存 raw workflow payload / 未脫敏 action log、建立 / 更新 / rotate / 刪除 repo secret、讀 secret store、修改 secret injection path、修改 webhook、修改 deploy key、修改 branch protection、修改 CODEOWNERS、sync refs、force push、切 GitHub primary、停用 Gitea、把 CD pipeline 當 action 執行、注入 K8s secret、ArgoCD sync、production deploy、新增 action button 或開 runtime gate。 + +## 7. 完成度與邊界 + +| 工作 | 完成度 | 邊界 | +|------|--------|------| +| CD / Runner / Secret injection post-incident readback plan | `100%` | 只讀計畫與 snapshot 已建立 | +| Secret metadata 只讀治理成熟度 | `68% -> 70%` | 只代表事故後回讀欄位補齊,不代表可讀或可改 secret | +| Gitea workflow / runner source-control 只讀治理成熟度 | `72% -> 74%` | 只代表 workflow / runner 事故後回讀欄位補齊,不代表 workflow / runner 可修改 | +| post-incident readback received / accepted | `0%` | 尚未收到或接受任何事故後回讀 | +| runtime gate | `0` | 不開 workflow、runner、secret、deploy、ArgoCD 或 production action | + +## 8. 下一步 + +1. 要求 owner 只提供事故後 readback ref:workflow diff state、runner attestation、secret name parity、secret injection route、Gitea run readback、guard result、deploy marker、notification receipt、rollback owner 與 post-check evidence。 +2. reviewer 只檢查 metadata 完整性、no-secret-value、log redaction 與 no-false-green,不保存 raw workflow payload、raw action log 或 credential material。 +3. 若未來要進 runtime approval package,必須另開維護窗口、rollback owner、跨專案同步與 production post-check gate。 diff --git a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md index 75c900ea7..d99ecbef2 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -46,6 +46,8 @@ 固定數字為 `change_evidence_candidate_count=5`、`c0_change_evidence_candidate_count=4`、`c1_change_evidence_candidate_count=1`、`write_capable_candidate_count=5`、`local_workflow_file_count=33`、`local_referenced_secret_name_count=42`、`runner_label_count=5`、`required_evidence_field_count=19`、`reviewer_check_count=19`、`outcome_lane_count=8`、`blocked_action_count=32`。此更新讓 `secret_metadata` 從 `66%` 推進到 `68%`,讓 `gitea_workflow_runner_source_control` 從 `70%` 推進到 `72%`;workflow diff、runner attestation、secret name parity、secret injection route、deploy marker readback、guard result、post-check evidence、runtime approval package、workflow 修改、runner 啟用、secret rotation、repo secret change、Gitea action dispatch、production deploy 與 runtime gate 仍全部為 `0 / false`。 +2026-06-16 再新增 `docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md` 與 `docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json`,將同一批 CD pipeline、Code Review、Deploy alerts、Runner attestation 與 Secret parity / injection owner 轉成事故後回讀計畫。固定 `readback_candidate_count=5`、`c0_readback_candidate_count=4`、`c1_readback_candidate_count=1`、`write_capable_readback_candidate_count=5`、`required_readback_field_count=33`、`reviewer_check_count=30`、`outcome_lane_count=11`、`blocked_action_count=52`,讓 `secret_metadata` 從 `68%` 推進到 `70%`,讓 `gitea_workflow_runner_source_control` 從 `72%` 推進到 `74%`,高價值配置平均維持 `71%`,需 live evidence 類別仍為 `9`。此更新只補上 actor、時間窗、workflow diff state、runner executor / host、workspace cleanup、permission scope、secret name parity、secret injection route、step-env secret guard、log redaction、deploy marker / Gitea run、webhook / notification receipt、before / after deploy state、跨專案同步、rollback、post-check、防再發與 no-false-green 的脫敏回讀欄位;post-incident readback received / accepted、workflow 修改、dispatch、runner 變更、repo secret 變更、secret value collection、secret injection change、webhook / deploy key / branch protection / CODEOWNERS 變更、Gitea action dispatch、K8s secret injection、ArgoCD sync、production deploy、runtime gate 與 action button 仍全部為 `0 / false`。 + ## 1.2b 2026-06-15 Public / Admin / API runtime config 變更證據驗收 已新增 `docs/security/PUBLIC-RUNTIME-CONFIG-CHANGE-EVIDENCE-ACCEPTANCE.md` 與 `docs/security/public-runtime-config-change-evidence-acceptance.snapshot.json`,將公開產品頁、AwoooP 後台、API / CORS、frontend env、Sentry tunnel、webhook / callback 與跨產品 runtime route 轉成 metadata-only 變更證據驗收帳本。 diff --git a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md index a217a83c9..d4428dad5 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -77,6 +77,12 @@ 此更新讓 `secret_metadata` 類別成熟度從 `66%` 推進到 `68%`,讓 `gitea_workflow_runner_source_control` 類別成熟度從 `70%` 推進到 `72%`。它只表示 workflow diff、runner owner attestation、secret name parity、secret injection route、Gitea run readback、guard result、rollback owner 與 post-check evidence 已有收件驗收規則;workflow 修改、workflow dispatch、runner 啟用 / 重啟、GitHub hosted runner、secret value / hash / partial token 收集、secret store read、secret 建立 / 更新 / rotate / 刪除、webhook 修改、deploy key 修改、branch protection / CODEOWNERS 修改、refs sync、force push、GitHub primary switch、Gitea 停用、production deploy、runtime gate 仍全部為 `0 / false`。 +### 0.3c-1 2026-06-16 CD / Runner / Secret 注入事故後回讀計畫 + +`cd_runner_secret_injection_post_incident_readback_plan_v1` 已把同一批 CD pipeline、Code Review、Deploy alerts、Runner attestation 與 Repository secret name parity / injection owner 轉成事故後回讀計畫。固定 `candidates=5`、`c0=4`、`c1=1`、`write_capable=5`、`readback_fields=44`、`required_readback_fields=33`、`reviewer_checks=30`、`outcome_lanes=11`、`blocked_actions=52`。 + +此更新讓 `secret_metadata` 類別成熟度從 `68%` 推進到 `70%`,讓 `gitea_workflow_runner_source_control` 類別成熟度從 `72%` 推進到 `74%`。它只表示 workflow diff state、runner attestation、executor / host、workspace cleanup、permission scope、secret name parity、secret injection route、step-env secret guard、log redaction、deploy marker / Gitea run、webhook / notification receipt、before / after deploy state、cross-project sync、rollback、post-check、post-change monitoring、recurrence guard 與 no-false-green 已有事故後脫敏回讀欄位;post-incident readback received / accepted、workflow 修改、workflow dispatch、runner 變更、GitHub hosted runner、repo secret 變更、secret value collection、secret injection change、webhook / deploy key / branch protection / CODEOWNERS 變更、Gitea action dispatch、K8s secret injection、ArgoCD sync、production deploy、runtime gate 仍全部為 `0 / false`。 + ### 0.3d 2026-06-15 Public / Admin / API runtime config 變更證據驗收 `public_runtime_config_change_evidence_acceptance_v1` 已把公開產品頁、AwoooP 後台、API / CORS、frontend env、Sentry tunnel、webhook / callback 與跨產品 runtime route 轉成 metadata-only 變更證據驗收只讀帳本。固定 `candidates=6`、`c0=5`、`c1=1`、`write_capable=6`、`source_refs=20`、`required_evidence_fields=21`、`reviewer_checks=21`、`outcome_lanes=8`、`blocked_actions=32`。 diff --git a/docs/security/IWOOOS-POSTURE-PROJECTION.md b/docs/security/IWOOOS-POSTURE-PROJECTION.md index e47b82b9b..37f585664 100644 --- a/docs/security/IWOOOS-POSTURE-PROJECTION.md +++ b/docs/security/IWOOOS-POSTURE-PROJECTION.md @@ -3,7 +3,7 @@ | 項目 | 內容 | |------|------| | 日期 | 2026-06-15 | -| 狀態 | 草案;P0 governance 總帳已建立;高價值配置 Owner Packet count sync、K8s / ArgoCD 與 Public Gateway / Nginx 事故後回讀投影已完成 | +| 狀態 | 草案;P0 governance 總帳已建立;高價值配置 Owner Packet count sync、K8s / ArgoCD、Public Gateway / Nginx、Monitoring 與 CD / Runner / Secret 事故後回讀投影已完成 | | Schema | `docs/schemas/iwooos_posture_projection_v1.schema.json` | | Snapshot | `docs/security/iwooos-posture-projection.snapshot.json` | | 模式 | `mirror_only` | @@ -41,6 +41,12 @@ 此同步只代表前端可以顯示監控 / 告警 / 可觀測性事故後回讀計畫與邊界;`post_incident_readback_received_count`、`post_incident_readback_accepted_count`、`receiver_receipt_readback_accepted_count`、`stale_pending_resolved_review_accepted_count`、`silence_mute_dedup_inhibit_review_accepted_count`、`alert_chain_health_readback_accepted_count`、`runtime_gate_count` 與 `action_button_count` 仍全部維持 `0`。不得把 route `200`、dashboard up、container up、receiver reachable、CD success 或 UI 可見視為告警鏈路驗收。 +## 1.5 2026-06-16 CD / Runner / Secret injection 事故後回讀投影 + +`cd_runner_secret_injection_post_incident_readback_plan_v1` 已投影到 `iwooos-posture-projection.snapshot.json` 與前台 marker。固定 `candidate_count=5`、`c0_candidate_count=4`、`write_capable_candidate_count=5`、`required_readback_field_count=33`、`reviewer_check_count=30`、`outcome_lane_count=11`、`blocked_action_count=52`,並讓 `secret_metadata_coverage_percent=70`、`gitea_workflow_runner_source_control_coverage_percent=74`。 + +此同步只代表前端可以顯示 CD / Runner / Secret injection 事故後回讀計畫與邊界;`post_incident_readback_received_count`、`post_incident_readback_accepted_count`、`workflow_diff_state_accepted_count`、`runner_attestation_accepted_count`、`secret_name_parity_accepted_count`、`secret_injection_route_accepted_count`、`deploy_marker_readback_accepted_count`、`gitea_action_run_readback_accepted_count`、`log_redaction_readback_accepted_count`、`runtime_gate_count` 與 `action_button_count` 仍全部維持 `0`。不得把 CD success、deploy marker、workflow success、route `200`、runner online、AwoooP approval 或 UI 可見視為資安驗收。 + ## 2. 來源 IwoooS 首版只讀取或對齊以下已提交 evidence: @@ -54,6 +60,7 @@ IwoooS 首版只讀取或對齊以下已提交 evidence: | `public_gateway_post_incident_readback_plan_v1` | Public Gateway / Nginx 事故後回讀計畫、92% 子項成熟度、30 個必填欄位、41 類 blocked action、runtime gate 0 | | `k8s_argocd_post_incident_readback_plan_v1` | K8s / ArgoCD 事故後回讀計畫、66% 子項成熟度、31 個必填欄位、41 類 blocked action、runtime gate 0 | | `monitoring_post_incident_readback_plan_v1` | Monitoring / Alerting / Observability 事故後回讀計畫、70% 子項成熟度、30 個必填欄位、53 類 blocked action、runtime gate 0 | +| `cd_runner_secret_injection_post_incident_readback_plan_v1` | CD / Runner / Secret injection 事故後回讀計畫、secret metadata 70%、workflow / runner 74%、33 個必填欄位、52 類 blocked action、runtime gate 0 | | `kali_integration_status_v1` | Kali 112 observe-only 整合態勢 | | `vibework_iwooos_onboarding_handoff_v1` | VibeWork repo / product / surface / owner / evidence refs / 獨立產品邊界只讀 handoff | | `docs/LOGBOOK.md` | 部署 marker、Gitea run 與 rollout risk 邊界紀錄 | diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index 63f8b7a01..27f7bad92 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -3,7 +3,7 @@ | 項目 | 內容 | |------|------| | 日期 | 2026-06-15 | -| 狀態 | IwoooS 64% 只讀治理推進中;高價值配置集中 guard、Package / Docker 供應鏈 repo-only baseline 與 Package / Docker 供應鏈 owner policy gate 已完成;Frontend public sensitive surface guard、Backup / Restore / Escrow owner response acceptance backfill、Monitoring / Alerting / Observability no-false-green owner response acceptance、Host Service change evidence acceptance、Host Service post-incident readback plan、AI provider / model routing owner response acceptance、CD / Runner / Secret 注入變更證據驗收、Public / Admin / API runtime config 變更證據驗收、K8s / ArgoCD post-incident readback plan 與 Public Gateway / Nginx post-incident readback plan 已本地完成;端口 / 防火牆變更證據驗收、主機服務事故回補與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 | +| 狀態 | IwoooS 64% 只讀治理推進中;高價值配置集中 guard、Package / Docker 供應鏈 repo-only baseline 與 Package / Docker 供應鏈 owner policy gate 已完成;Frontend public sensitive surface guard、Backup / Restore / Escrow owner response acceptance backfill、Monitoring / Alerting / Observability no-false-green owner response acceptance、Host Service change evidence acceptance、Host Service post-incident readback plan、AI provider / model routing owner response acceptance、CD / Runner / Secret 注入變更證據驗收、CD / Runner / Secret 注入事故後回讀計畫、Public / Admin / API runtime config 變更證據驗收、K8s / ArgoCD post-incident readback plan、Monitoring / Alerting / Observability post-incident readback plan 與 Public Gateway / Nginx post-incident readback plan 已本地完成;端口 / 防火牆變更證據驗收、主機服務事故回補與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 | | 本階段完成 | 資安供應鏈 contract manifest + Source Control Approval Board + Draft Reconcile Plan + Ref Detail Diff + Ref Truth Classification + Source Control Ref Truth Owner Response 收件包 + GitHub Primary Readiness Gate + GitHub Primary Rollback ADR + GitHub Target Owner Decision Response 收件包 + Gitea 認證清冊匯出請求 + Gitea 認證清冊匯入驗收契約 + Gitea 清冊覆蓋 Owner Attestation + Gitea Owner Attestation Approval Lane 對齊 + Gitea Owner Attestation Response 收件包 + Workflow / Secret Name Inventory + Workflow / Secret Name Local Evidence + Workflow / Secret Name Redacted Export Request + Workflow / Secret Name Owner Response 收件包 + Source Control Owner Response Validation Rollup + Kali 112 live integration status + Security Finding contract + Kali scan scope approval package + Security Approval Queue + S3 人工批准 Gate + S3 人工決策紀錄 + S3 人工審查封包 + S3 人工決策狀態轉移 + S3 後續 runtime gate 準備契約 + 鏡像 readiness index + 鏡像接收計畫 + 鏡像事件信封 + 鏡像路由矩陣 + 鏡像驗收契約 + 鏡像隔離契約 + 鏡像 dry-run 報告契約 + 鏡像狀態彙整契約 + IwoooS 前端態勢入口 + IwoooS posture projection contract + IwoooS 既有前端資安頁面整合 + IwoooS 覆蓋與邊界矩陣 + IwoooS 只讀資安處理旅程 + IwoooS owner evidence readiness board + IwoooS host coverage view + IwoooS host action gate matrix + IwoooS host evidence readiness board + IwoooS host evidence collection order + IwoooS host evidence intake preflight + IwoooS host evidence review outcome lanes + IwoooS host evidence review handoff packets + IwoooS host evidence reviewer checklist + IwoooS host evidence reviewer outcome lanes + IwoooS host owner decision candidate packets + IwoooS host owner decision review checklist + IwoooS host owner decision review outcome lanes + IwoooS host owner decision record draft packets + IwoooS host owner decision record draft review checklist + IwoooS host owner decision record draft review outcome lanes + IwoooS host owner decision record write-up packets + IwoooS host owner decision record write-up review checklist + IwoooS host owner decision record write-up review outcome lanes + IwoooS host owner decision record formal candidate packets + IwoooS host owner decision record formal candidate review checklist + IwoooS host owner decision record formal candidate review outcome lanes + IwoooS host owner decision record formal record queue packets + IwoooS host owner decision record formal record queue review checklist + IwoooS host owner decision record formal record queue review outcome lanes + IwoooS host owner decision record human handoff readiness packets + IwoooS host owner decision record human handoff readiness review checklist + IwoooS host owner decision record human handoff readiness review outcome lanes + IwoooS host owner decision record human record owner review candidate packets + IwoooS host owner decision record human record owner review candidate checklist + IwoooS host owner decision record human record owner review candidate outcome lanes + IwoooS host owner decision record human record owner review preparation packets + IwoooS host owner decision record human record owner review preparation checklist + IwoooS progress acceleration lanes + IwoooS owner response next-action focus + IwoooS S4.9 owner response preflight + IwoooS S4.9 owner response request templates + IwoooS progress hold movement gates + IwoooS AwoooP read-only landing readiness + IwoooS AwoooP cross-session handoff packets + AwoooP 首頁 IwoooS 資安鏡像候選 + AwoooP 工作鏈路 IwoooS 資安鏡像候選 + AwoooP 審批佇列 IwoooS owner response 只讀焦點 | | 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP 執行監控 IwoooS 執行狀態只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 + IwoooS GitHub 主要來源就緒度只讀狀態板 + AwoooP 工作鏈路 GitHub 主要來源就緒度只讀工作項 + AwoooP 合約儀表板 GitHub 主要來源就緒度合約只讀候選 + AwoooP 審批佇列 GitHub 主要來源就緒度審批邊界 + AwoooP 首頁 GitHub 主要來源就緒度只讀摘要 + AwoooP 租戶管理 GitHub 主要來源就緒度租戶範圍 + AwoooP 執行監控 GitHub 主要來源就緒度執行邊界 + IwoooS / AwoooP 資安可視區塊繁體中文呈現防護檢查 + AwoooP 執行詳情 / 審批詳情繁體中文呈現防護檢查 + AwoooP 首頁負責人回覆驗收總覽 + AwoooP 工作鏈路負責人回覆驗收只讀工作項 + AwoooP 合約儀表板負責人回覆驗收契約只讀候選 + AwoooP 審批佇列負責人回覆驗收只讀審查邊界 + AwoooP 租戶管理負責人回覆驗收租戶範圍 + AwoooP 執行監控負責人回覆驗收執行邊界 + AwoooP 執行詳情負責人回覆驗收詳情邊界 + AwoooP 審批決策負責人回覆驗收審批邊界 + IwoooS AwoooP 資安入口覆蓋狀態板 + IwoooS 階段式資安收斂節奏圖 + IwoooS 下一步人工收件作戰板 + IwoooS 人工回覆安全驗收閘道 + IwoooS 人工回覆審查結果分流 + IwoooS 人工決策準備佇列 + IwoooS 人工決策紀錄草稿防誤用 + IwoooS 人工決策正式紀錄負責人指派確認準備包 + IwoooS 人工決策正式紀錄負責人指派確認清單 + IwoooS 人工決策正式紀錄負責人指派確認結果分流 + IwoooS 人工決策正式紀錄負責人指派決策準備包 + IwoooS 人工決策正式紀錄負責人指派決策檢查清單 + IwoooS S4.9 負責人回覆封套欄位 + IwoooS S4.9 負責人回覆封套送件前檢查 + IwoooS S4.9 負責人回覆封套送件前結果分流 + IwoooS S4.9 負責人回覆送件請求草稿 + IwoooS S4.9 負責人回覆送件鏈路摘要 + IwoooS 低摩擦分階段收斂主控 + IwoooS 低摩擦下一步行動邊界 + IwoooS 64% 進度移動訊號驗收條 + IwoooS 第一個進度解鎖路徑 + IwoooS 第一解鎖證據包 + IwoooS 第一解鎖證據包預檢分流 + IwoooS 第一解鎖證據包補件路徑 + IwoooS 第一解鎖證據包補件送審前檢查 + IwoooS 第一解鎖證據包補件送審結果分流 + IwoooS 第一解鎖證據包 reviewer 指派準備包 + IwoooS 第一解鎖證據包 reviewer 指派前檢查 + IwoooS 第一解鎖證據包 reviewer 指派前檢查結果分流 + IwoooS 正式只讀 landing 與 Kali 112 只讀證據進度重估 | | 本階段追加補充 | IwoooS 目前具體工作地圖 + IwoooS 目前具體交付清單 + IwoooS 目前阻塞與解除條件 + IwoooS 三軸進度與全產品套用範圍 + IwoooS 全產品分階段套用台帳 + IwoooS 全產品 rollout 波次驗收門檻 + IwoooS 全產品 rollout 驗收結果分流 + IwoooS 全產品證據接線地圖 + IwoooS 全產品證據接線預檢 + IwoooS 全產品證據接線預檢結果分流 + IwoooS 全產品預檢補件回收台帳 + IwoooS 全產品補件重試門檻 + IwoooS 全產品重試結果分流 + IwoooS 全產品人工審查候選準備 + IwoooS 全產品人工審查候選預檢 + IwoooS 全產品人工審查候選預檢結果分流 + IwoooS 全產品人工審查候選預檢補件回收台帳 + IwoooS 全產品人工審查候選預檢補件重試門檻 + IwoooS 全產品只讀套用快照 + P2-145 owner response acceptance gate 正式驗證完成 | @@ -76,6 +76,12 @@ 同步邊界:IwoooS headline 維持 `64%`,active runtime gate 維持 `0`;workflow diff、runner attestation、secret name parity、secret injection route、deploy marker readback、guard result、postcheck evidence、runtime approval package、runtime gate 與 action buttons 全部仍為 `0 / false`。本段只更新文件、snapshot、guard、覆蓋矩陣與前端 marker,不呼叫 Gitea / GitHub API、不讀 secret store、不讀 secret value、不修改 workflow、不啟用 runner、不 rotate secret、不 dispatch workflow、不觸發部署。 +## 0.00aaaa0 2026-06-16 CD / Runner / Secret 注入事故後回讀計畫 + +本輪把 CD pipeline、程式碼審查、部署通知、執行器證明與 repository secret name parity / injection owner 從 change evidence acceptance 再補一層事故後回讀計畫:`cd_runner_secret_injection_post_incident_readback_plan_v1` 固定 `candidates=5`、`c0=4`、`c1=1`、`write_capable=5`、`readback_fields=44`、`required_readback_fields=33`、`reviewer_checks=30`、`outcome_lanes=11`、`blocked_actions=52`,並讓 `secret_metadata` 只讀治理成熟度 `68% -> 70%`、`gitea_workflow_runner_source_control` 只讀治理成熟度 `72% -> 74%`,高價值配置平均只讀成熟度仍維持 `71%`。新增要求包含 actor、change time window、workflow diff state、runner attestation、executor / host、workspace cleanup、permission scope、secret name parity、secret injection route、step-env secret guard、log redaction、deploy marker / Gitea run、webhook / notification receipt、before / after deploy state、cross-project sync、rollback validation、post-check、post-change monitoring、recurrence guard 與 no-false-green attestation。 + +同步邊界:IwoooS headline 維持 `64%`,active runtime gate 維持 `0`;post-incident readback received / accepted、workflow diff state accepted、runner attestation accepted、secret name parity accepted、secret injection route accepted、deploy marker readback accepted、Gitea run readback accepted、log redaction readback accepted、workflow modification、workflow dispatch、runner change、repo secret change、secret injection change、webhook / deploy key / branch protection / CODEOWNERS change、K8s secret injection、ArgoCD sync、production deploy、runtime gate 與 action buttons 全部仍為 `0 / false`。本段只更新文件、snapshot、guard、覆蓋矩陣、投影契約與前端 marker,不呼叫 Gitea / GitHub API、不讀 secret store、不讀 secret value、不修改 workflow、不啟用 runner、不 rotate secret、不 dispatch workflow、不觸發部署。 + ## 0.00aaa 2026-06-15 K8s / ArgoCD GitOps 變更證據驗收 本輪把 K8s / ArgoCD 從 owner response acceptance 推進到 GitOps 變更證據驗收只讀帳本:`k8s_argocd_change_evidence_acceptance_v1` 固定 `candidates=4`、`c0=3`、`write_capable=4`、`required_evidence_fields=18`、`reviewer_checks=18`、`outcome_lanes=8`、`blocked_actions=28`,並讓 `k8s_production_gitops` 只讀治理成熟度 `62% -> 64%`,高價值配置平均只讀成熟度仍維持 `68%`。這是 metadata-only 收件驗收,不是 change evidence received / accepted、runtime approval package、ArgoCD API read、ArgoCD sync、kubectl action、Helm upgrade、NetworkPolicy apply、NodePort change、RBAC change、live cluster read、production write 或 runtime gate。 diff --git a/docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json b/docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json new file mode 100644 index 000000000..f7842e0d5 --- /dev/null +++ b/docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json @@ -0,0 +1,1894 @@ +{ + "blocked_actions": [ + "modify_workflow", + "workflow_dispatch_without_approval", + "enable_runner", + "change_runner_label", + "install_runner", + "restart_runner", + "use_runner_admin_token", + "enable_github_hosted_runner", + "collect_secret_value", + "collect_secret_hash", + "collect_partial_token", + "collect_masked_token", + "collect_runner_token", + "collect_webhook_secret", + "collect_deploy_key_private_material", + "collect_cookie_or_authorization_header", + "store_raw_workflow_payload", + "store_unredacted_action_log", + "create_repo_secret", + "update_repo_secret", + "rotate_secret", + "delete_secret", + "read_secret_store", + "change_secret_injection_path", + "modify_webhook", + "change_webhook_secret", + "modify_deploy_key", + "rotate_deploy_key", + "change_branch_protection", + "change_codeowners", + "sync_refs", + "force_push", + "switch_github_primary", + "disable_gitea", + "run_cd_pipeline_as_action", + "inject_k8s_secret", + "argocd_sync", + "production_deploy", + "accept_cd_success_as_security_acceptance", + "accept_deploy_marker_as_runtime_approval", + "accept_workflow_success_as_all_green", + "accept_runner_online_as_attestation", + "accept_route_200_as_deploy_acceptance", + "accept_ui_visible_as_runtime_approval", + "skip_log_redaction_review", + "skip_secret_name_parity", + "skip_runner_attestation", + "skip_cross_project_sync", + "skip_rollback_validation", + "skip_post_change_monitoring", + "open_runtime_gate", + "add_action_button" + ], + "execution_boundaries": { + "action_buttons_allowed": false, + "argocd_sync_authorized": false, + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "codeowners_change_authorized": false, + "deploy_key_change_authorized": false, + "deploy_key_private_material_collection_allowed": false, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "k8s_secret_injection_authorized": false, + "not_authorization": true, + "partial_token_collection_allowed": false, + "production_deploy_authorized": false, + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "runner_change_authorized": false, + "runner_token_collection_allowed": false, + "runtime_execution_authorized": false, + "secret_hash_collection_allowed": false, + "secret_injection_change_authorized": false, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "webhook_modification_authorized": false, + "webhook_secret_collection_allowed": false, + "workflow_dispatch_authorized": false, + "workflow_modification_authorized": false + }, + "generated_at": "2026-06-16T00:30:00+08:00", + "git_commit": "95be78bd", + "mode": "metadata_only_no_secret_value_no_workflow_runner_secret_change", + "operator_interpretation": [ + "此計畫只描述 CD / runner / secret injection 事故後如何回讀,不是 workflow、runner 或 secret 變更批准。", + "secret 只能以名稱、scope、present-absent、owner 與 redacted evidence ref 呈現,不得保存 value、hash、partial token 或 runner token。", + "CD success、deploy marker、workflow success、route 200、runner online、AwoooP approval 與 UI 可見狀態都不能被解讀成 runtime gate 已開。", + "未來若要修改 workflow、runner、secret injection、webhook、deploy key、branch protection、CODEOWNERS、refs 或 production deploy,仍需獨立維護窗口、rollback owner、跨專案同步與 runtime approval package。" + ], + "outcome_lanes": [ + { + "lane_id": "waiting_post_incident_readback", + "meaning": "尚未收到 CD / runner / secret injection 事故回讀包;所有 accepted / runtime count 維持 0。" + }, + { + "lane_id": "request_actor_or_time_supplement", + "meaning": "缺 actor、change time window、intent 或 break-glass reason 時要求補件。" + }, + { + "lane_id": "request_workflow_runner_supplement", + "meaning": "缺 workflow diff、runner attestation、executor / host、workspace cleanup 或 permission scope 時要求補件。" + }, + { + "lane_id": "request_secret_injection_supplement", + "meaning": "缺 secret name parity、injection route、step-env guard 或 log redaction readback 時要求補件。" + }, + { + "lane_id": "request_deploy_run_supplement", + "meaning": "缺 deploy marker、Gitea run readback、before / after deploy state 或 post-check 時要求補件。" + }, + { + "lane_id": "request_webhook_notification_supplement", + "meaning": "缺 webhook delivery、notification receipt、SRE route owner 或 cross-project sync 時要求補件。" + }, + { + "lane_id": "quarantine_sensitive_payload", + "meaning": "收到 secret value、hash、runner token、webhook secret、private key、cookie、credential URL、未脫敏 log 或截圖時只能隔離。" + }, + { + "lane_id": "reject_false_green_claim", + "meaning": "把 CD success、deploy marker、workflow success、route 200、runner online、UI 可見或 AwoooP approval 當驗收時拒收。" + }, + { + "lane_id": "ready_for_cd_runner_secret_post_incident_review", + "meaning": "metadata 合格後,只能進 reviewer review。" + }, + { + "lane_id": "recurrence_guard_backfill_required", + "meaning": "需補防再發 guard、owner review、change freeze、automation block 或 runner isolation plan。" + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "即使 readback accepted,runtime gate 仍需獨立人工批准。" + } + ], + "readback_candidates": [ + { + "action_buttons_allowed": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_route_or_service_state_accepted": false, + "affected_route_or_service_state_ref": null, + "affected_scope": "main push CD、Harbor build / push、K8s secret injection、ArgoCD deploy marker、post-deploy checks", + "argocd_sync_authorized": false, + "before_after_deploy_state_accepted": false, + "before_after_deploy_state_ref": null, + "blocked_actions": [ + "modify_workflow", + "workflow_dispatch_without_approval", + "enable_runner", + "change_runner_label", + "install_runner", + "restart_runner", + "use_runner_admin_token", + "enable_github_hosted_runner", + "collect_secret_value", + "collect_secret_hash", + "collect_partial_token", + "collect_masked_token", + "collect_runner_token", + "collect_webhook_secret", + "collect_deploy_key_private_material", + "collect_cookie_or_authorization_header", + "store_raw_workflow_payload", + "store_unredacted_action_log", + "create_repo_secret", + "update_repo_secret", + "rotate_secret", + "delete_secret", + "read_secret_store", + "change_secret_injection_path", + "modify_webhook", + "change_webhook_secret", + "modify_deploy_key", + "rotate_deploy_key", + "change_branch_protection", + "change_codeowners", + "sync_refs", + "force_push", + "switch_github_primary", + "disable_gitea", + "run_cd_pipeline_as_action", + "inject_k8s_secret", + "argocd_sync", + "production_deploy", + "accept_cd_success_as_security_acceptance", + "accept_deploy_marker_as_runtime_approval", + "accept_workflow_success_as_all_green", + "accept_runner_online_as_attestation", + "accept_route_200_as_deploy_acceptance", + "accept_ui_visible_as_runtime_approval", + "skip_log_redaction_review", + "skip_secret_name_parity", + "skip_runner_attestation", + "skip_cross_project_sync", + "skip_rollback_validation", + "skip_post_change_monitoring", + "open_runtime_gate", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_intent_or_break_glass_ref": null, + "change_time_window_ref": null, + "codeowners_change_authorized": false, + "control_tier": "C0", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "deploy_key_branch_protection_codeowners_accepted": false, + "deploy_key_branch_protection_codeowners_ref": null, + "deploy_key_change_authorized": false, + "deploy_key_private_material_collection_allowed": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "followup_owner": "pending_post_incident_readback", + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_readback_accepted": false, + "gitea_action_run_readback_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "incident_or_change_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_readback_accepted": false, + "log_redaction_readback_ref": null, + "maintenance_window": "pending_post_incident_readback", + "no_false_green_accepted": false, + "no_false_green_attestation": false, + "no_raw_workflow_payload_attestation": false, + "no_secret_value_attestation": false, + "no_unredacted_log_attestation": false, + "not_approval": true, + "notification_delivery_receipt_accepted": false, + "notification_delivery_receipt_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_or_time_supplement", + "request_workflow_runner_supplement", + "request_secret_injection_supplement", + "request_deploy_run_supplement", + "request_webhook_notification_supplement", + "quarantine_sensitive_payload", + "reject_false_green_claim", + "ready_for_cd_runner_secret_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "post_change_monitoring_accepted": false, + "post_change_monitoring_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_candidate_id": "cd_runner_secret_injection_post_incident_readback:cd_pipeline_deploy_marker_and_k8s_secret_injection", + "post_incident_readback_received": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "readback_fields": [ + "post_incident_readback_candidate_id", + "source_change_evidence_candidate_id", + "title", + "control_tier", + "risk", + "source_refs", + "affected_scope", + "workflow_secret_name_refs", + "write_capable", + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "reviewer_outcome", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_readback_fields": [ + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "source_change_evidence_acceptance_current", + "incident_or_change_ref_present", + "actor_attribution_present", + "change_time_window_present", + "intent_or_break_glass_present", + "workflow_diff_state_present", + "runner_attestation_present", + "runner_executor_host_readback_present", + "runner_workspace_cleanup_present", + "runner_permission_scope_present", + "secret_name_parity_present", + "secret_injection_route_present", + "step_env_secret_guard_present", + "log_redaction_readback_present", + "deploy_marker_readback_present", + "gitea_action_run_readback_present", + "webhook_delivery_state_present", + "deploy_key_branch_protection_codeowners_present", + "notification_delivery_receipt_present", + "before_after_deploy_state_present", + "affected_route_or_service_state_present", + "cross_project_sync_present", + "rollback_validation_present", + "postcheck_independent", + "post_change_monitoring_present", + "recurrence_guard_present", + "redacted_refs_only", + "secret_material_absent", + "no_false_green", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "risk": "HIGH", + "rollback_owner": "pending_post_incident_readback", + "rollback_validation_accepted": false, + "rollback_validation_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_state_ref": null, + "runner_change_authorized": false, + "runner_executor_host_readback_accepted": false, + "runner_executor_host_readback_ref": null, + "runner_permission_scope_accepted": false, + "runner_permission_scope_ref": null, + "runner_token_collection_allowed": false, + "runner_workspace_cleanup_accepted": false, + "runner_workspace_cleanup_readback_ref": null, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_hash_collection_allowed": false, + "secret_injection_change_authorized": false, + "secret_injection_route_accepted": false, + "secret_injection_route_state_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_state_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_change_evidence_candidate_id": "cd_runner_secret_injection:cd_pipeline_deploy_marker_and_k8s_secret_injection", + "source_refs": [ + ".gitea/workflows/cd.yaml", + "scripts/ci/check-gitea-step-env-secrets.js" + ], + "status": "waiting_post_incident_readback", + "step_env_secret_guard_accepted": false, + "step_env_secret_guard_result_ref": null, + "title": "CD pipeline / deploy marker / K8s secret 注入路徑", + "webhook_delivery_state_accepted": false, + "webhook_delivery_state_ref": null, + "webhook_modification_authorized": false, + "webhook_secret_collection_allowed": false, + "workflow_diff_state_accepted": false, + "workflow_diff_state_ref": null, + "workflow_dispatch_authorized": false, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [ + "ARGOCD_API_TOKEN", + "AWOOOI_GITEA_API_TOKEN", + "AWOOOI_GITEA_WEBHOOK_SECRET", + "AWOOOP_OPERATOR_API_KEY", + "CD_PUSH_TOKEN", + "CLAUDE_API_KEY", + "DATABASE_URL", + "DEPLOY_SSH_KEY", + "GEMINI_API_KEY", + "HARBOR_PASSWORD", + "HARBOR_USERNAME", + "JWT_ALGORITHM", + "JWT_SECRET", + "LANGFUSE_PUBLIC_KEY", + "LANGFUSE_SECRET_KEY", + "MIGRATION_DATABASE_URL", + "NEMOTRON_BOT_TOKEN", + "NVIDIA_API_KEY", + "OPENCLAW_BOT_TOKEN", + "OPENCLAW_TG_USER_WHITELIST", + "REDIS_URL", + "SENTRY_AUTH_TOKEN", + "SENTRY_DSN", + "SMTP_HOST", + "SRE_GROUP_CHAT_ID", + "TELEGRAM_BOT_TOKEN", + "WEBHOOK_HMAC_SECRET" + ], + "write_capable": true + }, + { + "action_buttons_allowed": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_route_or_service_state_accepted": false, + "affected_route_or_service_state_ref": null, + "affected_scope": "Code Review、Telegram / AWOOI API notification、deterministic review report、Gitea Actions status", + "argocd_sync_authorized": false, + "before_after_deploy_state_accepted": false, + "before_after_deploy_state_ref": null, + "blocked_actions": [ + "modify_workflow", + "workflow_dispatch_without_approval", + "enable_runner", + "change_runner_label", + "install_runner", + "restart_runner", + "use_runner_admin_token", + "enable_github_hosted_runner", + "collect_secret_value", + "collect_secret_hash", + "collect_partial_token", + "collect_masked_token", + "collect_runner_token", + "collect_webhook_secret", + "collect_deploy_key_private_material", + "collect_cookie_or_authorization_header", + "store_raw_workflow_payload", + "store_unredacted_action_log", + "create_repo_secret", + "update_repo_secret", + "rotate_secret", + "delete_secret", + "read_secret_store", + "change_secret_injection_path", + "modify_webhook", + "change_webhook_secret", + "modify_deploy_key", + "rotate_deploy_key", + "change_branch_protection", + "change_codeowners", + "sync_refs", + "force_push", + "switch_github_primary", + "disable_gitea", + "run_cd_pipeline_as_action", + "inject_k8s_secret", + "argocd_sync", + "production_deploy", + "accept_cd_success_as_security_acceptance", + "accept_deploy_marker_as_runtime_approval", + "accept_workflow_success_as_all_green", + "accept_runner_online_as_attestation", + "accept_route_200_as_deploy_acceptance", + "accept_ui_visible_as_runtime_approval", + "skip_log_redaction_review", + "skip_secret_name_parity", + "skip_runner_attestation", + "skip_cross_project_sync", + "skip_rollback_validation", + "skip_post_change_monitoring", + "open_runtime_gate", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_intent_or_break_glass_ref": null, + "change_time_window_ref": null, + "codeowners_change_authorized": false, + "control_tier": "C0", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "deploy_key_branch_protection_codeowners_accepted": false, + "deploy_key_branch_protection_codeowners_ref": null, + "deploy_key_change_authorized": false, + "deploy_key_private_material_collection_allowed": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "followup_owner": "pending_post_incident_readback", + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_readback_accepted": false, + "gitea_action_run_readback_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "incident_or_change_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_readback_accepted": false, + "log_redaction_readback_ref": null, + "maintenance_window": "pending_post_incident_readback", + "no_false_green_accepted": false, + "no_false_green_attestation": false, + "no_raw_workflow_payload_attestation": false, + "no_secret_value_attestation": false, + "no_unredacted_log_attestation": false, + "not_approval": true, + "notification_delivery_receipt_accepted": false, + "notification_delivery_receipt_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_or_time_supplement", + "request_workflow_runner_supplement", + "request_secret_injection_supplement", + "request_deploy_run_supplement", + "request_webhook_notification_supplement", + "quarantine_sensitive_payload", + "reject_false_green_claim", + "ready_for_cd_runner_secret_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "post_change_monitoring_accepted": false, + "post_change_monitoring_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_candidate_id": "cd_runner_secret_injection_post_incident_readback:code_review_pipeline_secret_and_notification_surface", + "post_incident_readback_received": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "readback_fields": [ + "post_incident_readback_candidate_id", + "source_change_evidence_candidate_id", + "title", + "control_tier", + "risk", + "source_refs", + "affected_scope", + "workflow_secret_name_refs", + "write_capable", + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "reviewer_outcome", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_readback_fields": [ + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "source_change_evidence_acceptance_current", + "incident_or_change_ref_present", + "actor_attribution_present", + "change_time_window_present", + "intent_or_break_glass_present", + "workflow_diff_state_present", + "runner_attestation_present", + "runner_executor_host_readback_present", + "runner_workspace_cleanup_present", + "runner_permission_scope_present", + "secret_name_parity_present", + "secret_injection_route_present", + "step_env_secret_guard_present", + "log_redaction_readback_present", + "deploy_marker_readback_present", + "gitea_action_run_readback_present", + "webhook_delivery_state_present", + "deploy_key_branch_protection_codeowners_present", + "notification_delivery_receipt_present", + "before_after_deploy_state_present", + "affected_route_or_service_state_present", + "cross_project_sync_present", + "rollback_validation_present", + "postcheck_independent", + "post_change_monitoring_present", + "recurrence_guard_present", + "redacted_refs_only", + "secret_material_absent", + "no_false_green", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "risk": "HIGH", + "rollback_owner": "pending_post_incident_readback", + "rollback_validation_accepted": false, + "rollback_validation_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_state_ref": null, + "runner_change_authorized": false, + "runner_executor_host_readback_accepted": false, + "runner_executor_host_readback_ref": null, + "runner_permission_scope_accepted": false, + "runner_permission_scope_ref": null, + "runner_token_collection_allowed": false, + "runner_workspace_cleanup_accepted": false, + "runner_workspace_cleanup_readback_ref": null, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_hash_collection_allowed": false, + "secret_injection_change_authorized": false, + "secret_injection_route_accepted": false, + "secret_injection_route_state_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_state_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_change_evidence_candidate_id": "cd_runner_secret_injection:code_review_pipeline_secret_and_notification_surface", + "source_refs": [ + ".gitea/workflows/code-review.yaml", + "scripts/ci/check-gitea-step-env-secrets.js" + ], + "status": "waiting_post_incident_readback", + "step_env_secret_guard_accepted": false, + "step_env_secret_guard_result_ref": null, + "title": "Code Review workflow / notification / secret 使用面", + "webhook_delivery_state_accepted": false, + "webhook_delivery_state_ref": null, + "webhook_modification_authorized": false, + "webhook_secret_collection_allowed": false, + "workflow_diff_state_accepted": false, + "workflow_diff_state_ref": null, + "workflow_dispatch_authorized": false, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [ + "TELEGRAM_BOT_TOKEN" + ], + "write_capable": true + }, + { + "action_buttons_allowed": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_route_or_service_state_accepted": false, + "affected_route_or_service_state_ref": null, + "affected_scope": "Prometheus / Alertmanager rule deploy、notification route、SRE receipt evidence", + "argocd_sync_authorized": false, + "before_after_deploy_state_accepted": false, + "before_after_deploy_state_ref": null, + "blocked_actions": [ + "modify_workflow", + "workflow_dispatch_without_approval", + "enable_runner", + "change_runner_label", + "install_runner", + "restart_runner", + "use_runner_admin_token", + "enable_github_hosted_runner", + "collect_secret_value", + "collect_secret_hash", + "collect_partial_token", + "collect_masked_token", + "collect_runner_token", + "collect_webhook_secret", + "collect_deploy_key_private_material", + "collect_cookie_or_authorization_header", + "store_raw_workflow_payload", + "store_unredacted_action_log", + "create_repo_secret", + "update_repo_secret", + "rotate_secret", + "delete_secret", + "read_secret_store", + "change_secret_injection_path", + "modify_webhook", + "change_webhook_secret", + "modify_deploy_key", + "rotate_deploy_key", + "change_branch_protection", + "change_codeowners", + "sync_refs", + "force_push", + "switch_github_primary", + "disable_gitea", + "run_cd_pipeline_as_action", + "inject_k8s_secret", + "argocd_sync", + "production_deploy", + "accept_cd_success_as_security_acceptance", + "accept_deploy_marker_as_runtime_approval", + "accept_workflow_success_as_all_green", + "accept_runner_online_as_attestation", + "accept_route_200_as_deploy_acceptance", + "accept_ui_visible_as_runtime_approval", + "skip_log_redaction_review", + "skip_secret_name_parity", + "skip_runner_attestation", + "skip_cross_project_sync", + "skip_rollback_validation", + "skip_post_change_monitoring", + "open_runtime_gate", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_intent_or_break_glass_ref": null, + "change_time_window_ref": null, + "codeowners_change_authorized": false, + "control_tier": "C1", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "deploy_key_branch_protection_codeowners_accepted": false, + "deploy_key_branch_protection_codeowners_ref": null, + "deploy_key_change_authorized": false, + "deploy_key_private_material_collection_allowed": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "followup_owner": "pending_post_incident_readback", + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_readback_accepted": false, + "gitea_action_run_readback_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "incident_or_change_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_readback_accepted": false, + "log_redaction_readback_ref": null, + "maintenance_window": "pending_post_incident_readback", + "no_false_green_accepted": false, + "no_false_green_attestation": false, + "no_raw_workflow_payload_attestation": false, + "no_secret_value_attestation": false, + "no_unredacted_log_attestation": false, + "not_approval": true, + "notification_delivery_receipt_accepted": false, + "notification_delivery_receipt_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_or_time_supplement", + "request_workflow_runner_supplement", + "request_secret_injection_supplement", + "request_deploy_run_supplement", + "request_webhook_notification_supplement", + "quarantine_sensitive_payload", + "reject_false_green_claim", + "ready_for_cd_runner_secret_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "post_change_monitoring_accepted": false, + "post_change_monitoring_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_candidate_id": "cd_runner_secret_injection_post_incident_readback:deploy_alerts_and_monitoring_route", + "post_incident_readback_received": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "readback_fields": [ + "post_incident_readback_candidate_id", + "source_change_evidence_candidate_id", + "title", + "control_tier", + "risk", + "source_refs", + "affected_scope", + "workflow_secret_name_refs", + "write_capable", + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "reviewer_outcome", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_readback_fields": [ + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "source_change_evidence_acceptance_current", + "incident_or_change_ref_present", + "actor_attribution_present", + "change_time_window_present", + "intent_or_break_glass_present", + "workflow_diff_state_present", + "runner_attestation_present", + "runner_executor_host_readback_present", + "runner_workspace_cleanup_present", + "runner_permission_scope_present", + "secret_name_parity_present", + "secret_injection_route_present", + "step_env_secret_guard_present", + "log_redaction_readback_present", + "deploy_marker_readback_present", + "gitea_action_run_readback_present", + "webhook_delivery_state_present", + "deploy_key_branch_protection_codeowners_present", + "notification_delivery_receipt_present", + "before_after_deploy_state_present", + "affected_route_or_service_state_present", + "cross_project_sync_present", + "rollback_validation_present", + "postcheck_independent", + "post_change_monitoring_present", + "recurrence_guard_present", + "redacted_refs_only", + "secret_material_absent", + "no_false_green", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "risk": "MEDIUM", + "rollback_owner": "pending_post_incident_readback", + "rollback_validation_accepted": false, + "rollback_validation_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_state_ref": null, + "runner_change_authorized": false, + "runner_executor_host_readback_accepted": false, + "runner_executor_host_readback_ref": null, + "runner_permission_scope_accepted": false, + "runner_permission_scope_ref": null, + "runner_token_collection_allowed": false, + "runner_workspace_cleanup_accepted": false, + "runner_workspace_cleanup_readback_ref": null, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_hash_collection_allowed": false, + "secret_injection_change_authorized": false, + "secret_injection_route_accepted": false, + "secret_injection_route_state_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_state_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_change_evidence_candidate_id": "cd_runner_secret_injection:deploy_alerts_and_monitoring_route", + "source_refs": [ + ".gitea/workflows/deploy-alerts.yaml", + "scripts/ops/deploy-alerts.sh" + ], + "status": "waiting_post_incident_readback", + "step_env_secret_guard_accepted": false, + "step_env_secret_guard_result_ref": null, + "title": "Deploy alerts workflow / monitoring notification route", + "webhook_delivery_state_accepted": false, + "webhook_delivery_state_ref": null, + "webhook_modification_authorized": false, + "webhook_secret_collection_allowed": false, + "workflow_diff_state_accepted": false, + "workflow_diff_state_ref": null, + "workflow_dispatch_authorized": false, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [ + "DEPLOY_SSH_KEY", + "TELEGRAM_BOT_TOKEN" + ], + "write_capable": true + }, + { + "action_buttons_allowed": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_route_or_service_state_accepted": false, + "affected_route_or_service_state_ref": null, + "affected_scope": "awoooi-host、self-hosted、ubuntu-latest、harbor、k8s runner labels 與 executor owner", + "argocd_sync_authorized": false, + "before_after_deploy_state_accepted": false, + "before_after_deploy_state_ref": null, + "blocked_actions": [ + "modify_workflow", + "workflow_dispatch_without_approval", + "enable_runner", + "change_runner_label", + "install_runner", + "restart_runner", + "use_runner_admin_token", + "enable_github_hosted_runner", + "collect_secret_value", + "collect_secret_hash", + "collect_partial_token", + "collect_masked_token", + "collect_runner_token", + "collect_webhook_secret", + "collect_deploy_key_private_material", + "collect_cookie_or_authorization_header", + "store_raw_workflow_payload", + "store_unredacted_action_log", + "create_repo_secret", + "update_repo_secret", + "rotate_secret", + "delete_secret", + "read_secret_store", + "change_secret_injection_path", + "modify_webhook", + "change_webhook_secret", + "modify_deploy_key", + "rotate_deploy_key", + "change_branch_protection", + "change_codeowners", + "sync_refs", + "force_push", + "switch_github_primary", + "disable_gitea", + "run_cd_pipeline_as_action", + "inject_k8s_secret", + "argocd_sync", + "production_deploy", + "accept_cd_success_as_security_acceptance", + "accept_deploy_marker_as_runtime_approval", + "accept_workflow_success_as_all_green", + "accept_runner_online_as_attestation", + "accept_route_200_as_deploy_acceptance", + "accept_ui_visible_as_runtime_approval", + "skip_log_redaction_review", + "skip_secret_name_parity", + "skip_runner_attestation", + "skip_cross_project_sync", + "skip_rollback_validation", + "skip_post_change_monitoring", + "open_runtime_gate", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_intent_or_break_glass_ref": null, + "change_time_window_ref": null, + "codeowners_change_authorized": false, + "control_tier": "C0", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "deploy_key_branch_protection_codeowners_accepted": false, + "deploy_key_branch_protection_codeowners_ref": null, + "deploy_key_change_authorized": false, + "deploy_key_private_material_collection_allowed": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "followup_owner": "pending_post_incident_readback", + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_readback_accepted": false, + "gitea_action_run_readback_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "incident_or_change_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_readback_accepted": false, + "log_redaction_readback_ref": null, + "maintenance_window": "pending_post_incident_readback", + "no_false_green_accepted": false, + "no_false_green_attestation": false, + "no_raw_workflow_payload_attestation": false, + "no_secret_value_attestation": false, + "no_unredacted_log_attestation": false, + "not_approval": true, + "notification_delivery_receipt_accepted": false, + "notification_delivery_receipt_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_or_time_supplement", + "request_workflow_runner_supplement", + "request_secret_injection_supplement", + "request_deploy_run_supplement", + "request_webhook_notification_supplement", + "quarantine_sensitive_payload", + "reject_false_green_claim", + "ready_for_cd_runner_secret_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "post_change_monitoring_accepted": false, + "post_change_monitoring_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_candidate_id": "cd_runner_secret_injection_post_incident_readback:runner_label_and_executor_attestation", + "post_incident_readback_received": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "readback_fields": [ + "post_incident_readback_candidate_id", + "source_change_evidence_candidate_id", + "title", + "control_tier", + "risk", + "source_refs", + "affected_scope", + "workflow_secret_name_refs", + "write_capable", + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "reviewer_outcome", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_readback_fields": [ + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "source_change_evidence_acceptance_current", + "incident_or_change_ref_present", + "actor_attribution_present", + "change_time_window_present", + "intent_or_break_glass_present", + "workflow_diff_state_present", + "runner_attestation_present", + "runner_executor_host_readback_present", + "runner_workspace_cleanup_present", + "runner_permission_scope_present", + "secret_name_parity_present", + "secret_injection_route_present", + "step_env_secret_guard_present", + "log_redaction_readback_present", + "deploy_marker_readback_present", + "gitea_action_run_readback_present", + "webhook_delivery_state_present", + "deploy_key_branch_protection_codeowners_present", + "notification_delivery_receipt_present", + "before_after_deploy_state_present", + "affected_route_or_service_state_present", + "cross_project_sync_present", + "rollback_validation_present", + "postcheck_independent", + "post_change_monitoring_present", + "recurrence_guard_present", + "redacted_refs_only", + "secret_material_absent", + "no_false_green", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "risk": "HIGH", + "rollback_owner": "pending_post_incident_readback", + "rollback_validation_accepted": false, + "rollback_validation_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_state_ref": null, + "runner_change_authorized": false, + "runner_executor_host_readback_accepted": false, + "runner_executor_host_readback_ref": null, + "runner_permission_scope_accepted": false, + "runner_permission_scope_ref": null, + "runner_token_collection_allowed": false, + "runner_workspace_cleanup_accepted": false, + "runner_workspace_cleanup_readback_ref": null, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_hash_collection_allowed": false, + "secret_injection_change_authorized": false, + "secret_injection_route_accepted": false, + "secret_injection_route_state_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_state_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_change_evidence_candidate_id": "cd_runner_secret_injection:runner_label_and_executor_attestation", + "source_refs": [ + "docs/security/source-control-workflow-secret-name-local-evidence.snapshot.json" + ], + "status": "waiting_post_incident_readback", + "step_env_secret_guard_accepted": false, + "step_env_secret_guard_result_ref": null, + "title": "Runner label / executor / hosted minutes owner attestation", + "webhook_delivery_state_accepted": false, + "webhook_delivery_state_ref": null, + "webhook_modification_authorized": false, + "webhook_secret_collection_allowed": false, + "workflow_diff_state_accepted": false, + "workflow_diff_state_ref": null, + "workflow_dispatch_authorized": false, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [], + "write_capable": true + }, + { + "action_buttons_allowed": false, + "actor_attribution_accepted": false, + "actor_attribution_ref": null, + "affected_route_or_service_state_accepted": false, + "affected_route_or_service_state_ref": null, + "affected_scope": "9 個 in-scope repos 的 secret name parity、rotation owner、CD / K8s injection owner", + "argocd_sync_authorized": false, + "before_after_deploy_state_accepted": false, + "before_after_deploy_state_ref": null, + "blocked_actions": [ + "modify_workflow", + "workflow_dispatch_without_approval", + "enable_runner", + "change_runner_label", + "install_runner", + "restart_runner", + "use_runner_admin_token", + "enable_github_hosted_runner", + "collect_secret_value", + "collect_secret_hash", + "collect_partial_token", + "collect_masked_token", + "collect_runner_token", + "collect_webhook_secret", + "collect_deploy_key_private_material", + "collect_cookie_or_authorization_header", + "store_raw_workflow_payload", + "store_unredacted_action_log", + "create_repo_secret", + "update_repo_secret", + "rotate_secret", + "delete_secret", + "read_secret_store", + "change_secret_injection_path", + "modify_webhook", + "change_webhook_secret", + "modify_deploy_key", + "rotate_deploy_key", + "change_branch_protection", + "change_codeowners", + "sync_refs", + "force_push", + "switch_github_primary", + "disable_gitea", + "run_cd_pipeline_as_action", + "inject_k8s_secret", + "argocd_sync", + "production_deploy", + "accept_cd_success_as_security_acceptance", + "accept_deploy_marker_as_runtime_approval", + "accept_workflow_success_as_all_green", + "accept_runner_online_as_attestation", + "accept_route_200_as_deploy_acceptance", + "accept_ui_visible_as_runtime_approval", + "skip_log_redaction_review", + "skip_secret_name_parity", + "skip_runner_attestation", + "skip_cross_project_sync", + "skip_rollback_validation", + "skip_post_change_monitoring", + "open_runtime_gate", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_intent_or_break_glass_ref": null, + "change_time_window_ref": null, + "codeowners_change_authorized": false, + "control_tier": "C0", + "cross_project_sync_accepted": false, + "cross_project_sync_ref": null, + "deploy_key_branch_protection_codeowners_accepted": false, + "deploy_key_branch_protection_codeowners_ref": null, + "deploy_key_change_authorized": false, + "deploy_key_private_material_collection_allowed": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "followup_owner": "pending_post_incident_readback", + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_readback_accepted": false, + "gitea_action_run_readback_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "incident_or_change_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_readback_accepted": false, + "log_redaction_readback_ref": null, + "maintenance_window": "pending_post_incident_readback", + "no_false_green_accepted": false, + "no_false_green_attestation": false, + "no_raw_workflow_payload_attestation": false, + "no_secret_value_attestation": false, + "no_unredacted_log_attestation": false, + "not_approval": true, + "notification_delivery_receipt_accepted": false, + "notification_delivery_receipt_ref": null, + "outcome_lanes": [ + "waiting_post_incident_readback", + "request_actor_or_time_supplement", + "request_workflow_runner_supplement", + "request_secret_injection_supplement", + "request_deploy_run_supplement", + "request_webhook_notification_supplement", + "quarantine_sensitive_payload", + "reject_false_green_claim", + "ready_for_cd_runner_secret_post_incident_review", + "recurrence_guard_backfill_required", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "post_change_monitoring_accepted": false, + "post_change_monitoring_ref": null, + "post_incident_readback_accepted": false, + "post_incident_readback_candidate_id": "cd_runner_secret_injection_post_incident_readback:repository_secret_name_parity_and_injection_owner", + "post_incident_readback_received": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "readback_fields": [ + "post_incident_readback_candidate_id", + "source_change_evidence_candidate_id", + "title", + "control_tier", + "risk", + "source_refs", + "affected_scope", + "workflow_secret_name_refs", + "write_capable", + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "reviewer_outcome", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", + "not_approval" + ], + "recurrence_guard_accepted": false, + "recurrence_guard_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_readback_fields": [ + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "source_change_evidence_acceptance_current", + "incident_or_change_ref_present", + "actor_attribution_present", + "change_time_window_present", + "intent_or_break_glass_present", + "workflow_diff_state_present", + "runner_attestation_present", + "runner_executor_host_readback_present", + "runner_workspace_cleanup_present", + "runner_permission_scope_present", + "secret_name_parity_present", + "secret_injection_route_present", + "step_env_secret_guard_present", + "log_redaction_readback_present", + "deploy_marker_readback_present", + "gitea_action_run_readback_present", + "webhook_delivery_state_present", + "deploy_key_branch_protection_codeowners_present", + "notification_delivery_receipt_present", + "before_after_deploy_state_present", + "affected_route_or_service_state_present", + "cross_project_sync_present", + "rollback_validation_present", + "postcheck_independent", + "post_change_monitoring_present", + "recurrence_guard_present", + "redacted_refs_only", + "secret_material_absent", + "no_false_green", + "runtime_stays_zero" + ], + "reviewer_outcome": "waiting_post_incident_readback", + "risk": "HIGH", + "rollback_owner": "pending_post_incident_readback", + "rollback_validation_accepted": false, + "rollback_validation_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_state_ref": null, + "runner_change_authorized": false, + "runner_executor_host_readback_accepted": false, + "runner_executor_host_readback_ref": null, + "runner_permission_scope_accepted": false, + "runner_permission_scope_ref": null, + "runner_token_collection_allowed": false, + "runner_workspace_cleanup_accepted": false, + "runner_workspace_cleanup_readback_ref": null, + "runtime_execution_authorized": false, + "runtime_gate": false, + "secret_hash_collection_allowed": false, + "secret_injection_change_authorized": false, + "secret_injection_route_accepted": false, + "secret_injection_route_state_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_state_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_change_evidence_candidate_id": "cd_runner_secret_injection:repository_secret_name_parity_and_injection_owner", + "source_refs": [ + "docs/security/source-control-workflow-secret-name-export-request.snapshot.json", + "docs/security/source-control-workflow-secret-name-owner-response.snapshot.json" + ], + "status": "waiting_post_incident_readback", + "step_env_secret_guard_accepted": false, + "step_env_secret_guard_result_ref": null, + "title": "Repository secret name parity / injection owner", + "webhook_delivery_state_accepted": false, + "webhook_delivery_state_ref": null, + "webhook_modification_authorized": false, + "webhook_secret_collection_allowed": false, + "workflow_diff_state_accepted": false, + "workflow_diff_state_ref": null, + "workflow_dispatch_authorized": false, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [], + "write_capable": true + } + ], + "readback_fields": [ + "post_incident_readback_candidate_id", + "source_change_evidence_candidate_id", + "title", + "control_tier", + "risk", + "source_refs", + "affected_scope", + "workflow_secret_name_refs", + "write_capable", + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "reviewer_outcome", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", + "not_approval" + ], + "required_readback_fields": [ + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation" + ], + "reviewer_checks": [ + { + "check_id": "source_change_evidence_acceptance_current", + "instruction": "來源 change evidence acceptance snapshot 必須是目前版本。" + }, + { + "check_id": "incident_or_change_ref_present", + "instruction": "必須有 incident、change、outage、ticket 或 maintenance ref,不能只寫 CD 成功。" + }, + { + "check_id": "actor_attribution_present", + "instruction": "必須標示 actor role / team,不接受匿名 workflow dispatch、runner restart 或 secret injection change。" + }, + { + "check_id": "change_time_window_present", + "instruction": "必須有變更 / 異常時間窗,供 Gitea run、deploy marker 與通知回執對齊。" + }, + { + "check_id": "intent_or_break_glass_present", + "instruction": "正常變更需有 change intent;緊急變更需有 break-glass reason,但 break-glass 不等於事前批准。" + }, + { + "check_id": "workflow_diff_state_present", + "instruction": "必須回讀 workflow diff state;不得保存 raw workflow payload 或未脫敏 patch。" + }, + { + "check_id": "runner_attestation_present", + "instruction": "runner label、executor、host alias、owner 與維護窗口必須可追溯。" + }, + { + "check_id": "runner_executor_host_readback_present", + "instruction": "必須回讀 runner executor / host / container boundary,不得只看 job success。" + }, + { + "check_id": "runner_workspace_cleanup_present", + "instruction": "必須回讀 workspace cleanup、root-owned cache、artifact residue 或 shared Docker daemon 影響。" + }, + { + "check_id": "runner_permission_scope_present", + "instruction": "必須回讀 runner permission、token scope、hosted runner minutes / supply-chain 風險。" + }, + { + "check_id": "secret_name_parity_present", + "instruction": "secret parity 只能保存 secret name / scope / present-absent / owner metadata。" + }, + { + "check_id": "secret_injection_route_present", + "instruction": "涉及 CD / K8s secret injection 時必須標出 injection path 與 owner,不得讀 value。" + }, + { + "check_id": "step_env_secret_guard_present", + "instruction": "必須附 `check-gitea-step-env-secrets` 或等價 guard result ref。" + }, + { + "check_id": "log_redaction_readback_present", + "instruction": "必須回讀 Actions log / notification log 未展開 secret value、hash 或 partial token。" + }, + { + "check_id": "deploy_marker_readback_present", + "instruction": "deploy marker 只能當部署證據,不代表資安 runtime approval。" + }, + { + "check_id": "gitea_action_run_readback_present", + "instruction": "Gitea Actions run readback 只能是 run id / job id / status ref,不保存 token 或 cookie。" + }, + { + "check_id": "webhook_delivery_state_present", + "instruction": "涉及 webhook 時必須回讀 delivery state 與 owner,不保存 webhook secret。" + }, + { + "check_id": "deploy_key_branch_protection_codeowners_present", + "instruction": "影響 deploy key、required checks、CODEOWNERS 或 branch protection 時必須標出影響。" + }, + { + "check_id": "notification_delivery_receipt_present", + "instruction": "涉及通知時必須有 SRE route owner 與 delivery receipt metadata ref。" + }, + { + "check_id": "before_after_deploy_state_present", + "instruction": "必須有 before / after deploy state ref,不得只看最新 route 200。" + }, + { + "check_id": "affected_route_or_service_state_present", + "instruction": "需列 affected route、service、API、admin、webhook、AI provider 或監控影響。" + }, + { + "check_id": "cross_project_sync_present", + "instruction": "若影響 AwoooP、IwoooS、agent-bounty、監控或公開服務,需有跨專案同步 ref。" + }, + { + "check_id": "rollback_validation_present", + "instruction": "必須提供 rollback validation ref,包含 rollback owner 與回復方式。" + }, + { + "check_id": "postcheck_independent", + "instruction": "post-check 必須獨立於原操作人、workflow success 與 UI 顯示。" + }, + { + "check_id": "post_change_monitoring_present", + "instruction": "必須有 post-change monitoring window,觀察 route、error、alert、deploy marker 與 notification receipt。" + }, + { + "check_id": "recurrence_guard_present", + "instruction": "必須提出防再發 guard、owner review、change freeze 或 automation block。" + }, + { + "check_id": "redacted_refs_only", + "instruction": "evidence 只能是脫敏 ref、commit、run id、job id、ticket、hash 或 artifact pointer。" + }, + { + "check_id": "secret_material_absent", + "instruction": "不得保存 secret value、hash、masked token、partial token、runner token、webhook secret、deploy key private material、cookie、authorization header 或完整 credential URL。" + }, + { + "check_id": "no_false_green", + "instruction": "不得只用 CD success、deploy marker、workflow success、route 200、runner online、UI 可見或 AwoooP approval 當驗收。" + }, + { + "check_id": "runtime_stays_zero", + "instruction": "readback plan 不得觸發 workflow dispatch、runner change、secret change、webhook change、deploy key change、branch protection change、refs sync、ArgoCD sync、K8s secret injection 或 production deploy。" + } + ], + "schema_version": "cd_runner_secret_injection_post_incident_readback_plan_v1", + "source_paths": [ + "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", + ".gitea/workflows/cd.yaml", + ".gitea/workflows/code-review.yaml", + ".gitea/workflows/deploy-alerts.yaml", + "scripts/ci/check-gitea-step-env-secrets.js" + ], + "status": "post_incident_readback_plan_ready_no_runtime_action", + "summary": { + "action_button_count": 0, + "actor_attribution_accepted_count": 0, + "affected_route_or_service_state_accepted_count": 0, + "argocd_sync_authorized_count": 0, + "before_after_deploy_state_accepted_count": 0, + "blocked_action_count": 52, + "branch_protection_change_authorized_count": 0, + "c0_readback_candidate_count": 4, + "c1_readback_candidate_count": 1, + "cd_pipeline_run_authorized_count": 0, + "codeowners_change_authorized_count": 0, + "cross_project_sync_accepted_count": 0, + "cross_project_sync_required_candidate_count": 5, + "deploy_key_branch_protection_codeowners_accepted_count": 0, + "deploy_key_change_authorized_count": 0, + "deploy_marker_readback_accepted_count": 0, + "deploy_or_run_readback_required_candidate_count": 5, + "gitea_action_dispatch_authorized_count": 0, + "gitea_action_run_readback_accepted_count": 0, + "gitea_workflow_runner_coverage_percent_after_readback_plan": 74, + "github_hosted_runner_enable_authorized_count": 0, + "k8s_secret_injection_authorized_count": 0, + "log_redaction_readback_accepted_count": 0, + "no_false_green_accepted_count": 0, + "no_false_green_required_candidate_count": 5, + "notification_delivery_receipt_accepted_count": 0, + "outcome_lane_count": 11, + "post_change_monitoring_accepted_count": 0, + "post_incident_readback_accepted_count": 0, + "post_incident_readback_received_count": 0, + "postcheck_evidence_accepted_count": 0, + "production_deploy_authorized_count": 0, + "readback_candidate_count": 5, + "readback_field_count": 44, + "recurrence_guard_accepted_count": 0, + "repo_secret_change_authorized_count": 0, + "required_readback_field_count": 33, + "reviewer_check_count": 30, + "rollback_validation_accepted_count": 0, + "runner_attestation_accepted_count": 0, + "runner_change_authorized_count": 0, + "runner_executor_host_readback_accepted_count": 0, + "runner_or_workflow_readback_candidate_count": 5, + "runner_permission_scope_accepted_count": 0, + "runner_workspace_cleanup_accepted_count": 0, + "runtime_gate_count": 0, + "secret_injection_change_authorized_count": 0, + "secret_injection_route_accepted_count": 0, + "secret_metadata_coverage_percent_after_readback_plan": 70, + "secret_name_parity_accepted_count": 0, + "secret_sensitive_readback_candidate_count": 5, + "secret_value_collection_allowed_count": 0, + "source_blocked_action_count": 32, + "source_c0_change_evidence_candidate_count": 4, + "source_c1_change_evidence_candidate_count": 1, + "source_change_evidence_accepted_count": 0, + "source_change_evidence_candidate_count": 5, + "source_required_evidence_field_count": 19, + "source_reviewer_check_count": 19, + "source_runtime_gate_count": 0, + "step_env_secret_guard_accepted_count": 0, + "webhook_delivery_state_accepted_count": 0, + "webhook_modification_authorized_count": 0, + "workflow_diff_state_accepted_count": 0, + "workflow_dispatch_authorized_count": 0, + "workflow_modification_authorized_count": 0, + "write_capable_readback_candidate_count": 5 + } +} diff --git a/docs/security/high-value-config-control-coverage.snapshot.json b/docs/security/high-value-config-control-coverage.snapshot.json index e98c522cc..b9231a65c 100644 --- a/docs/security/high-value-config-control-coverage.snapshot.json +++ b/docs/security/high-value-config-control-coverage.snapshot.json @@ -135,9 +135,9 @@ "action_buttons_allowed": false, "category_id": "secret_metadata", "control_tier": "C0", - "coverage_percent": 68, - "coverage_status": "secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", - "current_gap": "已固定 secret name / injection owner 變更證據驗收帳本;secret value、hash、partial token、secret store read、secret rotation、repo secret change 與 injection path change 仍全部為 0。", + "coverage_percent": 70, + "coverage_status": "post_incident_readback_plan_ready_needs_secret_injection_owner_evidence", + "current_gap": "已固定 secret name / injection owner 變更證據驗收帳本,並新增事故後回讀計畫;secret name parity state、secret injection route、step-env secret guard、log redaction、deploy marker / Gitea run readback、rollback、post-check、防再發與 no-false-green 已納入;secret value、hash、partial token、runner token、secret store read、secret rotation、repo secret change 與 injection path change 仍全部為 0。", "evidence_refs": [ "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", "docs/security/source-control-workflow-secret-name-inventory.snapshot.json", @@ -145,10 +145,12 @@ "docs/security/source-control-workflow-secret-name-owner-response.snapshot.json", "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json", "docs/security/SECRETS_REFERENCE.md" ], "label": "Secret metadata / injection / redaction", - "next_owner_action": "補 secret name parity ref、injection route owner、rotation owner、guard result ref、rollback owner、post-check evidence 與 redacted evidence refs。", + "next_owner_action": "補 secret name parity state ref、secret injection route state ref、step-env secret guard result、log redaction readback、deploy marker / Gitea run readback、notification receipt、rollback owner、post-check evidence、recurrence guard 與 no-secret-value evidence。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -177,18 +179,20 @@ "action_buttons_allowed": false, "category_id": "gitea_workflow_runner_source_control", "control_tier": "C0", - "coverage_percent": 72, - "coverage_status": "cd_runner_secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", - "current_gap": "已固定 CD / runner / secret injection 變更證據驗收帳本;workflow diff、runner attestation、secret parity、guard result、deploy marker readback、rollback owner 與 post-check evidence 仍全部為 0。", + "coverage_percent": 74, + "coverage_status": "post_incident_readback_plan_ready_needs_workflow_runner_owner_evidence", + "current_gap": "已固定 CD / runner / secret injection 變更證據驗收帳本,並新增事故後回讀計畫;workflow diff state、runner attestation、executor / host、workspace cleanup、permission scope、webhook / notification、deploy key / branch protection / CODEOWNERS、deploy marker / Gitea run、rollback、post-change monitoring、防再發與 no-false-green 已納入;workflow 修改、dispatch、runner 啟用 / 重啟、GitHub hosted runner、webhook / deploy key / branch protection / CODEOWNERS 修改仍全部為 0。", "evidence_refs": [ "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-OWNER-RESPONSE.md", "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json", "docs/security/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md" ], "label": "Gitea workflow / runner / deploy key / webhook / branch protection", - "next_owner_action": "補 workflow diff ref、runner owner attestation、secret name parity ref、Gitea run readback、guard result、maintenance window、rollback owner 與 post-check evidence。", + "next_owner_action": "補 workflow diff state ref、runner owner attestation、executor / host readback、workspace cleanup、permission scope、Gitea run readback、deploy marker readback、webhook / notification receipt、maintenance window、rollback owner、post-change monitoring 與 recurrence guard evidence。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -649,8 +653,8 @@ "websocket_route_change_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-06-15T23:45:00+08:00", - "git_commit": "dfee85c0", + "generated_at": "2026-06-16T00:30:00+08:00", + "git_commit": "7db05e00", "lowest_coverage_categories": [ { "category_id": "backup_restore_credential", diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json index d56c1aef0..a3209dbdf 100644 --- a/docs/security/iwooos-posture-projection.snapshot.json +++ b/docs/security/iwooos-posture-projection.snapshot.json @@ -351,7 +351,7 @@ "target_surface": "execution_boundary" } ], - "date": "2026-06-14", + "date": "2026-06-16", "decision_runway_boundary_signals": [ { "authorized": false, @@ -8555,6 +8555,63 @@ "cd_runner_secret_injection_change_evidence_acceptance_secret_name_parity_accepted_count": 0, "cd_runner_secret_injection_change_evidence_acceptance_workflow_diff_accepted_count": 0, "cd_runner_secret_injection_change_evidence_acceptance_write_capable_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_action_button_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_actor_attribution_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_affected_route_or_service_state_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_argocd_sync_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_before_after_deploy_state_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_blocked_action_count": 52, + "cd_runner_secret_injection_post_incident_readback_plan_branch_protection_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_c0_candidate_count": 4, + "cd_runner_secret_injection_post_incident_readback_plan_c1_candidate_count": 1, + "cd_runner_secret_injection_post_incident_readback_plan_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_cd_pipeline_run_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_codeowners_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_cross_project_sync_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_deploy_key_branch_protection_codeowners_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_deploy_key_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_deploy_marker_readback_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_deploy_or_run_readback_required_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_first_layer": true, + "cd_runner_secret_injection_post_incident_readback_plan_gitea_action_dispatch_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_gitea_action_run_readback_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_gitea_workflow_runner_coverage_percent_after_readback_plan": 74, + "cd_runner_secret_injection_post_incident_readback_plan_github_hosted_runner_enable_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_k8s_secret_injection_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_log_redaction_readback_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_no_false_green_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_notification_delivery_receipt_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_outcome_lane_count": 11, + "cd_runner_secret_injection_post_incident_readback_plan_post_change_monitoring_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_postcheck_evidence_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_production_deploy_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_received_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_recurrence_guard_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_repo_secret_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_required_readback_field_count": 33, + "cd_runner_secret_injection_post_incident_readback_plan_reviewer_check_count": 30, + "cd_runner_secret_injection_post_incident_readback_plan_rollback_validation_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_attestation_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_executor_host_readback_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_or_workflow_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_runner_permission_scope_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_workspace_cleanup_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runtime_gate_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_injection_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_injection_route_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_metadata_coverage_percent_after_readback_plan": 70, + "cd_runner_secret_injection_post_incident_readback_plan_secret_name_parity_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_sensitive_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_secret_value_collection_allowed_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_step_env_secret_guard_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_webhook_delivery_state_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_webhook_modification_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_workflow_diff_state_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_workflow_dispatch_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_workflow_modification_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_write_capable_candidate_count": 5, "command_map_above_first_progress_unlock_path": true, "command_map_default_mode": "unlock", "command_map_default_visible": false, @@ -8652,6 +8709,7 @@ "gate_radar_interactive_lens_allowed": true, "gate_radar_lane_count": 4, "gate_radar_runtime_gate_count": 0, + "gitea_workflow_runner_source_control_coverage_percent": 74, "github_primary_ready_count": 0, "global_security_mesh_matrix_asset_count": 9, "global_security_mesh_matrix_default_visible": false, @@ -9152,6 +9210,7 @@ "s4_9_request_draft_package_request_sent_count": 0, "s4_9_request_draft_package_runtime_gate_count": 0, "s4_9_request_draft_package_template_ready_count": 5, + "secret_metadata_coverage_percent": 70, "source_control_primary_readiness_item_count": 6, "ssh_firewall_network_access_coverage_percent": 64, "ssh_network_access_inventory_action_button_count": 0, diff --git a/scripts/security/cd-runner-secret-injection-post-incident-readback-plan.py b/scripts/security/cd-runner-secret-injection-post-incident-readback-plan.py new file mode 100644 index 000000000..2a777fa9f --- /dev/null +++ b/scripts/security/cd-runner-secret-injection-post-incident-readback-plan.py @@ -0,0 +1,489 @@ +#!/usr/bin/env python3 +""" +IwoooS CD / Runner / Secret injection post-incident readback 只讀計畫產生器。 + +本工具讀取 CD / Runner / Secret injection change evidence acceptance snapshot, +建立事故後回讀計畫:誰改了 workflow / runner / secret injection、何時異常、 +runner / secret name / deploy marker / notification 是否可回讀、rollback 與防再發。 +它不呼叫 Gitea / GitHub API、不讀 secret store、不讀 secret value、不修改 workflow、 +不啟用 runner、不 rotate secret、不 dispatch workflow、不觸發部署、不寫 production。 +""" + +from __future__ import annotations + +import argparse +import json +import subprocess +import sys +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any + + +TAIPEI = timezone(timedelta(hours=8)) + +READBACK_FIELDS = [ + "post_incident_readback_candidate_id", + "source_change_evidence_candidate_id", + "title", + "control_tier", + "risk", + "source_refs", + "affected_scope", + "workflow_secret_name_refs", + "write_capable", + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "reviewer_outcome", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", + "not_approval", +] + +REQUIRED_READBACK_FIELDS = [ + "incident_or_change_ref", + "actor_attribution_ref", + "change_time_window_ref", + "change_intent_or_break_glass_ref", + "workflow_diff_state_ref", + "runner_attestation_state_ref", + "runner_executor_host_readback_ref", + "runner_workspace_cleanup_readback_ref", + "runner_permission_scope_ref", + "secret_name_parity_state_ref", + "secret_injection_route_state_ref", + "step_env_secret_guard_result_ref", + "log_redaction_readback_ref", + "deploy_marker_readback_ref", + "gitea_action_run_readback_ref", + "webhook_delivery_state_ref", + "deploy_key_branch_protection_codeowners_ref", + "notification_delivery_receipt_ref", + "before_after_deploy_state_ref", + "affected_route_or_service_state_ref", + "cross_project_sync_ref", + "rollback_validation_ref", + "postcheck_evidence_ref", + "post_change_monitoring_ref", + "recurrence_guard_ref", + "maintenance_window", + "rollback_owner", + "followup_owner", + "redacted_evidence_refs", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", +] + +REVIEWER_CHECKS = [ + {"check_id": "source_change_evidence_acceptance_current", "instruction": "來源 change evidence acceptance snapshot 必須是目前版本。"}, + {"check_id": "incident_or_change_ref_present", "instruction": "必須有 incident、change、outage、ticket 或 maintenance ref,不能只寫 CD 成功。"}, + {"check_id": "actor_attribution_present", "instruction": "必須標示 actor role / team,不接受匿名 workflow dispatch、runner restart 或 secret injection change。"}, + {"check_id": "change_time_window_present", "instruction": "必須有變更 / 異常時間窗,供 Gitea run、deploy marker 與通知回執對齊。"}, + {"check_id": "intent_or_break_glass_present", "instruction": "正常變更需有 change intent;緊急變更需有 break-glass reason,但 break-glass 不等於事前批准。"}, + {"check_id": "workflow_diff_state_present", "instruction": "必須回讀 workflow diff state;不得保存 raw workflow payload 或未脫敏 patch。"}, + {"check_id": "runner_attestation_present", "instruction": "runner label、executor、host alias、owner 與維護窗口必須可追溯。"}, + {"check_id": "runner_executor_host_readback_present", "instruction": "必須回讀 runner executor / host / container boundary,不得只看 job success。"}, + {"check_id": "runner_workspace_cleanup_present", "instruction": "必須回讀 workspace cleanup、root-owned cache、artifact residue 或 shared Docker daemon 影響。"}, + {"check_id": "runner_permission_scope_present", "instruction": "必須回讀 runner permission、token scope、hosted runner minutes / supply-chain 風險。"}, + {"check_id": "secret_name_parity_present", "instruction": "secret parity 只能保存 secret name / scope / present-absent / owner metadata。"}, + {"check_id": "secret_injection_route_present", "instruction": "涉及 CD / K8s secret injection 時必須標出 injection path 與 owner,不得讀 value。"}, + {"check_id": "step_env_secret_guard_present", "instruction": "必須附 `check-gitea-step-env-secrets` 或等價 guard result ref。"}, + {"check_id": "log_redaction_readback_present", "instruction": "必須回讀 Actions log / notification log 未展開 secret value、hash 或 partial token。"}, + {"check_id": "deploy_marker_readback_present", "instruction": "deploy marker 只能當部署證據,不代表資安 runtime approval。"}, + {"check_id": "gitea_action_run_readback_present", "instruction": "Gitea Actions run readback 只能是 run id / job id / status ref,不保存 token 或 cookie。"}, + {"check_id": "webhook_delivery_state_present", "instruction": "涉及 webhook 時必須回讀 delivery state 與 owner,不保存 webhook secret。"}, + {"check_id": "deploy_key_branch_protection_codeowners_present", "instruction": "影響 deploy key、required checks、CODEOWNERS 或 branch protection 時必須標出影響。"}, + {"check_id": "notification_delivery_receipt_present", "instruction": "涉及通知時必須有 SRE route owner 與 delivery receipt metadata ref。"}, + {"check_id": "before_after_deploy_state_present", "instruction": "必須有 before / after deploy state ref,不得只看最新 route 200。"}, + {"check_id": "affected_route_or_service_state_present", "instruction": "需列 affected route、service、API、admin、webhook、AI provider 或監控影響。"}, + {"check_id": "cross_project_sync_present", "instruction": "若影響 AwoooP、IwoooS、agent-bounty、監控或公開服務,需有跨專案同步 ref。"}, + {"check_id": "rollback_validation_present", "instruction": "必須提供 rollback validation ref,包含 rollback owner 與回復方式。"}, + {"check_id": "postcheck_independent", "instruction": "post-check 必須獨立於原操作人、workflow success 與 UI 顯示。"}, + {"check_id": "post_change_monitoring_present", "instruction": "必須有 post-change monitoring window,觀察 route、error、alert、deploy marker 與 notification receipt。"}, + {"check_id": "recurrence_guard_present", "instruction": "必須提出防再發 guard、owner review、change freeze 或 automation block。"}, + {"check_id": "redacted_refs_only", "instruction": "evidence 只能是脫敏 ref、commit、run id、job id、ticket、hash 或 artifact pointer。"}, + {"check_id": "secret_material_absent", "instruction": "不得保存 secret value、hash、masked token、partial token、runner token、webhook secret、deploy key private material、cookie、authorization header 或完整 credential URL。"}, + {"check_id": "no_false_green", "instruction": "不得只用 CD success、deploy marker、workflow success、route 200、runner online、UI 可見或 AwoooP approval 當驗收。"}, + {"check_id": "runtime_stays_zero", "instruction": "readback plan 不得觸發 workflow dispatch、runner change、secret change、webhook change、deploy key change、branch protection change、refs sync、ArgoCD sync、K8s secret injection 或 production deploy。"}, +] + +OUTCOME_LANES = [ + {"lane_id": "waiting_post_incident_readback", "meaning": "尚未收到 CD / runner / secret injection 事故回讀包;所有 accepted / runtime count 維持 0。"}, + {"lane_id": "request_actor_or_time_supplement", "meaning": "缺 actor、change time window、intent 或 break-glass reason 時要求補件。"}, + {"lane_id": "request_workflow_runner_supplement", "meaning": "缺 workflow diff、runner attestation、executor / host、workspace cleanup 或 permission scope 時要求補件。"}, + {"lane_id": "request_secret_injection_supplement", "meaning": "缺 secret name parity、injection route、step-env guard 或 log redaction readback 時要求補件。"}, + {"lane_id": "request_deploy_run_supplement", "meaning": "缺 deploy marker、Gitea run readback、before / after deploy state 或 post-check 時要求補件。"}, + {"lane_id": "request_webhook_notification_supplement", "meaning": "缺 webhook delivery、notification receipt、SRE route owner 或 cross-project sync 時要求補件。"}, + {"lane_id": "quarantine_sensitive_payload", "meaning": "收到 secret value、hash、runner token、webhook secret、private key、cookie、credential URL、未脫敏 log 或截圖時只能隔離。"}, + {"lane_id": "reject_false_green_claim", "meaning": "把 CD success、deploy marker、workflow success、route 200、runner online、UI 可見或 AwoooP approval 當驗收時拒收。"}, + {"lane_id": "ready_for_cd_runner_secret_post_incident_review", "meaning": "metadata 合格後,只能進 reviewer review。"}, + {"lane_id": "recurrence_guard_backfill_required", "meaning": "需補防再發 guard、owner review、change freeze、automation block 或 runner isolation plan。"}, + {"lane_id": "waiting_runtime_gate", "meaning": "即使 readback accepted,runtime gate 仍需獨立人工批准。"}, +] + +BLOCKED_ACTIONS = [ + "modify_workflow", + "workflow_dispatch_without_approval", + "enable_runner", + "change_runner_label", + "install_runner", + "restart_runner", + "use_runner_admin_token", + "enable_github_hosted_runner", + "collect_secret_value", + "collect_secret_hash", + "collect_partial_token", + "collect_masked_token", + "collect_runner_token", + "collect_webhook_secret", + "collect_deploy_key_private_material", + "collect_cookie_or_authorization_header", + "store_raw_workflow_payload", + "store_unredacted_action_log", + "create_repo_secret", + "update_repo_secret", + "rotate_secret", + "delete_secret", + "read_secret_store", + "change_secret_injection_path", + "modify_webhook", + "change_webhook_secret", + "modify_deploy_key", + "rotate_deploy_key", + "change_branch_protection", + "change_codeowners", + "sync_refs", + "force_push", + "switch_github_primary", + "disable_gitea", + "run_cd_pipeline_as_action", + "inject_k8s_secret", + "argocd_sync", + "production_deploy", + "accept_cd_success_as_security_acceptance", + "accept_deploy_marker_as_runtime_approval", + "accept_workflow_success_as_all_green", + "accept_runner_online_as_attestation", + "accept_route_200_as_deploy_acceptance", + "accept_ui_visible_as_runtime_approval", + "skip_log_redaction_review", + "skip_secret_name_parity", + "skip_runner_attestation", + "skip_cross_project_sync", + "skip_rollback_validation", + "skip_post_change_monitoring", + "open_runtime_gate", + "add_action_button", +] + +EXECUTION_BOUNDARIES = { + "runtime_execution_authorized": False, + "workflow_modification_authorized": False, + "workflow_dispatch_authorized": False, + "runner_change_authorized": False, + "github_hosted_runner_enable_authorized": False, + "webhook_modification_authorized": False, + "deploy_key_change_authorized": False, + "branch_protection_change_authorized": False, + "codeowners_change_authorized": False, + "repo_secret_change_authorized": False, + "secret_value_collection_allowed": False, + "secret_hash_collection_allowed": False, + "partial_token_collection_allowed": False, + "runner_token_collection_allowed": False, + "webhook_secret_collection_allowed": False, + "deploy_key_private_material_collection_allowed": False, + "secret_rotation_authorized": False, + "secret_store_read_authorized": False, + "secret_injection_change_authorized": False, + "gitea_action_dispatch_authorized": False, + "cd_pipeline_run_authorized": False, + "deploy_marker_write_authorized": False, + "k8s_secret_injection_authorized": False, + "argocd_sync_authorized": False, + "production_deploy_authorized": False, + "refs_sync_authorized": False, + "force_push_authorized": False, + "github_primary_switch_authorized": False, + "disable_gitea_authorized": False, + "action_buttons_allowed": False, + "not_authorization": True, +} + + +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]: + candidate_id = source["change_evidence_candidate_id"] + return { + "post_incident_readback_candidate_id": f"cd_runner_secret_injection_post_incident_readback:{candidate_id.split(':', 1)[1]}", + "source_change_evidence_candidate_id": candidate_id, + "status": "waiting_post_incident_readback", + "title": source["title"], + "control_tier": source["control_tier"], + "risk": source["risk"], + "source_refs": source["source_refs"], + "affected_scope": source["affected_scope"], + "workflow_secret_name_refs": source.get("workflow_secret_name_refs", []), + "write_capable": source["write_capable"], + "requires_runtime_approval_package": True, + "incident_or_change_ref": None, + "actor_attribution_ref": None, + "change_time_window_ref": None, + "change_intent_or_break_glass_ref": None, + "workflow_diff_state_ref": None, + "runner_attestation_state_ref": None, + "runner_executor_host_readback_ref": None, + "runner_workspace_cleanup_readback_ref": None, + "runner_permission_scope_ref": None, + "secret_name_parity_state_ref": None, + "secret_injection_route_state_ref": None, + "step_env_secret_guard_result_ref": None, + "log_redaction_readback_ref": None, + "deploy_marker_readback_ref": None, + "gitea_action_run_readback_ref": None, + "webhook_delivery_state_ref": None, + "deploy_key_branch_protection_codeowners_ref": None, + "notification_delivery_receipt_ref": None, + "before_after_deploy_state_ref": None, + "affected_route_or_service_state_ref": None, + "cross_project_sync_ref": None, + "rollback_validation_ref": None, + "postcheck_evidence_ref": None, + "post_change_monitoring_ref": None, + "recurrence_guard_ref": None, + "maintenance_window": "pending_post_incident_readback", + "rollback_owner": "pending_post_incident_readback", + "followup_owner": "pending_post_incident_readback", + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_post_incident_readback", + "no_secret_value_attestation": False, + "no_raw_workflow_payload_attestation": False, + "no_unredacted_log_attestation": False, + "no_false_green_attestation": False, + "not_approval": True, + "readback_fields": READBACK_FIELDS, + "required_readback_fields": REQUIRED_READBACK_FIELDS, + "reviewer_checks": [item["check_id"] for item in REVIEWER_CHECKS], + "outcome_lanes": [item["lane_id"] for item in OUTCOME_LANES], + "blocked_actions": BLOCKED_ACTIONS, + "post_incident_readback_received": False, + "post_incident_readback_accepted": False, + "actor_attribution_accepted": False, + "workflow_diff_state_accepted": False, + "runner_attestation_accepted": False, + "runner_executor_host_readback_accepted": False, + "runner_workspace_cleanup_accepted": False, + "runner_permission_scope_accepted": False, + "secret_name_parity_accepted": False, + "secret_injection_route_accepted": False, + "step_env_secret_guard_accepted": False, + "log_redaction_readback_accepted": False, + "deploy_marker_readback_accepted": False, + "gitea_action_run_readback_accepted": False, + "webhook_delivery_state_accepted": False, + "deploy_key_branch_protection_codeowners_accepted": False, + "notification_delivery_receipt_accepted": False, + "before_after_deploy_state_accepted": False, + "affected_route_or_service_state_accepted": False, + "cross_project_sync_accepted": False, + "rollback_validation_accepted": False, + "postcheck_evidence_accepted": False, + "post_change_monitoring_accepted": False, + "recurrence_guard_accepted": False, + "no_false_green_accepted": False, + "runtime_gate": False, + **{key: value for key, value in EXECUTION_BOUNDARIES.items() if key != "not_authorization"}, + } + + +def build_report(root: Path, generated_at: str | None) -> dict[str, Any]: + source = load_json( + root / "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json" + ) + source_summary = source["summary"] + candidates = [build_candidate(item) for item in source["change_evidence_candidates"]] + c0_candidates = [item for item in candidates if item["control_tier"] == "C0"] + c1_candidates = [item for item in candidates if item["control_tier"] == "C1"] + report_time = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds") + + return { + "schema_version": "cd_runner_secret_injection_post_incident_readback_plan_v1", + "generated_at": report_time, + "git_commit": git_short_sha(root), + "status": "post_incident_readback_plan_ready_no_runtime_action", + "mode": "metadata_only_no_secret_value_no_workflow_runner_secret_change", + "source_paths": [ + "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", + ".gitea/workflows/cd.yaml", + ".gitea/workflows/code-review.yaml", + ".gitea/workflows/deploy-alerts.yaml", + "scripts/ci/check-gitea-step-env-secrets.js", + ], + "summary": { + "source_change_evidence_candidate_count": source_summary["change_evidence_candidate_count"], + "source_c0_change_evidence_candidate_count": source_summary["c0_change_evidence_candidate_count"], + "source_c1_change_evidence_candidate_count": source_summary["c1_change_evidence_candidate_count"], + "source_required_evidence_field_count": source_summary["required_evidence_field_count"], + "source_reviewer_check_count": source_summary["reviewer_check_count"], + "source_blocked_action_count": source_summary["blocked_action_count"], + "source_change_evidence_accepted_count": source_summary["change_evidence_accepted_count"], + "source_runtime_gate_count": source_summary["runtime_gate_count"], + "readback_candidate_count": len(candidates), + "c0_readback_candidate_count": len(c0_candidates), + "c1_readback_candidate_count": len(c1_candidates), + "write_capable_readback_candidate_count": sum(1 for item in candidates if item["write_capable"]), + "secret_sensitive_readback_candidate_count": len(candidates), + "runner_or_workflow_readback_candidate_count": len(candidates), + "deploy_or_run_readback_required_candidate_count": len(candidates), + "cross_project_sync_required_candidate_count": len(candidates), + "no_false_green_required_candidate_count": len(candidates), + "readback_field_count": len(READBACK_FIELDS), + "required_readback_field_count": len(REQUIRED_READBACK_FIELDS), + "reviewer_check_count": len(REVIEWER_CHECKS), + "outcome_lane_count": len(OUTCOME_LANES), + "blocked_action_count": len(BLOCKED_ACTIONS), + "post_incident_readback_received_count": 0, + "post_incident_readback_accepted_count": 0, + "actor_attribution_accepted_count": 0, + "workflow_diff_state_accepted_count": 0, + "runner_attestation_accepted_count": 0, + "runner_executor_host_readback_accepted_count": 0, + "runner_workspace_cleanup_accepted_count": 0, + "runner_permission_scope_accepted_count": 0, + "secret_name_parity_accepted_count": 0, + "secret_injection_route_accepted_count": 0, + "step_env_secret_guard_accepted_count": 0, + "log_redaction_readback_accepted_count": 0, + "deploy_marker_readback_accepted_count": 0, + "gitea_action_run_readback_accepted_count": 0, + "webhook_delivery_state_accepted_count": 0, + "deploy_key_branch_protection_codeowners_accepted_count": 0, + "notification_delivery_receipt_accepted_count": 0, + "before_after_deploy_state_accepted_count": 0, + "affected_route_or_service_state_accepted_count": 0, + "cross_project_sync_accepted_count": 0, + "rollback_validation_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "post_change_monitoring_accepted_count": 0, + "recurrence_guard_accepted_count": 0, + "no_false_green_accepted_count": 0, + "workflow_modification_authorized_count": 0, + "workflow_dispatch_authorized_count": 0, + "runner_change_authorized_count": 0, + "github_hosted_runner_enable_authorized_count": 0, + "repo_secret_change_authorized_count": 0, + "secret_value_collection_allowed_count": 0, + "secret_injection_change_authorized_count": 0, + "webhook_modification_authorized_count": 0, + "deploy_key_change_authorized_count": 0, + "branch_protection_change_authorized_count": 0, + "codeowners_change_authorized_count": 0, + "gitea_action_dispatch_authorized_count": 0, + "cd_pipeline_run_authorized_count": 0, + "k8s_secret_injection_authorized_count": 0, + "argocd_sync_authorized_count": 0, + "production_deploy_authorized_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "secret_metadata_coverage_percent_after_readback_plan": 70, + "gitea_workflow_runner_coverage_percent_after_readback_plan": 74, + }, + "execution_boundaries": EXECUTION_BOUNDARIES, + "readback_fields": READBACK_FIELDS, + "required_readback_fields": REQUIRED_READBACK_FIELDS, + "reviewer_checks": REVIEWER_CHECKS, + "outcome_lanes": OUTCOME_LANES, + "blocked_actions": BLOCKED_ACTIONS, + "readback_candidates": candidates, + "operator_interpretation": [ + "此計畫只描述 CD / runner / secret injection 事故後如何回讀,不是 workflow、runner 或 secret 變更批准。", + "secret 只能以名稱、scope、present-absent、owner 與 redacted evidence ref 呈現,不得保存 value、hash、partial token 或 runner token。", + "CD success、deploy marker、workflow success、route 200、runner online、AwoooP approval 與 UI 可見狀態都不能被解讀成 runtime gate 已開。", + "未來若要修改 workflow、runner、secret injection、webhook、deploy key、branch protection、CODEOWNERS、refs 或 production deploy,仍需獨立維護窗口、rollback owner、跨專案同步與 runtime approval package。", + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser(description="CD / Runner / Secret injection 事故後回讀只讀計畫") + parser.add_argument("--root", default=".", help="repo root") + parser.add_argument("--output", help="寫出 JSON 報告") + parser.add_argument("--generated-at", help="固定報告時間,供 committed snapshot 使用") + args = parser.parse_args() + + root = Path(args.root).resolve() + report = build_report(root, 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( + "CD_RUNNER_SECRET_INJECTION_POST_INCIDENT_READBACK_PLAN_OK " + f"candidates={summary['readback_candidate_count']} " + f"c0={summary['c0_readback_candidate_count']} " + f"write_capable={summary['write_capable_readback_candidate_count']} " + f"checks={summary['reviewer_check_count']} " + f"lanes={summary['outcome_lane_count']} " + f"accepted={summary['post_incident_readback_accepted_count']} " + f"runtime_gate={summary['runtime_gate_count']}", + file=sys.stderr, + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/security/high-value-config-control-coverage.py b/scripts/security/high-value-config-control-coverage.py index f45e10f96..54d25e908 100644 --- a/scripts/security/high-value-config-control-coverage.py +++ b/scripts/security/high-value-config-control-coverage.py @@ -77,8 +77,8 @@ CONTROL_STATUS_BY_CATEGORY = { "next_owner_action": "補 GitOps / K8s 事故回讀包:incident / change ref、actor role / team、ArgoCD sync / health / revision、degraded / Pending / image pull / scheduling 摘要、rollout before-after、event summary、metrics / alert、drift scanner、CronJob schedule、NetworkPolicy / Service / RBAC 影響、public/admin route、AI provider、monitoring、operator notification、cross-project sync、recovery 或 still-degraded ref、recurrence guard、maintenance window、rollback revision、rollback owner、post-check owner 與 no-secret-value evidence。", }, "secret_metadata": { - "coverage_status": "secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", - "coverage_percent": 68, + "coverage_status": "post_incident_readback_plan_ready_needs_secret_injection_owner_evidence", + "coverage_percent": 70, "evidence_refs": [ "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", "docs/security/source-control-workflow-secret-name-inventory.snapshot.json", @@ -86,23 +86,27 @@ CONTROL_STATUS_BY_CATEGORY = { "docs/security/source-control-workflow-secret-name-owner-response.snapshot.json", "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json", "docs/security/SECRETS_REFERENCE.md", ], - "current_gap": "已固定 secret name / injection owner 變更證據驗收帳本;secret value、hash、partial token、secret store read、secret rotation、repo secret change 與 injection path change 仍全部為 0。", - "next_owner_action": "補 secret name parity ref、injection route owner、rotation owner、guard result ref、rollback owner、post-check evidence 與 redacted evidence refs。", + "current_gap": "已固定 secret name / injection owner 變更證據驗收帳本,並新增事故後回讀計畫;secret name parity state、secret injection route、step-env secret guard、log redaction、deploy marker / Gitea run readback、rollback、post-check、防再發與 no-false-green 已納入;secret value、hash、partial token、runner token、secret store read、secret rotation、repo secret change 與 injection path change 仍全部為 0。", + "next_owner_action": "補 secret name parity state ref、secret injection route state ref、step-env secret guard result、log redaction readback、deploy marker / Gitea run readback、notification receipt、rollback owner、post-check evidence、recurrence guard 與 no-secret-value evidence。", }, "gitea_workflow_runner_source_control": { - "coverage_status": "cd_runner_secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", - "coverage_percent": 72, + "coverage_status": "post_incident_readback_plan_ready_needs_workflow_runner_owner_evidence", + "coverage_percent": 74, "evidence_refs": [ "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-OWNER-RESPONSE.md", "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json", "docs/security/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md", ], - "current_gap": "已固定 CD / runner / secret injection 變更證據驗收帳本;workflow diff、runner attestation、secret parity、guard result、deploy marker readback、rollback owner 與 post-check evidence 仍全部為 0。", - "next_owner_action": "補 workflow diff ref、runner owner attestation、secret name parity ref、Gitea run readback、guard result、maintenance window、rollback owner 與 post-check evidence。", + "current_gap": "已固定 CD / runner / secret injection 變更證據驗收帳本,並新增事故後回讀計畫;workflow diff state、runner attestation、executor / host、workspace cleanup、permission scope、webhook / notification、deploy key / branch protection / CODEOWNERS、deploy marker / Gitea run、rollback、post-change monitoring、防再發與 no-false-green 已納入;workflow 修改、dispatch、runner 啟用 / 重啟、GitHub hosted runner、webhook / deploy key / branch protection / CODEOWNERS 修改仍全部為 0。", + "next_owner_action": "補 workflow diff state ref、runner owner attestation、executor / host readback、workspace cleanup、permission scope、Gitea run readback、deploy marker readback、webhook / notification receipt、maintenance window、rollback owner、post-change monitoring 與 recurrence guard evidence。", }, "public_admin_api_runtime_config": { "coverage_status": "frontend_sensitive_surface_guard_ready_needs_runtime_config_owner_evidence", @@ -392,6 +396,8 @@ def build_report(root: Path, generated_at: str | None) -> dict[str, Any]: "post_incident_readback_plan_ready_needs_gitops_owner_evidence", "secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", "cd_runner_secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", + "post_incident_readback_plan_ready_needs_secret_injection_owner_evidence", + "post_incident_readback_plan_ready_needs_workflow_runner_owner_evidence", "change_evidence_acceptance_ready_needs_runtime_config_owner_evidence", "frontend_sensitive_surface_guard_ready_needs_runtime_config_owner_evidence", "owner_response_acceptance_ledger_ready_needs_restore_drill_owner", diff --git a/scripts/security/iwooos-config-control-guard.py b/scripts/security/iwooos-config-control-guard.py index 33f042d69..872801cf2 100644 --- a/scripts/security/iwooos-config-control-guard.py +++ b/scripts/security/iwooos-config-control-guard.py @@ -20,8 +20,8 @@ EXPECTED_CATEGORIES = { "nginx_public_gateway": 92, "dns_tls_certbot": 78, "k8s_production_gitops": 66, - "secret_metadata": 68, - "gitea_workflow_runner_source_control": 72, + "secret_metadata": 70, + "gitea_workflow_runner_source_control": 74, "public_admin_api_runtime_config": 66, "backup_restore_credential": 64, "agent_bounty_protocol_runtime": 68, @@ -63,6 +63,7 @@ REQUIRED_CONTROL_DOCS = [ "docs/security/K8S-ARGOCD-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/K8S-ARGOCD-POST-INCIDENT-READBACK-PLAN.md", "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", "docs/security/PUBLIC-RUNTIME-CONFIG-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/MONITORING-OWNER-REQUEST-DRAFT.md", "docs/security/MONITORING-POST-INCIDENT-READBACK-PLAN.md", @@ -600,6 +601,55 @@ ARTIFACT_SPECS = [ "runtime_gate_count": 0, }, }, + { + "label": "cd runner secret injection post incident readback plan", + "path": "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json", + "schema": "cd_runner_secret_injection_post_incident_readback_plan_v1", + "status": "post_incident_readback_plan_ready_no_runtime_action", + "list_counts": { + "readback_candidates": 5, + "blocked_actions": 52, + "reviewer_checks": 30, + "outcome_lanes": 11, + "required_readback_fields": 33, + }, + "summary_counts": { + "source_change_evidence_candidate_count": 5, + "source_c0_change_evidence_candidate_count": 4, + "source_c1_change_evidence_candidate_count": 1, + "source_required_evidence_field_count": 19, + "source_reviewer_check_count": 19, + "source_blocked_action_count": 32, + "source_change_evidence_accepted_count": 0, + "source_runtime_gate_count": 0, + "readback_candidate_count": 5, + "c0_readback_candidate_count": 4, + "c1_readback_candidate_count": 1, + "write_capable_readback_candidate_count": 5, + "secret_sensitive_readback_candidate_count": 5, + "runner_or_workflow_readback_candidate_count": 5, + "deploy_or_run_readback_required_candidate_count": 5, + "cross_project_sync_required_candidate_count": 5, + "no_false_green_required_candidate_count": 5, + "readback_field_count": 44, + "required_readback_field_count": 33, + "reviewer_check_count": 30, + "outcome_lane_count": 11, + "blocked_action_count": 52, + "post_incident_readback_received_count": 0, + "post_incident_readback_accepted_count": 0, + "workflow_diff_state_accepted_count": 0, + "runner_attestation_accepted_count": 0, + "secret_name_parity_accepted_count": 0, + "secret_injection_route_accepted_count": 0, + "deploy_marker_readback_accepted_count": 0, + "gitea_action_run_readback_accepted_count": 0, + "log_redaction_readback_accepted_count": 0, + "runtime_gate_count": 0, + "secret_metadata_coverage_percent_after_readback_plan": 70, + "gitea_workflow_runner_coverage_percent_after_readback_plan": 74, + }, + }, { "label": "public runtime config change evidence acceptance", "path": "docs/security/public-runtime-config-change-evidence-acceptance.snapshot.json", diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 1f6b2496e..9e1665bdf 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -216,6 +216,9 @@ def validate(root: Path) -> None: cd_runner_secret_injection_change_evidence_acceptance = load_json( security_dir / "cd-runner-secret-injection-change-evidence-acceptance.snapshot.json" ) + cd_runner_secret_injection_post_incident_readback_plan = load_json( + security_dir / "cd-runner-secret-injection-post-incident-readback-plan.snapshot.json" + ) public_runtime_config_change_evidence_acceptance = load_json( security_dir / "public-runtime-config-change-evidence-acceptance.snapshot.json" ) @@ -3106,12 +3109,12 @@ def validate(root: Path) -> None: assert_equal( "high_value_config_coverage.coverage_categories.secret_metadata.coverage_percent", secret_metadata_category["coverage_percent"], - 68, + 70, ) assert_equal( "high_value_config_coverage.coverage_categories.secret_metadata.coverage_status", secret_metadata_category["coverage_status"], - "secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", + "post_incident_readback_plan_ready_needs_secret_injection_owner_evidence", ) for evidence_ref in [ "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", @@ -3120,6 +3123,8 @@ def validate(root: Path) -> None: "docs/security/source-control-workflow-secret-name-owner-response.snapshot.json", "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json", "docs/security/SECRETS_REFERENCE.md", ]: assert_contains( @@ -3135,18 +3140,20 @@ def validate(root: Path) -> None: assert_equal( "high_value_config_coverage.coverage_categories.workflow_runner.coverage_percent", workflow_runner_category["coverage_percent"], - 72, + 74, ) assert_equal( "high_value_config_coverage.coverage_categories.workflow_runner.coverage_status", workflow_runner_category["coverage_status"], - "cd_runner_secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", + "post_incident_readback_plan_ready_needs_workflow_runner_owner_evidence", ) for evidence_ref in [ "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-OWNER-RESPONSE.md", "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-POST-INCIDENT-READBACK-PLAN.md", + "docs/security/cd-runner-secret-injection-post-incident-readback-plan.snapshot.json", "docs/security/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md", ]: assert_contains( @@ -8049,6 +8056,64 @@ def validate(root: Path) -> None: "cd_runner_secret_injection_change_evidence_acceptance_secret_metadata_coverage_percent_after_acceptance": 68, "cd_runner_secret_injection_change_evidence_acceptance_gitea_workflow_runner_coverage_percent_before_acceptance": 70, "cd_runner_secret_injection_change_evidence_acceptance_gitea_workflow_runner_coverage_percent_after_acceptance": 72, + "cd_runner_secret_injection_post_incident_readback_plan_first_layer": True, + "cd_runner_secret_injection_post_incident_readback_plan_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_c0_candidate_count": 4, + "cd_runner_secret_injection_post_incident_readback_plan_c1_candidate_count": 1, + "cd_runner_secret_injection_post_incident_readback_plan_write_capable_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_secret_sensitive_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_runner_or_workflow_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_deploy_or_run_readback_required_candidate_count": 5, + "cd_runner_secret_injection_post_incident_readback_plan_required_readback_field_count": 33, + "cd_runner_secret_injection_post_incident_readback_plan_reviewer_check_count": 30, + "cd_runner_secret_injection_post_incident_readback_plan_outcome_lane_count": 11, + "cd_runner_secret_injection_post_incident_readback_plan_blocked_action_count": 52, + "cd_runner_secret_injection_post_incident_readback_plan_received_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_workflow_diff_state_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_attestation_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_executor_host_readback_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_workspace_cleanup_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_permission_scope_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_name_parity_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_injection_route_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_step_env_secret_guard_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_log_redaction_readback_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_deploy_marker_readback_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_gitea_action_run_readback_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_webhook_delivery_state_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_deploy_key_branch_protection_codeowners_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_notification_delivery_receipt_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_before_after_deploy_state_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_affected_route_or_service_state_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_cross_project_sync_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_rollback_validation_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_postcheck_evidence_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_post_change_monitoring_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_recurrence_guard_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_no_false_green_accepted_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_workflow_modification_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_workflow_dispatch_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runner_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_github_hosted_runner_enable_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_webhook_modification_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_deploy_key_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_branch_protection_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_codeowners_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_repo_secret_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_value_collection_allowed_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_injection_change_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_gitea_action_dispatch_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_cd_pipeline_run_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_k8s_secret_injection_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_argocd_sync_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_production_deploy_authorized_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_runtime_gate_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_action_button_count": 0, + "cd_runner_secret_injection_post_incident_readback_plan_secret_metadata_coverage_percent_after_readback_plan": 70, + "cd_runner_secret_injection_post_incident_readback_plan_gitea_workflow_runner_coverage_percent_after_readback_plan": 74, + "secret_metadata_coverage_percent": 70, + "gitea_workflow_runner_source_control_coverage_percent": 74, "public_runtime_config_change_evidence_acceptance_first_layer": True, "public_runtime_config_change_evidence_acceptance_candidate_count": 6, "public_runtime_config_change_evidence_acceptance_c0_candidate_count": 5, @@ -17900,8 +17965,8 @@ def validate(root: Path) -> None: "public_gateway_owner_response_acceptance_outcome_lane_count=8", "public_gateway_owner_response_acceptance_blocked_action_count=28", "k8s_production_gitops_coverage_percent=66", - "secret_metadata_coverage_percent=68", - "gitea_workflow_runner_source_control_coverage_percent=72", + "secret_metadata_coverage_percent=70", + "gitea_workflow_runner_source_control_coverage_percent=74", "public_admin_api_runtime_config_coverage_percent=66", "ai_provider_model_routing_coverage_percent=64", "ai_provider_owner_response_acceptance_candidate_count=8", @@ -17971,6 +18036,23 @@ def validate(root: Path) -> None: "cd_runner_secret_injection_change_evidence_acceptance_postcheck_evidence_accepted_count=0", "cd_runner_secret_injection_change_evidence_acceptance_runtime_approval_package_ready_count=0", "cd_runner_secret_injection_change_evidence_acceptance_runtime_gate_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_candidate_count=5", + "cd_runner_secret_injection_post_incident_readback_plan_c0_candidate_count=4", + "cd_runner_secret_injection_post_incident_readback_plan_write_capable_candidate_count=5", + "cd_runner_secret_injection_post_incident_readback_plan_required_readback_field_count=33", + "cd_runner_secret_injection_post_incident_readback_plan_reviewer_check_count=30", + "cd_runner_secret_injection_post_incident_readback_plan_outcome_lane_count=11", + "cd_runner_secret_injection_post_incident_readback_plan_blocked_action_count=52", + "cd_runner_secret_injection_post_incident_readback_plan_received_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_workflow_diff_state_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_runner_attestation_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_secret_name_parity_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_secret_injection_route_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_deploy_marker_readback_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_gitea_action_run_readback_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_log_redaction_readback_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_runtime_gate_count=0", "k8s_argocd_change_evidence_acceptance_candidate_count=4", "k8s_argocd_change_evidence_acceptance_c0_candidate_count=3", "k8s_argocd_change_evidence_acceptance_write_capable_candidate_count=4", @@ -18293,7 +18375,7 @@ def validate(root: Path) -> None: assert_text_contains( "iwooos_page.critical_config_priority_workflow_secret_percent", iwooos_projection_page, - "{ key: 'workflowSecret', rank: 'P0-4', state: '68% / 72%'", + "{ key: 'workflowSecret', rank: 'P0-4', state: '70% / 74%'", ) assert_text_contains( "iwooos_page.critical_config_priority_public_runtime_percent", @@ -18317,8 +18399,8 @@ def validate(root: Path) -> None: "nginx_public_gateway_post_incident_readback_plan_blocked_action_count=41", "nginx_public_gateway_post_incident_readback_plan_runtime_gate_count=0", "nginx_public_gateway_nginx_test_evidence_count=0", - "secret_metadata_coverage_percent=68", - "gitea_workflow_runner_source_control_coverage_percent=72", + "secret_metadata_coverage_percent=70", + "gitea_workflow_runner_source_control_coverage_percent=74", "public_admin_api_runtime_config_coverage_percent=66", "public_frontend_sensitive_surface_guard_file_count=225", "public_frontend_sensitive_surface_guard_forbidden_pattern_count=12", @@ -18357,6 +18439,20 @@ def validate(root: Path) -> None: "cd_runner_secret_injection_change_evidence_acceptance_secret_injection_route_accepted_count=0", "cd_runner_secret_injection_change_evidence_acceptance_runtime_approval_package_ready_count=0", "cd_runner_secret_injection_change_evidence_acceptance_runtime_gate_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_candidate_count=5", + "cd_runner_secret_injection_post_incident_readback_plan_c0_candidate_count=4", + "cd_runner_secret_injection_post_incident_readback_plan_write_capable_candidate_count=5", + "cd_runner_secret_injection_post_incident_readback_plan_required_readback_field_count=33", + "cd_runner_secret_injection_post_incident_readback_plan_reviewer_check_count=30", + "cd_runner_secret_injection_post_incident_readback_plan_outcome_lane_count=11", + "cd_runner_secret_injection_post_incident_readback_plan_blocked_action_count=52", + "cd_runner_secret_injection_post_incident_readback_plan_received_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_workflow_diff_state_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_runner_attestation_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_secret_name_parity_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_secret_injection_route_accepted_count=0", + "cd_runner_secret_injection_post_incident_readback_plan_runtime_gate_count=0", "k8s_argocd_change_evidence_acceptance_candidate_count=4", "k8s_argocd_change_evidence_acceptance_c0_candidate_count=3", "k8s_argocd_change_evidence_acceptance_write_capable_candidate_count=4", @@ -20194,6 +20290,237 @@ def validate(root: Path) -> None: f"cd_runner_secret_injection_change_evidence_acceptance.{item['change_evidence_candidate_id']}.{false_key}", item[false_key], ) + assert_equal( + "cd_runner_secret_injection_post_incident_readback_plan.schema", + cd_runner_secret_injection_post_incident_readback_plan["schema_version"], + "cd_runner_secret_injection_post_incident_readback_plan_v1", + ) + assert_equal( + "cd_runner_secret_injection_post_incident_readback_plan.status", + cd_runner_secret_injection_post_incident_readback_plan["status"], + "post_incident_readback_plan_ready_no_runtime_action", + ) + assert_equal( + "cd_runner_secret_injection_post_incident_readback_plan.mode", + cd_runner_secret_injection_post_incident_readback_plan["mode"], + "metadata_only_no_secret_value_no_workflow_runner_secret_change", + ) + expected_cd_runner_secret_injection_readback_summary = { + "source_change_evidence_candidate_count": 5, + "source_c0_change_evidence_candidate_count": 4, + "source_c1_change_evidence_candidate_count": 1, + "source_required_evidence_field_count": 19, + "source_reviewer_check_count": 19, + "source_blocked_action_count": 32, + "source_change_evidence_accepted_count": 0, + "source_runtime_gate_count": 0, + "readback_candidate_count": 5, + "c0_readback_candidate_count": 4, + "c1_readback_candidate_count": 1, + "write_capable_readback_candidate_count": 5, + "secret_sensitive_readback_candidate_count": 5, + "runner_or_workflow_readback_candidate_count": 5, + "deploy_or_run_readback_required_candidate_count": 5, + "cross_project_sync_required_candidate_count": 5, + "no_false_green_required_candidate_count": 5, + "readback_field_count": 44, + "required_readback_field_count": 33, + "reviewer_check_count": 30, + "outcome_lane_count": 11, + "blocked_action_count": 52, + "post_incident_readback_received_count": 0, + "post_incident_readback_accepted_count": 0, + "actor_attribution_accepted_count": 0, + "workflow_diff_state_accepted_count": 0, + "runner_attestation_accepted_count": 0, + "runner_executor_host_readback_accepted_count": 0, + "runner_workspace_cleanup_accepted_count": 0, + "runner_permission_scope_accepted_count": 0, + "secret_name_parity_accepted_count": 0, + "secret_injection_route_accepted_count": 0, + "step_env_secret_guard_accepted_count": 0, + "log_redaction_readback_accepted_count": 0, + "deploy_marker_readback_accepted_count": 0, + "gitea_action_run_readback_accepted_count": 0, + "webhook_delivery_state_accepted_count": 0, + "deploy_key_branch_protection_codeowners_accepted_count": 0, + "notification_delivery_receipt_accepted_count": 0, + "before_after_deploy_state_accepted_count": 0, + "affected_route_or_service_state_accepted_count": 0, + "cross_project_sync_accepted_count": 0, + "rollback_validation_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "post_change_monitoring_accepted_count": 0, + "recurrence_guard_accepted_count": 0, + "no_false_green_accepted_count": 0, + "workflow_modification_authorized_count": 0, + "workflow_dispatch_authorized_count": 0, + "runner_change_authorized_count": 0, + "github_hosted_runner_enable_authorized_count": 0, + "webhook_modification_authorized_count": 0, + "deploy_key_change_authorized_count": 0, + "branch_protection_change_authorized_count": 0, + "codeowners_change_authorized_count": 0, + "repo_secret_change_authorized_count": 0, + "secret_value_collection_allowed_count": 0, + "secret_injection_change_authorized_count": 0, + "gitea_action_dispatch_authorized_count": 0, + "cd_pipeline_run_authorized_count": 0, + "k8s_secret_injection_authorized_count": 0, + "argocd_sync_authorized_count": 0, + "production_deploy_authorized_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "secret_metadata_coverage_percent_after_readback_plan": 70, + "gitea_workflow_runner_coverage_percent_after_readback_plan": 74, + } + for key, expected in expected_cd_runner_secret_injection_readback_summary.items(): + assert_equal( + f"cd_runner_secret_injection_post_incident_readback_plan.summary.{key}", + cd_runner_secret_injection_post_incident_readback_plan["summary"][key], + expected, + ) + for key, value in cd_runner_secret_injection_post_incident_readback_plan["execution_boundaries"].items(): + if key == "not_authorization": + assert_true( + f"cd_runner_secret_injection_post_incident_readback_plan.execution_boundaries.{key}", + value, + ) + else: + assert_false( + f"cd_runner_secret_injection_post_incident_readback_plan.execution_boundaries.{key}", + value, + ) + expected_cd_runner_secret_injection_readback_ids = [ + "cd_runner_secret_injection_post_incident_readback:cd_pipeline_deploy_marker_and_k8s_secret_injection", + "cd_runner_secret_injection_post_incident_readback:code_review_pipeline_secret_and_notification_surface", + "cd_runner_secret_injection_post_incident_readback:deploy_alerts_and_monitoring_route", + "cd_runner_secret_injection_post_incident_readback:runner_label_and_executor_attestation", + "cd_runner_secret_injection_post_incident_readback:repository_secret_name_parity_and_injection_owner", + ] + assert_equal( + "cd_runner_secret_injection_post_incident_readback_plan.candidate_ids", + [ + item["post_incident_readback_candidate_id"] + for item in cd_runner_secret_injection_post_incident_readback_plan["readback_candidates"] + ], + expected_cd_runner_secret_injection_readback_ids, + ) + assert_equal( + "cd_runner_secret_injection_post_incident_readback_plan.reviewer_checks.count", + len(cd_runner_secret_injection_post_incident_readback_plan["reviewer_checks"]), + 30, + ) + assert_equal( + "cd_runner_secret_injection_post_incident_readback_plan.outcome_lanes.count", + len(cd_runner_secret_injection_post_incident_readback_plan["outcome_lanes"]), + 11, + ) + assert_equal( + "cd_runner_secret_injection_post_incident_readback_plan.blocked_actions.count", + len(cd_runner_secret_injection_post_incident_readback_plan["blocked_actions"]), + 52, + ) + for item in cd_runner_secret_injection_post_incident_readback_plan["readback_candidates"]: + assert_equal( + f"cd_runner_secret_injection_post_incident_readback_plan.{item['post_incident_readback_candidate_id']}.readback_fields", + len(item["readback_fields"]), + 44, + ) + assert_equal( + f"cd_runner_secret_injection_post_incident_readback_plan.{item['post_incident_readback_candidate_id']}.required_readback_fields", + len(item["required_readback_fields"]), + 33, + ) + assert_equal( + f"cd_runner_secret_injection_post_incident_readback_plan.{item['post_incident_readback_candidate_id']}.reviewer_checks", + len(item["reviewer_checks"]), + 30, + ) + assert_equal( + f"cd_runner_secret_injection_post_incident_readback_plan.{item['post_incident_readback_candidate_id']}.outcome_lanes", + len(item["outcome_lanes"]), + 11, + ) + assert_equal( + f"cd_runner_secret_injection_post_incident_readback_plan.{item['post_incident_readback_candidate_id']}.blocked_actions", + len(item["blocked_actions"]), + 52, + ) + assert_true( + f"cd_runner_secret_injection_post_incident_readback_plan.{item['post_incident_readback_candidate_id']}.not_approval", + item["not_approval"], + ) + assert_true( + f"cd_runner_secret_injection_post_incident_readback_plan.{item['post_incident_readback_candidate_id']}.requires_runtime_approval_package", + item["requires_runtime_approval_package"], + ) + for false_key in [ + "post_incident_readback_received", + "post_incident_readback_accepted", + "actor_attribution_accepted", + "workflow_diff_state_accepted", + "runner_attestation_accepted", + "runner_executor_host_readback_accepted", + "runner_workspace_cleanup_accepted", + "runner_permission_scope_accepted", + "secret_name_parity_accepted", + "secret_injection_route_accepted", + "step_env_secret_guard_accepted", + "log_redaction_readback_accepted", + "deploy_marker_readback_accepted", + "gitea_action_run_readback_accepted", + "webhook_delivery_state_accepted", + "deploy_key_branch_protection_codeowners_accepted", + "notification_delivery_receipt_accepted", + "before_after_deploy_state_accepted", + "affected_route_or_service_state_accepted", + "cross_project_sync_accepted", + "rollback_validation_accepted", + "postcheck_evidence_accepted", + "post_change_monitoring_accepted", + "recurrence_guard_accepted", + "no_secret_value_attestation", + "no_raw_workflow_payload_attestation", + "no_unredacted_log_attestation", + "no_false_green_attestation", + "no_false_green_accepted", + "runtime_execution_authorized", + "workflow_modification_authorized", + "workflow_dispatch_authorized", + "runner_change_authorized", + "github_hosted_runner_enable_authorized", + "webhook_modification_authorized", + "deploy_key_change_authorized", + "branch_protection_change_authorized", + "codeowners_change_authorized", + "repo_secret_change_authorized", + "secret_value_collection_allowed", + "secret_hash_collection_allowed", + "partial_token_collection_allowed", + "runner_token_collection_allowed", + "webhook_secret_collection_allowed", + "deploy_key_private_material_collection_allowed", + "secret_rotation_authorized", + "secret_store_read_authorized", + "secret_injection_change_authorized", + "gitea_action_dispatch_authorized", + "cd_pipeline_run_authorized", + "deploy_marker_write_authorized", + "k8s_secret_injection_authorized", + "argocd_sync_authorized", + "production_deploy_authorized", + "refs_sync_authorized", + "force_push_authorized", + "github_primary_switch_authorized", + "disable_gitea_authorized", + "runtime_gate", + "action_buttons_allowed", + ]: + assert_false( + f"cd_runner_secret_injection_post_incident_readback_plan.{item['post_incident_readback_candidate_id']}.{false_key}", + item[false_key], + ) assert_equal( "public_runtime_config_change_evidence_acceptance.schema", public_runtime_config_change_evidence_acceptance["schema_version"],