diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 1929642a8..9b4c0f7e6 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -17751,8 +17751,8 @@ "body": "production manifests、ConfigMap / Secret metadata、NetworkPolicy、CronJob 與 rollback revision 需被納管;GitOps 變更證據驗收已固定 proposed commit、rendered diff、ArgoCD readback、health before / after、rollout、route smoke、metrics / alert 與 rollback 欄位,目前仍不執行 ArgoCD sync、kubectl、Helm upgrade 或 live patch。" }, "workflowSecret": { - "title": "Workflow / runner / secret metadata", - "body": "Gitea workflow、runner label、deploy key、webhook、branch protection、CODEOWNERS 與 secret name 只能收 metadata,不收 value、hash、partial token 或 private key。" + "title": "工作流程 / 執行器 / 機密中繼資料", + "body": "Gitea 工作流程、執行器標籤、部署金鑰、webhook、分支保護、CODEOWNERS 與機密名稱已新增變更證據驗收;目前只收脫敏參照、執行紀錄代號、負責人與回復方案,不收明文值、hash、片段 token 或私鑰,也不修改工作流程、啟用執行器或輪替機密。" }, "publicRuntime": { "title": "Public / admin / API runtime config", @@ -17820,7 +17820,7 @@ "highValueConfigControlCoverage": { "eyebrow": "高價值配置覆蓋矩陣", "title": "14 類重要配置已進入同一張控管矩陣", - "subtitle": "這張卡顯示全域高價值配置控管成熟度,不是單次變更分類;Nginx、DNS / TLS、K8s、Secret、Workflow、Backup、Monitoring、AI provider、agent-bounty runtime 都已註冊,但 owner response 與執行期仍為 0。", + "subtitle": "這張卡顯示全域高價值配置控管成熟度,不是單次變更分類;Nginx、DNS / TLS、K8s、機密、工作流程、執行器、備份、監控、AI provider、agent-bounty runtime 都已註冊,但負責人回覆與執行期仍為 0。", "coverageLabel": "只讀成熟度", "boundaryTitle": "配置覆蓋矩陣邊界", "boundaryIntro": "以下鍵值固定:矩陣只顯示分類、證據與下一步收件順序,不代表 live evidence 已取得,也不代表 reload、sync、scan、secret rotation、agent-bounty runtime 或主機操作已授權。", @@ -17843,6 +17843,10 @@ } }, "items": { + "workflowSecret": { + "title": "工作流程 / 執行器 / 機密中繼資料", + "body": "持續部署、程式碼審查、部署通知、執行器證明與機密名稱一致性已新增變更證據驗收帳本;機密中繼資料成熟度為 68%,工作流程 / 執行器成熟度為 72%,但工作流程差異、執行器證明、機密名稱一致性、注入路徑、部署標記回讀、防護檢查、回復負責人與後檢證據仍全部為 0。" + }, "dockerSystemd": { "title": "Docker / systemd 主機服務", "body": "repo-only 清冊、owner request draft 與 owner response acceptance 只讀帳本已納入 9 個 surface;下一步仍需 live hash metadata、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。" diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 1929642a8..9b4c0f7e6 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -17751,8 +17751,8 @@ "body": "production manifests、ConfigMap / Secret metadata、NetworkPolicy、CronJob 與 rollback revision 需被納管;GitOps 變更證據驗收已固定 proposed commit、rendered diff、ArgoCD readback、health before / after、rollout、route smoke、metrics / alert 與 rollback 欄位,目前仍不執行 ArgoCD sync、kubectl、Helm upgrade 或 live patch。" }, "workflowSecret": { - "title": "Workflow / runner / secret metadata", - "body": "Gitea workflow、runner label、deploy key、webhook、branch protection、CODEOWNERS 與 secret name 只能收 metadata,不收 value、hash、partial token 或 private key。" + "title": "工作流程 / 執行器 / 機密中繼資料", + "body": "Gitea 工作流程、執行器標籤、部署金鑰、webhook、分支保護、CODEOWNERS 與機密名稱已新增變更證據驗收;目前只收脫敏參照、執行紀錄代號、負責人與回復方案,不收明文值、hash、片段 token 或私鑰,也不修改工作流程、啟用執行器或輪替機密。" }, "publicRuntime": { "title": "Public / admin / API runtime config", @@ -17820,7 +17820,7 @@ "highValueConfigControlCoverage": { "eyebrow": "高價值配置覆蓋矩陣", "title": "14 類重要配置已進入同一張控管矩陣", - "subtitle": "這張卡顯示全域高價值配置控管成熟度,不是單次變更分類;Nginx、DNS / TLS、K8s、Secret、Workflow、Backup、Monitoring、AI provider、agent-bounty runtime 都已註冊,但 owner response 與執行期仍為 0。", + "subtitle": "這張卡顯示全域高價值配置控管成熟度,不是單次變更分類;Nginx、DNS / TLS、K8s、機密、工作流程、執行器、備份、監控、AI provider、agent-bounty runtime 都已註冊,但負責人回覆與執行期仍為 0。", "coverageLabel": "只讀成熟度", "boundaryTitle": "配置覆蓋矩陣邊界", "boundaryIntro": "以下鍵值固定:矩陣只顯示分類、證據與下一步收件順序,不代表 live evidence 已取得,也不代表 reload、sync、scan、secret rotation、agent-bounty runtime 或主機操作已授權。", @@ -17843,6 +17843,10 @@ } }, "items": { + "workflowSecret": { + "title": "工作流程 / 執行器 / 機密中繼資料", + "body": "持續部署、程式碼審查、部署通知、執行器證明與機密名稱一致性已新增變更證據驗收帳本;機密中繼資料成熟度為 68%,工作流程 / 執行器成熟度為 72%,但工作流程差異、執行器證明、機密名稱一致性、注入路徑、部署標記回讀、防護檢查、回復負責人與後檢證據仍全部為 0。" + }, "dockerSystemd": { "title": "Docker / systemd 主機服務", "body": "repo-only 清冊、owner request draft 與 owner response acceptance 只讀帳本已納入 9 個 surface;下一步仍需 live hash metadata、maintenance / restart window、rollback owner、post-check plan、disable switch 與 no-secret-value evidence。" diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index 5ead9e418..fead1f0ea 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -2105,7 +2105,7 @@ const highValueConfigControlCoverageBoundaries = [ 'high_value_config_control_coverage_c0_category_count=8', 'high_value_config_control_coverage_c1_category_count=4', 'high_value_config_control_coverage_average_percent=68', - 'high_value_config_control_coverage_needs_live_evidence_count=6', + 'high_value_config_control_coverage_needs_live_evidence_count=8', 'high_value_config_control_coverage_owner_response_required_count=14', 'high_value_config_control_coverage_owner_response_received_count=0', 'high_value_config_control_coverage_owner_response_accepted_count=0', @@ -2113,6 +2113,32 @@ const highValueConfigControlCoverageBoundaries = [ 'high_value_config_control_coverage_action_button_count=0', 'nginx_public_gateway_coverage_percent=88', 'k8s_production_gitops_coverage_percent=64', + 'secret_metadata_coverage_percent=68', + 'gitea_workflow_runner_source_control_coverage_percent=72', + '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_c1_candidate_count=1', + 'cd_runner_secret_injection_change_evidence_acceptance_write_capable_candidate_count=5', + 'cd_runner_secret_injection_change_evidence_acceptance_local_workflow_file_count=33', + 'cd_runner_secret_injection_change_evidence_acceptance_gitea_workflow_file_count=12', + 'cd_runner_secret_injection_change_evidence_acceptance_github_workflow_file_count=21', + 'cd_runner_secret_injection_change_evidence_acceptance_local_referenced_secret_name_count=42', + 'cd_runner_secret_injection_change_evidence_acceptance_runner_label_count=5', + 'cd_runner_secret_injection_change_evidence_acceptance_required_evidence_field_count=19', + 'cd_runner_secret_injection_change_evidence_acceptance_reviewer_check_count=19', + 'cd_runner_secret_injection_change_evidence_acceptance_outcome_lane_count=8', + 'cd_runner_secret_injection_change_evidence_acceptance_blocked_action_count=32', + 'cd_runner_secret_injection_change_evidence_acceptance_received_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_workflow_diff_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_runner_attestation_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_secret_name_parity_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_secret_injection_route_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_deploy_marker_readback_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_guard_result_accepted_count=0', + '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', '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', @@ -2236,6 +2262,27 @@ const highValueConfigControlCoverageBoundaries = [ 'live_alert_fire_authorized=false', 'alert_chain_smoke_authorized=false', 'workflow_modification_authorized=false', + 'webhook_modification_authorized=false', + 'runner_change_authorized=false', + 'deploy_key_change_authorized=false', + 'branch_protection_change_authorized=false', + 'codeowners_change_authorized=false', + 'repo_secret_change_authorized=false', + 'secret_hash_collection_allowed=false', + 'partial_token_collection_allowed=false', + 'secret_rotation_authorized=false', + 'secret_store_read_authorized=false', + 'secret_injection_change_authorized=false', + 'github_hosted_runner_enable_authorized=false', + 'gitea_action_dispatch_authorized=false', + 'cd_pipeline_run_authorized=false', + 'deploy_marker_write_authorized=false', + 'k8s_secret_injection_authorized=false', + 'production_deploy_authorized=false', + 'refs_sync_authorized=false', + 'force_push_authorized=false', + 'github_primary_switch_authorized=false', + 'disable_gitea_authorized=false', 'active_scan_authorized=false', 'agent_bounty_runtime_authorized=false', ] as const @@ -2251,7 +2298,7 @@ const criticalConfigPriorityItems: CriticalConfigPriorityItem[] = [ { key: 'nginxGateway', rank: 'P0-1', state: '88% / live 0', icon: Server, tone: 'warn' }, { key: 'dnsTls', rank: 'P0-2', state: '78% / probe 0', icon: Route, tone: 'warn' }, { key: 'k8sArgocd', rank: 'P0-3', state: '64% / sync 0', icon: Cloud, tone: 'warn' }, - { key: 'workflowSecret', rank: 'P0-4', state: 'metadata only', icon: GitBranch, tone: 'warn' }, + { key: 'workflowSecret', rank: 'P0-4', state: '68% / 72%', icon: GitBranch, tone: 'warn' }, { key: 'publicRuntime', rank: 'P0-5', state: 'route gate 0', icon: Network, tone: 'warn' }, { key: 'agentBounty', rank: 'P0-6', state: 'runtime 0', icon: Workflow, tone: 'locked' }, ] @@ -2270,6 +2317,23 @@ const criticalConfigPriorityBoundaries = [ 'nginx_public_gateway_rendered_diff_accepted=false', 'nginx_public_gateway_rendered_diff_acceptance_candidate_count=3', 'nginx_public_gateway_nginx_test_evidence_count=0', + 'secret_metadata_coverage_percent=68', + 'gitea_workflow_runner_source_control_coverage_percent=72', + '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', + 'cd_runner_secret_injection_change_evidence_acceptance_required_evidence_field_count=19', + 'cd_runner_secret_injection_change_evidence_acceptance_reviewer_check_count=19', + 'cd_runner_secret_injection_change_evidence_acceptance_outcome_lane_count=8', + 'cd_runner_secret_injection_change_evidence_acceptance_blocked_action_count=32', + 'cd_runner_secret_injection_change_evidence_acceptance_received_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_workflow_diff_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_runner_attestation_accepted_count=0', + 'cd_runner_secret_injection_change_evidence_acceptance_secret_name_parity_accepted_count=0', + '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', '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', @@ -2291,6 +2355,14 @@ const criticalConfigPriorityBoundaries = [ 'nodeport_change_authorized=false', 'rbac_change_authorized=false', 'workflow_modification_authorized=false', + 'runner_change_authorized=false', + 'repo_secret_change_authorized=false', + 'secret_injection_change_authorized=false', + 'gitea_action_dispatch_authorized=false', + 'cd_pipeline_run_authorized=false', + 'production_deploy_authorized=false', + 'force_push_authorized=false', + 'github_primary_switch_authorized=false', 'secret_value_collection_allowed=false', 'public_route_change_authorized=false', 'agent_bounty_runtime_authorized=false', diff --git a/docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md b/docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md new file mode 100644 index 000000000..acf42a9a9 --- /dev/null +++ b/docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md @@ -0,0 +1,120 @@ +# CD / Runner / Secret 注入變更證據驗收只讀帳本 + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-15 | +| 狀態 | `change_evidence_acceptance_ledger_ready_no_runtime_action` | +| 工具 | `scripts/security/cd-runner-secret-injection-change-evidence-acceptance.py` | +| Snapshot | `docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json` | +| Source evidence | `docs/security/source-control-workflow-secret-name-local-evidence.snapshot.json` | +| Source export request | `docs/security/source-control-workflow-secret-name-export-request.snapshot.json` | +| Source owner response | `docs/security/source-control-workflow-secret-name-owner-response.snapshot.json` | +| runtime gate | `0` | + +## 1. 目的 + +此帳本補在 workflow / runner / secret 名稱 inventory、redacted export request 與 owner response 收件包之後,專門驗收「CD / runner / secret injection 變更證據」是否足夠進入 reviewer acceptance。 + +它只處理 metadata-only evidence ref,不呼叫 Gitea / GitHub API、不讀 secret store、不讀 secret value、不修改 workflow、不啟用 runner、不 rotate secret、不 dispatch workflow、不觸發部署,也不把 deploy marker、Gitea Actions success、AwoooP approval 或 UI 可見狀態當成 runtime 授權。 + +## 2. 固定範圍 + +| 指標 | 數值 | 解讀 | +|------|------|------| +| `change_evidence_candidate_count` | `5` | CD pipeline、Code Review、Deploy alerts、Runner attestation、Secret parity 五類候選 | +| `c0_change_evidence_candidate_count` | `4` | CD、Code Review、Runner、Secret parity 為 C0 | +| `c1_change_evidence_candidate_count` | `1` | Deploy alerts / monitoring route 為 C1 | +| `write_capable_candidate_count` | `5` | 五類都可能影響 workflow、runner、secret injection、通知或部署路徑 | +| `local_workflow_file_count` | `33` | 本機只讀 workflow evidence 數 | +| `gitea_workflow_file_count` | `12` | Gitea workflow evidence 數 | +| `github_workflow_file_count` | `21` | GitHub workflow evidence 數 | +| `local_referenced_secret_name_count` | `42` | 只保存 secret 名稱,不保存 value | +| `runner_label_count` | `5` | `awoooi-host`、`harbor`、`k8s`、`self-hosted`、`ubuntu-latest` | +| `export_request_count` | `9` | 九個 in-scope repo 仍需 owner / read-only export | +| `export_lane_count` | `5` | webhook、runner、deploy key、branch protection / CODEOWNERS、secret name parity | +| `required_evidence_field_count` | `19` | 變更證據必填欄位 | +| `reviewer_check_count` | `19` | reviewer 必檢規則 | +| `outcome_lane_count` | `8` | 收件結果分流 | +| `blocked_action_count` | `32` | 明確禁止動作 | + +## 3. 必填變更證據欄位 + +1. `proposed_workflow_or_config_change_ref` +2. `workflow_diff_ref` +3. `runner_attestation_ref` +4. `secret_name_parity_ref` +5. `secret_injection_route_ref` +6. `deploy_marker_readback_ref` +7. `gitea_action_run_ref` +8. `guard_result_ref` +9. `log_redaction_review_ref` +10. `notification_route_owner_ref` +11. `blast_radius` +12. `maintenance_window` +13. `rollback_owner` +14. `rollback_plan_ref` +15. `postcheck_evidence_ref` +16. `affected_scope` +17. `redacted_evidence_refs` +18. `reviewer_outcome` +19. `not_approval` + +以上欄位都只能保存脫敏 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 或未脫敏截圖。 + +## 4. Reviewer checks + +| Check | 用途 | +|------|------| +| `change_ref_present` | 確認有 proposed workflow / config / policy change ref | +| `workflow_diff_ref_only` | 確認只收 workflow diff ref 或 committed patch ref | +| `gitea_actions_run_readback_ref_shape` | 確認 Gitea Actions readback 只保存 run / job / status ref | +| `deploy_marker_not_runtime_approval` | deploy marker 只能當部署證據,不代表 runtime approval | +| `runner_owner_attestation_present` | runner label、executor、host alias、owner 與維護窗口可追溯 | +| `hosted_minutes_risk_review_present` | hosted runner 額度與供應鏈風險需獨立 review | +| `secret_name_parity_ref_only` | secret parity 只能保存名稱、scope、present-absent 與 owner metadata | +| `no_secret_value_or_hash` | 確認沒有 secret value、hash、partial token 或 credential derivative | +| `secret_injection_path_called_out` | 涉及 CD / K8s secret injection 時標出 injection path 與 owner | +| `step_env_with_secret_guard_result_present` | 必須有 `check-gitea-step-env-secrets` 或等價 guard result | +| `telegram_route_owner_present` | 通知路徑必須確認 SRE route owner,不得新增 legacy route | +| `deploy_key_and_webhook_material_absent` | 不保存 webhook secret、deploy key private material、runner token 或 write token | +| `branch_protection_or_required_checks_impact_called_out` | 影響 required checks / CODEOWNERS / branch protection 時需標出影響 | +| `blast_radius_present` | 標出 repo、workflow、runner、secret metadata、notification、deploy path 影響 | +| `maintenance_window_present` | future workflow / runner / secret injection 變更需獨立維護窗口 | +| `rollback_owner_present` | rollback owner 與回復方式必須可追溯 | +| `postcheck_evidence_present` | 需有 guard result、run status、route smoke 或 notification receipt ref | +| `no_execution_claim` | 不把帳本、owner response、CD success 或 AwoooP approval 當執行批准 | +| `cross_project_sync_noted` | 影響 AwoooP、IwoooS、代理賞金協議、監控或公開服務時需跨專案同步 ref | + +## 5. Outcome lanes + +| Lane | 說明 | +|------|------| +| `waiting_change_evidence` | 尚未收到 CD / runner / secret injection 變更證據 | +| `quarantine_sensitive_payload` | 收到敏感值、runner token、webhook secret、private key 或未脫敏截圖時隔離 | +| `reject_unredacted_or_runtime_claim` | 出現未脫敏 payload 或把 evidence 誤當執行批准時拒收 | +| `request_supplement` | 缺 workflow diff、runner owner、secret parity、guard result、rollback 或 post-check 時補件 | +| `ready_for_reviewer_acceptance` | metadata 合格後進 reviewer acceptance | +| `ready_for_runtime_approval_package` | reviewer 接受後只能形成 runtime approval package | +| `waiting_maintenance_window` | future workflow / runner / secret injection 仍需獨立維護窗口 | +| `waiting_runtime_gate` | change evidence accepted 後 runtime gate 仍等待獨立人工批准 | + +## 6. 禁止動作 + +此帳本明確禁止修改 workflow、未批准 dispatch workflow、啟用或重啟 runner、修改 runner label、使用 runner admin token、啟用 GitHub hosted runner、收集 secret value / hash / partial token、建立 / 更新 / rotate / 刪除 repo secret、讀 secret store、修改 secret injection path、修改 webhook、修改 webhook secret、修改 deploy key、修改 branch protection、修改 CODEOWNERS、sync refs、force push、切 GitHub primary、停用 Gitea、把 CD pipeline 當 action 執行、注入 K8s secret、ArgoCD sync、production deploy 或新增 action button。 + +## 7. 完成度與邊界 + +| 工作 | 完成度 | 邊界 | +|------|--------|------| +| CD / Runner / Secret injection change evidence acceptance artifact | `100%` | 只讀帳本與 snapshot 已建立 | +| Gitea workflow / runner source-control 只讀治理成熟度 | `70% -> 72%` | 只代表變更證據驗收規則補齊,不代表 workflow / runner 可修改 | +| Secret metadata 只讀治理成熟度 | `66% -> 68%` | 只代表 secret name / injection owner evidence gate 補齊,不代表可讀或可改 secret | +| change evidence received / accepted | `0%` | 尚未收到或接受任何變更證據 | +| runtime approval package | `0%` | 尚未形成 runtime approval package | +| active runtime gate | `0` | 不開 workflow、runner、secret、deploy、ArgoCD 或 production action | + +## 8. 下一步 + +1. 要求 owner 只提供 workflow diff ref、runner attestation ref、secret name parity ref、secret injection route ref、Gitea run readback ref、guard result ref、rollback owner 與 post-check evidence。 +2. reviewer 只檢查 metadata 完整性、no-secret-value 與 no-execution-claim,不保存 raw workflow payload 或 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 31ea4ddf3..314ceab9a 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -2,7 +2,7 @@ | 項目 | 內容 | |------|------| -| 日期 | 2026-06-14 | +| 日期 | 2026-06-15 | | 狀態 | `coverage_matrix_ready` | | 工具 | `scripts/security/high-value-config-control-coverage.py` | | Snapshot | `docs/security/high-value-config-control-coverage.snapshot.json` | @@ -38,6 +38,12 @@ 2026-06-15 再新增 `docs/security/K8S-ARGOCD-CHANGE-EVIDENCE-ACCEPTANCE.md` 與 `docs/security/k8s-argocd-change-evidence-acceptance.snapshot.json`,將四個 K8s / ArgoCD scan group 轉成 GitOps 變更證據驗收只讀帳本。固定 `change_evidence_candidate_count=4`、`c0_change_evidence_candidate_count=3`、`write_capable_candidate_count=4`、`required_evidence_field_count=18`、`reviewer_check_count=18`、`outcome_lane_count=8`、`blocked_action_count=28`,讓 `k8s_production_gitops` 從 `62%` 推進到 `64%`;proposed commit、rendered manifest diff、ArgoCD app / sync revision、health before / after、rollout status、route smoke、metrics / alert、secret metadata parity、blast radius、maintenance window、rollback revision、postcheck owner、runtime approval package、ArgoCD sync、kubectl action、Helm upgrade、NetworkPolicy / NodePort / RBAC 變更、production write 與 runtime gate 仍全部為 `0 / false`。 +## 1.2a 2026-06-15 CD / Runner / Secret 注入變更證據驗收 + +已新增 `docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md` 與 `docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json`,將 CD pipeline、Code Review、Deploy alerts、Runner attestation 與 Secret parity / injection owner 轉成 metadata-only 變更證據驗收帳本。 + +固定數字為 `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`。 + ## 1.3 2026-06-14 agent-bounty-protocol owner request draft 已新增 `docs/security/AGENT-BOUNTY-OWNER-REQUEST-DRAFT.md` 與 `docs/security/agent-bounty-owner-request-draft.snapshot.json`,將 `agent-bounty-protocol` onboarding handoff 轉成 11 份 owner request draft。 @@ -82,7 +88,7 @@ | C2 類別 | `1` | 產品 runtime route 與跨產品邊界 | | C3 類別 | `1` | security evidence / snapshot / guard tooling | | 平均只讀控管成熟度 | `68%` | 僅代表框架 / evidence / owner packet / acceptance ledger 準備度,不代表 runtime 可執行 | -| 需要 live evidence 的類別 | `6` | 只能等 owner-provided redacted evidence 或維護窗口,不主動修改主機 | +| 需要 live / owner evidence 的類別 | `8` | 只能等 owner-provided redacted evidence 或維護窗口,不主動修改 workflow、secret、runner 或主機 | | owner response required | `14` | 每類都需要 owner response 才能往 accepted 前進 | | owner response received / accepted | `0 / 0` | 不得假性提高 | | runtime gate | `0` | 不得產生執行按鈕 | @@ -131,7 +137,16 @@ workflow_modification_authorized=false runner_change_authorized=false refs_sync_authorized=false force_push_authorized=false +gitea_action_dispatch_authorized=false +cd_pipeline_run_authorized=false +github_hosted_runner_enable_authorized=false +repo_secret_change_authorized=false +secret_store_read_authorized=false +secret_injection_change_authorized=false secret_value_collection_allowed=false +secret_hash_collection_allowed=false +partial_token_collection_allowed=false +secret_rotation_authorized=false active_scan_authorized=false agent_bounty_runtime_authorized=false payout_or_withdrawal_authorized=false @@ -187,6 +202,7 @@ python3 scripts/security/high-value-config-control-coverage.py \ | 覆蓋 snapshot / schema | `100%` | 已新增可重跑 snapshot 與 JSON schema | | DNS / TLS / certbot owner response acceptance | `100%` | 已新增 `domain_tls_certbot_owner_response_acceptance_v1`,4 個 C0 candidate、13 個 owner 必填欄位、13 個 reviewer checks、7 條 outcome lanes、20 類 blocked action;成熟度 `74% -> 78%` | | Docker / systemd / host service owner response acceptance | `100%` | 已新增 `host_service_owner_response_acceptance_v1`,9 個 candidate、3 個 write-capable、14 個 reviewer checks、7 條 outcome lanes、20 類 blocked action;成熟度 `50% -> 54%` | +| CD / Runner / Secret injection change evidence acceptance | `100%` | 已新增 `cd_runner_secret_injection_change_evidence_acceptance_v1`,5 個 candidate、4 個 C0、19 個 reviewer checks、8 條 outcome lanes、32 類 blocked action;secret metadata 成熟度 `66% -> 68%`,workflow / runner 成熟度 `70% -> 72%` | | owner response 收件 | `0%` | 尚未收到或接受任何 owner response | | live evidence collection | `0%` | 未 SSH、未 live probe、未 active scan | | runtime gate | `0%` | 未開啟任何執行期閘門 | diff --git a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md index 62d0b20e8..0c476b53b 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -63,6 +63,12 @@ 此更新只表示 proposed commit、rendered manifest diff、ArgoCD app / sync revision、health before / after、rollout status、route smoke、metrics / alert、secret metadata parity、blast radius、maintenance window、rollback revision 與 postcheck owner 已有收件驗收規則;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 仍全部為 `0 / false`。 +### 0.3b 2026-06-15 CD / Runner / Secret 注入變更證據驗收 + +`cd_runner_secret_injection_change_evidence_acceptance_v1` 已把 CD pipeline、Code Review、Deploy alerts、Runner attestation 與 Repository secret name parity / injection owner 轉成 metadata-only 變更證據驗收只讀帳本。固定 `candidates=5`、`c0=4`、`c1=1`、`write_capable=5`、`workflow_files=33`、`referenced_secret_names=42`、`runner_labels=5`、`required_evidence_fields=19`、`reviewer_checks=19`、`outcome_lanes=8`、`blocked_actions=32`。 + +此更新讓 `secret_metadata` 類別成熟度從 `66%` 推進到 `68%`,讓 `gitea_workflow_runner_source_control` 類別成熟度從 `70%` 推進到 `72%`。它只表示 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`。 + `backup_restore_owner_request_draft_v1` 已把 backup、restore、offsite、credential escrow、retention、Velero、alert / health 與 DR runbook 的 38 個 surface 轉成人工送件前 owner request draft。固定 `drafts=38`、`write_capable=27`、`live_evidence_required=38`、`owner_fields=14`、`blocked_actions=18`,但 request sent、owner response received / accepted、live backup evidence、backup run、restore run、offsite sync、remote delete、escrow marker write、retention change、host write、runtime gate 仍全部為 `0 / false`。 此更新仍不是 live network truth:live firewall、sudoers、known_hosts、NetworkPolicy、NodePort、WireGuard evidence、network owner、maintenance window、rollback owner 與 owner response received / accepted 全部仍為 `0`,也不得執行 SSH、keyscan、sudo、firewall change、NetworkPolicy apply、NodePort change 或 WireGuard cutover。 diff --git a/docs/security/IWOOOS-POSTURE-PROJECTION.md b/docs/security/IWOOOS-POSTURE-PROJECTION.md index 7003ef7c7..25692413f 100644 --- a/docs/security/IWOOOS-POSTURE-PROJECTION.md +++ b/docs/security/IWOOOS-POSTURE-PROJECTION.md @@ -95,10 +95,11 @@ IwoooS 首版只讀取或對齊以下已提交 evidence: 51. 10 個 frontend surface reverse bridge statuses,顯示既有資安入口目前是 embedded bridge、direct bridge 或 AwoooP read-only candidate;這只是連接狀態,不代表 owner response、runtime authorization、Code Review blocker、Gitea/GitHub action 或任何執行控制。 52. 6 個 source control primary readiness items,顯示 GitHub primary 前置缺口:candidate repo inventory、primary ready counter、owner response validation、refs truth、workflow / secret name inventory、rollback ADR;這只是 readiness,不代表 repo 建立、visibility 變更、refs mutation、secret value collection、primary switch 或 Gitea 停用。 53. 4 個 rollout risk read-only items,顯示風險來源部署 marker、`AWOOOI_ROLLOUT_RISK=1`、ArgoCD `Degraded` / `OutOfSync`、API health / smoke 已通過與執行期閘門仍為 0;這只是部署風險可見性,不代表 ArgoCD sync、kubectl、主機重啟、修復、部署或 runtime gate 已授權。 -54. 14 類 high-value config control coverage statuses,顯示 Nginx、DNS / TLS、K8s、secret、workflow、backup、agent-bounty runtime、monitoring、Docker / systemd、SSH / network、AI provider、產品 route 與 security evidence 的全域配置控管覆蓋矩陣;平均只讀成熟度 `68%`、C0 類別 `8`、需 live evidence 類別 `6`、owner response received / accepted 與 runtime gate 仍為 `0`,不代表 reload、sync、scan、secret rotation、payout 或主機操作授權。 +54. 14 類 high-value config control coverage statuses,顯示 Nginx、DNS / TLS、K8s、機密、工作流程、執行器、backup、agent-bounty runtime、monitoring、Docker / systemd、SSH / network、AI provider、產品 route 與 security evidence 的全域配置控管覆蓋矩陣;平均只讀成熟度 `68%`、C0 類別 `8`、需 live / owner evidence 類別 `8`、owner response received / accepted 與 runtime gate 仍為 `0`,不代表 reload、sync、scan、secret rotation、payout 或主機操作授權。 55. 9 個 host-service config repo-only inventory surfaces,顯示 Docker Compose、systemd / repair-bot、Ansible service role 與 host config backup capture 的第一層清冊;write-capable surface `3`、repair-bot whitelist `2`、systemd restart surface `1`,owner response、live evidence、restart window、rollback owner、runtime gate 與 action button 仍全部為 `0`,不代表 `docker compose`、`systemctl`、repair-bot 或 Ansible apply 已授權。 56. 16 個 SSH / network access repo-only inventory surfaces、owner response acceptance 與端口 / 防火牆變更證據驗收只讀帳本,顯示 SSH target、known_hosts workflow、CI deploy SSH、monitoring SSH、backup SSH capture、sudoers wrapper、NetworkPolicy、NodePort、WireGuard runbook 與 alert SSH action catalog 的第一層清冊;write-capable surface `6`、NetworkPolicy `2`、NodePort `2`、sudoers `1`、WireGuard `1`,acceptance candidate `16`、change evidence candidate `14`、reviewer check `16`、outcome lane `8`、blocked action `24`,讓 SSH / network 類別成熟度從 `58%` 推進到 `60%`;owner response、change evidence、actor、before / after state、cross-project sync、post-check evidence、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0`,不代表 SSH、sudo、firewall、port close / open、NetworkPolicy、NodePort、WireGuard、route smoke 或 known_hosts patch 已授權。 56a. 4 個 K8s / ArgoCD GitOps 變更證據驗收候選,顯示 production manifests、ArgoCD app、Velero、monitoring manifests 的 proposed commit、rendered manifest diff、ArgoCD app / sync revision、health before / after、rollout、route smoke、metrics / alert、secret metadata parity、blast radius、maintenance window、rollback revision 與 postcheck owner 收件規則;C0 candidate `3`、write-capable candidate `4`、reviewer check `18`、outcome lane `8`、blocked action `28`,讓 K8s / ArgoCD 類別成熟度從 `62%` 推進到 `64%`;change evidence、runtime approval package、ArgoCD API read、ArgoCD sync、kubectl action、Helm upgrade、NetworkPolicy / NodePort / RBAC change、production write、runtime gate 與 action button 仍全部為 `0`。 +56b. 5 個 CD / Runner / Secret 注入變更證據驗收候選,顯示 CD pipeline、程式碼審查、部署通知、執行器證明與 repository secret name parity / injection owner 的 metadata-only 收件規則;C0 candidate `4`、write-capable candidate `5`、local workflow file `33`、referenced secret name `42`、runner label `5`、reviewer check `19`、outcome lane `8`、blocked action `32`,讓 secret metadata 類別成熟度從 `66%` 推進到 `68%`,讓 Gitea workflow / runner 類別成熟度從 `70%` 推進到 `72%`;workflow diff、runner attestation、secret name parity、secret injection route、deploy marker readback、guard result、postcheck evidence、runtime approval package、workflow modification、runner change、repo secret change、secret rotation、Gitea action dispatch、production deploy、runtime gate 與 action button 仍全部為 `0`。 57. 38 個 Backup / restore / escrow / retention repo-only inventory surfaces,顯示 backup orchestration、service backup scripts、restic retention、offsite sync、credential escrow、Velero restore drill、backup health alert 與 cold-start / DR runbook 的第一層清冊;write-capable surface `27`、restore drill surface `4`、offsite / escrow surface `8`,owner response、live evidence、restore drill、offsite sync、credential escrow、retention change、runtime gate 與 action button 仍全部為 `0`,不代表 backup、restore、offsite sync、remote delete、restic prune、escrow marker write、rclone config 或 Velero restore 已授權。 58. 60 個 Monitoring / alerting / observability repo-only inventory surfaces,顯示 Prometheus、Alertmanager、Grafana、SigNoz、Sentry、Langfuse、OTEL、Telegram / notification policy、deploy / reload scripts 與 alert chain smoke scripts 的第一層清冊;write-capable surface `11`、alert rule surface `13`、deploy / reload surface `6`,owner response、live evidence、reload owner、receiver owner、route smoke、runtime gate 與 action button 仍全部為 `0`,不代表 Prometheus reload、Alertmanager reload、Grafana import、SigNoz apply、Sentry deploy、Telegram send、live alert fire 或 alert chain smoke 已授權。 59. 12 個 Public Gateway Preflight repo-only gates,顯示 Nginx public gateway reload / route change 前必備的 owner、live conf、rendered diff、`nginx -t`、public / admin / WebSocket route smoke、ACME / TLS owner check、maintenance window 與 rollback owner;source config `3`、route impact `14`、repo-only ready gate `2`,owner acceptance、live conf、rendered diff、`nginx -t` evidence、route smoke、runtime gate 與 action button 仍全部為 `0`,不代表 SSH、live conf read、Nginx reload、route change、DNS / TLS probe 或 certbot renew 已授權。 diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index 8629723af..9a01b3cf0 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -3,16 +3,22 @@ | 項目 | 內容 | |------|------| | 日期 | 2026-06-15 | -| 狀態 | IwoooS 64% 只讀治理推進中;K8s / ArgoCD GitOps 變更證據驗收只讀帳本已本地完成;端口 / 防火牆變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 | +| 狀態 | IwoooS 64% 只讀治理推進中;CD / Runner / Secret 注入變更證據驗收只讀帳本已本地完成;端口 / 防火牆變更證據驗收與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 | | 本階段完成 | 資安供應鏈 contract manifest + Source Control Approval Board + Draft Reconcile Plan + Ref Detail Diff + Ref Truth Classification + Source Control Ref Truth Owner Response 收件包 + GitHub Primary Readiness Gate + GitHub Primary Rollback ADR + GitHub Target Owner Decision Response 收件包 + Gitea 認證清冊匯出請求 + Gitea 認證清冊匯入驗收契約 + Gitea 清冊覆蓋 Owner Attestation + Gitea Owner Attestation Approval Lane 對齊 + Gitea Owner Attestation Response 收件包 + Workflow / Secret Name Inventory + Workflow / Secret Name Local Evidence + Workflow / Secret Name Redacted Export Request + Workflow / Secret Name Owner Response 收件包 + Source Control Owner Response Validation Rollup + Kali 112 live integration status + Security Finding contract + Kali scan scope approval package + Security Approval Queue + S3 人工批准 Gate + S3 人工決策紀錄 + S3 人工審查封包 + S3 人工決策狀態轉移 + S3 後續 runtime gate 準備契約 + 鏡像 readiness index + 鏡像接收計畫 + 鏡像事件信封 + 鏡像路由矩陣 + 鏡像驗收契約 + 鏡像隔離契約 + 鏡像 dry-run 報告契約 + 鏡像狀態彙整契約 + IwoooS 前端態勢入口 + IwoooS posture projection contract + IwoooS 既有前端資安頁面整合 + IwoooS 覆蓋與邊界矩陣 + IwoooS 只讀資安處理旅程 + IwoooS owner evidence readiness board + IwoooS host coverage view + IwoooS host action gate matrix + IwoooS host evidence readiness board + IwoooS host evidence collection order + IwoooS host evidence intake preflight + IwoooS host evidence review outcome lanes + IwoooS host evidence review handoff packets + IwoooS host evidence reviewer checklist + IwoooS host evidence reviewer outcome lanes + IwoooS host owner decision candidate packets + IwoooS host owner decision review checklist + IwoooS host owner decision review outcome lanes + IwoooS host owner decision record draft packets + IwoooS host owner decision record draft review checklist + IwoooS host owner decision record draft review outcome lanes + IwoooS host owner decision record write-up packets + IwoooS host owner decision record write-up review checklist + IwoooS host owner decision record write-up review outcome lanes + IwoooS host owner decision record formal candidate packets + IwoooS host owner decision record formal candidate review checklist + IwoooS host owner decision record formal candidate review outcome lanes + IwoooS host owner decision record formal record queue packets + IwoooS host owner decision record formal record queue review checklist + IwoooS host owner decision record formal record queue review outcome lanes + IwoooS host owner decision record human handoff readiness packets + IwoooS host owner decision record human handoff readiness review checklist + IwoooS host owner decision record human handoff readiness review outcome lanes + IwoooS host owner decision record human record owner review candidate packets + IwoooS host owner decision record human record owner review candidate checklist + IwoooS host owner decision record human record owner review candidate outcome lanes + IwoooS host owner decision record human record owner review preparation packets + IwoooS host owner decision record human record owner review preparation checklist + IwoooS progress acceleration lanes + IwoooS owner response next-action focus + IwoooS S4.9 owner response preflight + IwoooS S4.9 owner response request templates + IwoooS progress hold movement gates + IwoooS AwoooP read-only landing readiness + IwoooS AwoooP cross-session handoff packets + AwoooP 首頁 IwoooS 資安鏡像候選 + AwoooP 工作鏈路 IwoooS 資安鏡像候選 + AwoooP 審批佇列 IwoooS owner response 只讀焦點 | | 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP 執行監控 IwoooS 執行狀態只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 + IwoooS GitHub 主要來源就緒度只讀狀態板 + AwoooP 工作鏈路 GitHub 主要來源就緒度只讀工作項 + AwoooP 合約儀表板 GitHub 主要來源就緒度合約只讀候選 + AwoooP 審批佇列 GitHub 主要來源就緒度審批邊界 + AwoooP 首頁 GitHub 主要來源就緒度只讀摘要 + AwoooP 租戶管理 GitHub 主要來源就緒度租戶範圍 + AwoooP 執行監控 GitHub 主要來源就緒度執行邊界 + IwoooS / AwoooP 資安可視區塊繁體中文呈現防護檢查 + AwoooP 執行詳情 / 審批詳情繁體中文呈現防護檢查 + AwoooP 首頁負責人回覆驗收總覽 + AwoooP 工作鏈路負責人回覆驗收只讀工作項 + AwoooP 合約儀表板負責人回覆驗收契約只讀候選 + AwoooP 審批佇列負責人回覆驗收只讀審查邊界 + AwoooP 租戶管理負責人回覆驗收租戶範圍 + AwoooP 執行監控負責人回覆驗收執行邊界 + AwoooP 執行詳情負責人回覆驗收詳情邊界 + AwoooP 審批決策負責人回覆驗收審批邊界 + IwoooS AwoooP 資安入口覆蓋狀態板 + IwoooS 階段式資安收斂節奏圖 + IwoooS 下一步人工收件作戰板 + IwoooS 人工回覆安全驗收閘道 + IwoooS 人工回覆審查結果分流 + IwoooS 人工決策準備佇列 + IwoooS 人工決策紀錄草稿防誤用 + IwoooS 人工決策正式紀錄負責人指派確認準備包 + IwoooS 人工決策正式紀錄負責人指派確認清單 + IwoooS 人工決策正式紀錄負責人指派確認結果分流 + IwoooS 人工決策正式紀錄負責人指派決策準備包 + IwoooS 人工決策正式紀錄負責人指派決策檢查清單 + IwoooS S4.9 負責人回覆封套欄位 + IwoooS S4.9 負責人回覆封套送件前檢查 + IwoooS S4.9 負責人回覆封套送件前結果分流 + IwoooS S4.9 負責人回覆送件請求草稿 + IwoooS S4.9 負責人回覆送件鏈路摘要 + IwoooS 低摩擦分階段收斂主控 + IwoooS 低摩擦下一步行動邊界 + IwoooS 64% 進度移動訊號驗收條 + IwoooS 第一個進度解鎖路徑 + IwoooS 第一解鎖證據包 + IwoooS 第一解鎖證據包預檢分流 + IwoooS 第一解鎖證據包補件路徑 + IwoooS 第一解鎖證據包補件送審前檢查 + IwoooS 第一解鎖證據包補件送審結果分流 + IwoooS 第一解鎖證據包 reviewer 指派準備包 + IwoooS 第一解鎖證據包 reviewer 指派前檢查 + IwoooS 第一解鎖證據包 reviewer 指派前檢查結果分流 + IwoooS 正式只讀 landing 與 Kali 112 只讀證據進度重估 | | 本階段追加補充 | IwoooS 目前具體工作地圖 + IwoooS 目前具體交付清單 + IwoooS 目前阻塞與解除條件 + IwoooS 三軸進度與全產品套用範圍 + IwoooS 全產品分階段套用台帳 + IwoooS 全產品 rollout 波次驗收門檻 + IwoooS 全產品 rollout 驗收結果分流 + IwoooS 全產品證據接線地圖 + IwoooS 全產品證據接線預檢 + IwoooS 全產品證據接線預檢結果分流 + IwoooS 全產品預檢補件回收台帳 + IwoooS 全產品補件重試門檻 + IwoooS 全產品重試結果分流 + IwoooS 全產品人工審查候選準備 + IwoooS 全產品人工審查候選預檢 + IwoooS 全產品人工審查候選預檢結果分流 + IwoooS 全產品人工審查候選預檢補件回收台帳 + IwoooS 全產品人工審查候選預檢補件重試門檻 + IwoooS 全產品只讀套用快照 + P2-145 owner response acceptance gate 正式驗證完成 | -| P0 追加 | IwoooS P0 配置控管優先序前台正式驗證完成;Nginx public gateway、DNS / TLS / certbot、K8s / ArgoCD / production manifests、Workflow / runner / secret metadata、Public / admin / API runtime config、agent-bounty runtime / treasury 六類先列為即時風險配置;高價值配置 Gate 已補上 `k8s/nginx/**`、`scripts/ops/**/*cert*`、`scripts/ops/**/*tls*`,sample 從 `matched=0 / C0=0` 收斂到 `matched=3 / C0=2`;Gate 預設工作樹 preflight 已可讀取 staged / unstaged / untracked,本地 smoke 對臨時 `k8s/nginx/*` 檔命中 C0;Owner Packet snapshot 已同步為 `packets=3 / c0=2`,Coverage snapshot 已同步最新 patterns;IwoooS / AwoooP 前台 Owner Packet 摘要已正式驗證 `packet=3 / c0=2`,feature commit `e999c16b`、deploy marker `16c6b983`、Gitea code-review `2973` / CD `2972` success;IwoooS posture projection snapshot / schema / guard 已同步 `packet=3 / c0=2`,不再保留舊 `1 / 0` 口徑;高價值配置 Owner Packet 收件預檢已新增 `checks=9 / lanes=5 / required_fields=27 / blocked_requests=16`;高價值配置 Owner Request 草稿包已新增 `drafts=3 / handoff_fields=11 / forbidden_payloads=12 / sent=0`;Public Gateway live conf 匯出請求包已新增 `requests=3 / c0=2 / redaction_rules=8 / received=0`;Public Gateway redacted export 收件預檢已新增 `candidates=3 / c0=2 / checks=10 / rejection_guards=12 / received=0 / accepted=0`;Public Gateway rendered diff / nginx gate 草稿已新增 `candidates=3 / c0=2 / stages=7 / blocked=14 / rendered_diff=0 / runtime=0`;Public Gateway owner response acceptance 只讀帳本已新增 `candidates=3 / c0=2 / fields=12 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;DNS / TLS / certbot Owner Confirmation Request 已新增 `requests=4 / c0=4 / fields=9 / questions=5 / guards=12 / received=0 / accepted=0`;K8s / ArgoCD manifest repo-only 清冊已新增 `files=49 / c0=36 / yaml=45 / kinds=20 / blocked=13 / runtime=0`;K8s / ArgoCD Owner Request Draft 已新增 `drafts=4 / c0=3 / fields=11 / sent=0 / runtime=0`;K8s / ArgoCD owner response acceptance 只讀帳本已新增 `candidates=4 / c0=3 / fields=11 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;K8s / ArgoCD GitOps 變更證據驗收已新增 `candidates=4 / c0=3 / write_capable=4 / evidence_fields=18 / checks=18 / lanes=8 / blocked=28 / accepted=0 / runtime=0`;Backup / Restore / Escrow owner response acceptance 只讀帳本已新增 `candidates=38 / write_capable=27 / fields=14 / checks=13 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;SSH / Firewall / Network Access owner response acceptance 只讀帳本已新增 `candidates=16 / write_capable=6 / fields=13 / checks=15 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;端口 / 防火牆變更證據驗收只讀帳本已新增 `candidates=14 / write_capable=6 / policy_or_exposure=5 / evidence_fields=16 / checks=16 / lanes=8 / blocked=24 / accepted=0 / runtime=0`;owner response / live evidence / runtime gate / action buttons 仍全部為 0 | +| P0 追加 | IwoooS P0 配置控管優先序前台正式驗證完成;Nginx public gateway、DNS / TLS / certbot、K8s / ArgoCD / production manifests、Workflow / runner / secret metadata、Public / admin / API runtime config、agent-bounty runtime / treasury 六類先列為即時風險配置;高價值配置 Gate 已補上 `k8s/nginx/**`、`scripts/ops/**/*cert*`、`scripts/ops/**/*tls*`,sample 從 `matched=0 / C0=0` 收斂到 `matched=3 / C0=2`;Gate 預設工作樹 preflight 已可讀取 staged / unstaged / untracked,本地 smoke 對臨時 `k8s/nginx/*` 檔命中 C0;Owner Packet snapshot 已同步為 `packets=3 / c0=2`,Coverage snapshot 已同步最新 patterns;IwoooS / AwoooP 前台 Owner Packet 摘要已正式驗證 `packet=3 / c0=2`,feature commit `e999c16b`、deploy marker `16c6b983`、Gitea code-review `2973` / CD `2972` success;IwoooS posture projection snapshot / schema / guard 已同步 `packet=3 / c0=2`,不再保留舊 `1 / 0` 口徑;高價值配置 Owner Packet 收件預檢已新增 `checks=9 / lanes=5 / required_fields=27 / blocked_requests=16`;高價值配置 Owner Request 草稿包已新增 `drafts=3 / handoff_fields=11 / forbidden_payloads=12 / sent=0`;Public Gateway live conf 匯出請求包已新增 `requests=3 / c0=2 / redaction_rules=8 / received=0`;Public Gateway redacted export 收件預檢已新增 `candidates=3 / c0=2 / checks=10 / rejection_guards=12 / received=0 / accepted=0`;Public Gateway rendered diff / nginx gate 草稿已新增 `candidates=3 / c0=2 / stages=7 / blocked=14 / rendered_diff=0 / runtime=0`;Public Gateway owner response acceptance 只讀帳本已新增 `candidates=3 / c0=2 / fields=12 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;DNS / TLS / certbot Owner Confirmation Request 已新增 `requests=4 / c0=4 / fields=9 / questions=5 / guards=12 / received=0 / accepted=0`;K8s / ArgoCD manifest repo-only 清冊已新增 `files=49 / c0=36 / yaml=45 / kinds=20 / blocked=13 / runtime=0`;K8s / ArgoCD Owner Request Draft 已新增 `drafts=4 / c0=3 / fields=11 / sent=0 / runtime=0`;K8s / ArgoCD owner response acceptance 只讀帳本已新增 `candidates=4 / c0=3 / fields=11 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;K8s / ArgoCD GitOps 變更證據驗收已新增 `candidates=4 / c0=3 / write_capable=4 / evidence_fields=18 / checks=18 / lanes=8 / blocked=28 / accepted=0 / runtime=0`;CD / Runner / Secret 注入變更證據驗收已新增 `candidates=5 / c0=4 / write_capable=5 / workflow_files=33 / secret_names=42 / runner_labels=5 / evidence_fields=19 / checks=19 / lanes=8 / blocked=32 / accepted=0 / runtime=0`;Backup / Restore / Escrow owner response acceptance 只讀帳本已新增 `candidates=38 / write_capable=27 / fields=14 / checks=13 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;SSH / Firewall / Network Access owner response acceptance 只讀帳本已新增 `candidates=16 / write_capable=6 / fields=13 / checks=15 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;端口 / 防火牆變更證據驗收只讀帳本已新增 `candidates=14 / write_capable=6 / policy_or_exposure=5 / evidence_fields=16 / checks=16 / lanes=8 / blocked=24 / accepted=0 / runtime=0`;owner response / live evidence / runtime gate / action buttons 仍全部為 0 | | P0 agent-bounty 追加 | agent-bounty-protocol Owner Request Draft 已新增 `drafts=11 / control=4 / surface=7 / write_capable=8 / treasury=4 / mcp_a2a=5 / fields=22 / forbidden_inputs=25 / blocked=28 / sent=0 / runtime=0`;這是 repo / refs、deployment、data classification、MCP / A2A、cron / daemon、admin / treasury、webhook / traffic 的人工送件前草稿,不是 owner response、repo push、refs sync、workflow 修改、secret 收集、deploy、compose restart、DB migration、claim / submit、payout / withdrawal、cron / daemon、external send、host write 或 runtime gate | | P1 追加 | Docker / systemd / Host Service Owner Request Draft 已新增 `drafts=9 / write_capable=3 / fields=12 / blocked=14 / sent=0 / runtime=0`;SSH / Firewall / Network Access Owner Request Draft 已新增 `drafts=16 / write_capable=6 / fields=13 / blocked=16 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Request Draft 已新增 `drafts=38 / write_capable=27 / fields=14 / blocked=18 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Response Acceptance 已新增 `candidates=38 / write_capable=27 / reviewer_checks=13 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;Monitoring / Alerting / Observability Owner Request Draft 已新增 `drafts=60 / write_capable=11 / fields=14 / blocked=24 / sent=0 / runtime=0`;上述全部仍是人工送件前草稿或只讀 acceptance 帳本,不是 owner response、live evidence、reload、restart、backup、restore、Telegram send、alert smoke、host write 或 runtime gate | | 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary | | P0 主控板 | `docs/workplans/2026-06-04-iwooos-security-governance-p0.md` | +## 0.00aaaa 2026-06-15 CD / Runner / Secret 注入變更證據驗收 + +本輪把 CD pipeline、程式碼審查、部署通知、執行器證明與 repository secret name parity / injection owner 從 workflow / secret name owner response 再補一層變更證據驗收只讀帳本:`cd_runner_secret_injection_change_evidence_acceptance_v1` 固定 `candidates=5`、`c0=4`、`c1=1`、`write_capable=5`、`workflow_files=33`、`referenced_secret_names=42`、`runner_labels=5`、`required_evidence_fields=19`、`reviewer_checks=19`、`outcome_lanes=8`、`blocked_actions=32`,並讓 `secret_metadata` 只讀治理成熟度 `66% -> 68%`、`gitea_workflow_runner_source_control` 只讀治理成熟度 `70% -> 72%`,高價值配置平均只讀成熟度仍維持 `68%`。這是 metadata-only 收件驗收,不是 workflow diff accepted、runner attestation accepted、secret parity accepted、secret injection route accepted、deploy marker readback accepted、guard result accepted、post-check accepted、runtime approval package、workflow modification、runner change、repo secret change、secret rotation、Gitea action dispatch、production deploy 或 runtime gate。 + +同步邊界: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.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-change-evidence-acceptance.snapshot.json b/docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json new file mode 100644 index 000000000..c20b51ef6 --- /dev/null +++ b/docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json @@ -0,0 +1,1228 @@ +{ + "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", + "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", + "add_action_button" + ], + "change_evidence_candidates": [ + { + "action_buttons_allowed": false, + "affected_scope": "main push CD、Harbor build / push、K8s secret injection、ArgoCD deploy marker、post-deploy checks", + "argocd_sync_authorized": false, + "blast_radius": "pending_change_evidence", + "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", + "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", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_evidence_accepted": false, + "change_evidence_candidate_id": "cd_runner_secret_injection:cd_pipeline_deploy_marker_and_k8s_secret_injection", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_refs", + "control_tier", + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "codeowners_change_authorized": false, + "control_tier": "C0", + "deploy_key_change_authorized": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "guard_result_accepted": false, + "guard_result_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_review_ref": null, + "maintenance_window": "pending_change_evidence", + "not_approval": true, + "notification_route_owner_ref": null, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_sensitive_payload", + "reject_unredacted_or_runtime_claim", + "request_supplement", + "ready_for_reviewer_acceptance", + "ready_for_runtime_approval_package", + "waiting_maintenance_window", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "proposed_workflow_or_config_change_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_evidence_fields": [ + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "change_ref_present", + "workflow_diff_ref_only", + "gitea_actions_run_readback_ref_shape", + "deploy_marker_not_runtime_approval", + "runner_owner_attestation_present", + "hosted_minutes_risk_review_present", + "secret_name_parity_ref_only", + "no_secret_value_or_hash", + "secret_injection_path_called_out", + "step_env_with_secret_guard_result_present", + "telegram_route_owner_present", + "deploy_key_and_webhook_material_absent", + "branch_protection_or_required_checks_impact_called_out", + "blast_radius_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "no_execution_claim", + "cross_project_sync_noted" + ], + "reviewer_outcome": "waiting_change_evidence", + "risk": "HIGH", + "rollback_owner": "pending_change_evidence", + "rollback_plan_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_ref": null, + "runner_change_authorized": false, + "runtime_approval_package_ready": false, + "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_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_refs": [ + ".gitea/workflows/cd.yaml", + "scripts/ci/check-gitea-step-env-secrets.js" + ], + "status": "waiting_change_evidence", + "step_env_secret_allowed": false, + "title": "CD pipeline / deploy marker / K8s secret 注入路徑", + "webhook_modification_authorized": false, + "workflow_diff_accepted": false, + "workflow_diff_ref": null, + "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, + "affected_scope": "Code Review、Telegram / AWOOI API notification、deterministic review report、Gitea Actions status", + "argocd_sync_authorized": false, + "blast_radius": "pending_change_evidence", + "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", + "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", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_evidence_accepted": false, + "change_evidence_candidate_id": "cd_runner_secret_injection:code_review_pipeline_secret_and_notification_surface", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_refs", + "control_tier", + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "codeowners_change_authorized": false, + "control_tier": "C0", + "deploy_key_change_authorized": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "guard_result_accepted": false, + "guard_result_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_review_ref": null, + "maintenance_window": "pending_change_evidence", + "not_approval": true, + "notification_route_owner_ref": null, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_sensitive_payload", + "reject_unredacted_or_runtime_claim", + "request_supplement", + "ready_for_reviewer_acceptance", + "ready_for_runtime_approval_package", + "waiting_maintenance_window", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "proposed_workflow_or_config_change_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_evidence_fields": [ + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "change_ref_present", + "workflow_diff_ref_only", + "gitea_actions_run_readback_ref_shape", + "deploy_marker_not_runtime_approval", + "runner_owner_attestation_present", + "hosted_minutes_risk_review_present", + "secret_name_parity_ref_only", + "no_secret_value_or_hash", + "secret_injection_path_called_out", + "step_env_with_secret_guard_result_present", + "telegram_route_owner_present", + "deploy_key_and_webhook_material_absent", + "branch_protection_or_required_checks_impact_called_out", + "blast_radius_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "no_execution_claim", + "cross_project_sync_noted" + ], + "reviewer_outcome": "waiting_change_evidence", + "risk": "HIGH", + "rollback_owner": "pending_change_evidence", + "rollback_plan_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_ref": null, + "runner_change_authorized": false, + "runtime_approval_package_ready": false, + "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_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_refs": [ + ".gitea/workflows/code-review.yaml", + "scripts/ci/check-gitea-step-env-secrets.js" + ], + "status": "waiting_change_evidence", + "step_env_secret_allowed": false, + "title": "Code Review workflow / notification / secret 使用面", + "webhook_modification_authorized": false, + "workflow_diff_accepted": false, + "workflow_diff_ref": null, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [ + "TELEGRAM_BOT_TOKEN" + ], + "write_capable": true + }, + { + "action_buttons_allowed": false, + "affected_scope": "Prometheus / Alertmanager rule deploy、notification route、SRE receipt evidence", + "argocd_sync_authorized": false, + "blast_radius": "pending_change_evidence", + "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", + "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", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_evidence_accepted": false, + "change_evidence_candidate_id": "cd_runner_secret_injection:deploy_alerts_and_monitoring_route", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_refs", + "control_tier", + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "codeowners_change_authorized": false, + "control_tier": "C1", + "deploy_key_change_authorized": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "guard_result_accepted": false, + "guard_result_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_review_ref": null, + "maintenance_window": "pending_change_evidence", + "not_approval": true, + "notification_route_owner_ref": null, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_sensitive_payload", + "reject_unredacted_or_runtime_claim", + "request_supplement", + "ready_for_reviewer_acceptance", + "ready_for_runtime_approval_package", + "waiting_maintenance_window", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "proposed_workflow_or_config_change_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_evidence_fields": [ + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "change_ref_present", + "workflow_diff_ref_only", + "gitea_actions_run_readback_ref_shape", + "deploy_marker_not_runtime_approval", + "runner_owner_attestation_present", + "hosted_minutes_risk_review_present", + "secret_name_parity_ref_only", + "no_secret_value_or_hash", + "secret_injection_path_called_out", + "step_env_with_secret_guard_result_present", + "telegram_route_owner_present", + "deploy_key_and_webhook_material_absent", + "branch_protection_or_required_checks_impact_called_out", + "blast_radius_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "no_execution_claim", + "cross_project_sync_noted" + ], + "reviewer_outcome": "waiting_change_evidence", + "risk": "MEDIUM", + "rollback_owner": "pending_change_evidence", + "rollback_plan_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_ref": null, + "runner_change_authorized": false, + "runtime_approval_package_ready": false, + "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_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_refs": [ + ".gitea/workflows/deploy-alerts.yaml", + "scripts/ops/deploy-alerts.sh" + ], + "status": "waiting_change_evidence", + "step_env_secret_allowed": false, + "title": "Deploy alerts workflow / monitoring notification route", + "webhook_modification_authorized": false, + "workflow_diff_accepted": false, + "workflow_diff_ref": null, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [ + "DEPLOY_SSH_KEY", + "TELEGRAM_BOT_TOKEN" + ], + "write_capable": true + }, + { + "action_buttons_allowed": false, + "affected_scope": "awoooi-host、self-hosted、ubuntu-latest、harbor、k8s runner labels 與 executor owner", + "argocd_sync_authorized": false, + "blast_radius": "pending_change_evidence", + "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", + "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", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_evidence_accepted": false, + "change_evidence_candidate_id": "cd_runner_secret_injection:runner_label_and_executor_attestation", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_refs", + "control_tier", + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "codeowners_change_authorized": false, + "control_tier": "C0", + "deploy_key_change_authorized": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "guard_result_accepted": false, + "guard_result_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_review_ref": null, + "maintenance_window": "pending_change_evidence", + "not_approval": true, + "notification_route_owner_ref": null, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_sensitive_payload", + "reject_unredacted_or_runtime_claim", + "request_supplement", + "ready_for_reviewer_acceptance", + "ready_for_runtime_approval_package", + "waiting_maintenance_window", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "proposed_workflow_or_config_change_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_evidence_fields": [ + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "change_ref_present", + "workflow_diff_ref_only", + "gitea_actions_run_readback_ref_shape", + "deploy_marker_not_runtime_approval", + "runner_owner_attestation_present", + "hosted_minutes_risk_review_present", + "secret_name_parity_ref_only", + "no_secret_value_or_hash", + "secret_injection_path_called_out", + "step_env_with_secret_guard_result_present", + "telegram_route_owner_present", + "deploy_key_and_webhook_material_absent", + "branch_protection_or_required_checks_impact_called_out", + "blast_radius_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "no_execution_claim", + "cross_project_sync_noted" + ], + "reviewer_outcome": "waiting_change_evidence", + "risk": "HIGH", + "rollback_owner": "pending_change_evidence", + "rollback_plan_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_ref": null, + "runner_change_authorized": false, + "runtime_approval_package_ready": false, + "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_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "source_refs": [ + "docs/security/source-control-workflow-secret-name-local-evidence.snapshot.json" + ], + "status": "waiting_change_evidence", + "step_env_secret_allowed": false, + "title": "Runner label / executor / hosted minutes owner attestation", + "webhook_modification_authorized": false, + "workflow_diff_accepted": false, + "workflow_diff_ref": null, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [], + "write_capable": true + }, + { + "action_buttons_allowed": false, + "affected_scope": "9 個 in-scope repos 的 secret name parity、rotation owner、CD / K8s injection owner", + "argocd_sync_authorized": false, + "blast_radius": "pending_change_evidence", + "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", + "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", + "add_action_button" + ], + "branch_protection_change_authorized": false, + "cd_pipeline_run_authorized": false, + "change_evidence_accepted": false, + "change_evidence_candidate_id": "cd_runner_secret_injection:repository_secret_name_parity_and_injection_owner", + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_refs", + "control_tier", + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "change_evidence_quarantined": false, + "change_evidence_received": false, + "change_evidence_rejected": false, + "codeowners_change_authorized": false, + "control_tier": "C0", + "deploy_key_change_authorized": false, + "deploy_marker_readback_accepted": false, + "deploy_marker_readback_ref": null, + "deploy_marker_write_authorized": false, + "disable_gitea_authorized": false, + "force_push_authorized": false, + "gitea_action_dispatch_authorized": false, + "gitea_action_run_ref": null, + "github_hosted_runner_enable_authorized": false, + "github_primary_switch_authorized": false, + "guard_result_accepted": false, + "guard_result_ref": null, + "k8s_secret_injection_authorized": false, + "log_redaction_review_ref": null, + "maintenance_window": "pending_change_evidence", + "not_approval": true, + "notification_route_owner_ref": null, + "outcome_lanes": [ + "waiting_change_evidence", + "quarantine_sensitive_payload", + "reject_unredacted_or_runtime_claim", + "request_supplement", + "ready_for_reviewer_acceptance", + "ready_for_runtime_approval_package", + "waiting_maintenance_window", + "waiting_runtime_gate" + ], + "partial_token_collection_allowed": false, + "postcheck_evidence_accepted": false, + "postcheck_evidence_ref": null, + "production_deploy_authorized": false, + "proposed_workflow_or_config_change_ref": null, + "redacted_evidence_refs": [], + "refs_sync_authorized": false, + "repo_secret_change_authorized": false, + "required_evidence_fields": [ + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "requires_runtime_approval_package": true, + "reviewer_checks": [ + "change_ref_present", + "workflow_diff_ref_only", + "gitea_actions_run_readback_ref_shape", + "deploy_marker_not_runtime_approval", + "runner_owner_attestation_present", + "hosted_minutes_risk_review_present", + "secret_name_parity_ref_only", + "no_secret_value_or_hash", + "secret_injection_path_called_out", + "step_env_with_secret_guard_result_present", + "telegram_route_owner_present", + "deploy_key_and_webhook_material_absent", + "branch_protection_or_required_checks_impact_called_out", + "blast_radius_present", + "maintenance_window_present", + "rollback_owner_present", + "postcheck_evidence_present", + "no_execution_claim", + "cross_project_sync_noted" + ], + "reviewer_outcome": "waiting_change_evidence", + "risk": "HIGH", + "rollback_owner": "pending_change_evidence", + "rollback_plan_ref": null, + "runner_attestation_accepted": false, + "runner_attestation_ref": null, + "runner_change_authorized": false, + "runtime_approval_package_ready": false, + "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_ref": null, + "secret_name_parity_accepted": false, + "secret_name_parity_ref": null, + "secret_rotation_authorized": false, + "secret_store_read_authorized": false, + "secret_value_collection_allowed": false, + "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_change_evidence", + "step_env_secret_allowed": false, + "title": "Repository secret name parity / injection owner", + "webhook_modification_authorized": false, + "workflow_diff_accepted": false, + "workflow_diff_ref": null, + "workflow_modification_authorized": false, + "workflow_secret_name_refs": [], + "write_capable": true + } + ], + "change_evidence_fields": [ + "change_evidence_candidate_id", + "source_refs", + "control_tier", + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "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_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, + "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, + "step_env_secret_allowed": false, + "webhook_modification_authorized": false, + "workflow_modification_authorized": false + }, + "generated_at": "2026-06-15T03:20:00+08:00", + "git_commit": "a8ade565", + "mode": "metadata_only_no_secret_value_no_workflow_change", + "operator_interpretation": [ + "此帳本只描述 CD / runner / secret injection 變更證據如何收件與拒收,不是 workflow 變更批准。", + "secret 只能以名稱、scope、present-absent、owner 與 redacted evidence ref 呈現,不得保存 value、hash 或 partial token。", + "deploy marker、Gitea Actions success、AwoooP approval 與 UI 可見狀態都不能被解讀成 runtime gate 已開。", + "未來若要修改 workflow、runner、secret injection、webhook、deploy key 或 branch protection,仍需獨立 owner response、維護窗口、rollback owner 與 runtime approval package。" + ], + "outcome_lanes": [ + { + "lane_id": "waiting_change_evidence", + "meaning": "尚未收到 CD / runner / secret injection 變更證據;所有 accepted / runtime count 維持 0。" + }, + { + "lane_id": "quarantine_sensitive_payload", + "meaning": "收到 secret value、hash、runner token、webhook secret、private key 或未脫敏截圖時只能隔離。" + }, + { + "lane_id": "reject_unredacted_or_runtime_claim", + "meaning": "出現未脫敏 payload 或把 evidence 誤當執行批准時直接拒收。" + }, + { + "lane_id": "request_supplement", + "meaning": "缺 workflow diff、runner owner、secret parity、guard result、rollback 或 post-check 時要求補件。" + }, + { + "lane_id": "ready_for_reviewer_acceptance", + "meaning": "metadata 合格後只能進 reviewer acceptance,不得自動修改 workflow / secret / runner。" + }, + { + "lane_id": "ready_for_runtime_approval_package", + "meaning": "reviewer 接受後也只能形成 runtime approval package,不自動打開 gate。" + }, + { + "lane_id": "waiting_maintenance_window", + "meaning": "若未來要改 workflow / runner / secret injection,仍需獨立維護窗口。" + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "change evidence accepted 後 runtime gate 仍等待獨立人工批准。" + } + ], + "required_evidence_fields": [ + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval" + ], + "reviewer_checks": [ + { + "check_id": "change_ref_present", + "instruction": "必須有 proposed workflow / config / policy change ref,不能只寫口頭同意。" + }, + { + "check_id": "workflow_diff_ref_only", + "instruction": "只能收 workflow diff ref 或 committed patch ref,不保存未脫敏 workflow payload。" + }, + { + "check_id": "gitea_actions_run_readback_ref_shape", + "instruction": "Gitea Actions run readback 只能是 run id / job id / status ref,不保存 token 或 cookie。" + }, + { + "check_id": "deploy_marker_not_runtime_approval", + "instruction": "deploy marker 只能當部署證據,不代表資安 runtime approval。" + }, + { + "check_id": "runner_owner_attestation_present", + "instruction": "runner label、executor、host alias、owner 與維護窗口必須可追溯。" + }, + { + "check_id": "hosted_minutes_risk_review_present", + "instruction": "涉及 hosted runner 時必須標出額度與供應鏈風險,不得自動啟用。" + }, + { + "check_id": "secret_name_parity_ref_only", + "instruction": "secret parity 只能保存 secret name / scope / present-absent / owner metadata。" + }, + { + "check_id": "no_secret_value_or_hash", + "instruction": "不得出現 secret value、hash、masked token、partial token 或 credential derivative。" + }, + { + "check_id": "secret_injection_path_called_out", + "instruction": "涉及 CD / K8s secret injection 時必須標出 injection path 與 owner,不得讀 value。" + }, + { + "check_id": "step_env_with_secret_guard_result_present", + "instruction": "必須附 `check-gitea-step-env-secrets` 或等價 guard result ref。" + }, + { + "check_id": "telegram_route_owner_present", + "instruction": "涉及通知時必須確認 SRE route owner,不得新增 legacy Telegram route。" + }, + { + "check_id": "deploy_key_and_webhook_material_absent", + "instruction": "不得保存 webhook secret、deploy key private material、runner token 或 write token。" + }, + { + "check_id": "branch_protection_or_required_checks_impact_called_out", + "instruction": "影響 required checks / CODEOWNERS / branch protection 時必須標出影響。" + }, + { + "check_id": "blast_radius_present", + "instruction": "必須列出 repo、workflow、runner、secret metadata、notification、deploy path 影響範圍。" + }, + { + "check_id": "maintenance_window_present", + "instruction": "任何 future workflow / runner / secret injection 變更都必須另有維護窗口。" + }, + { + "check_id": "rollback_owner_present", + "instruction": "必須有 rollback owner 與回復方式;不能只寫『可回復』。" + }, + { + "check_id": "postcheck_evidence_present", + "instruction": "需有 post-check evidence ref,例如 guard result、run status、route smoke 或 notification receipt。" + }, + { + "check_id": "no_execution_claim", + "instruction": "不能把本帳本、owner response、CD success 或 AwoooP approval 當執行批准。" + }, + { + "check_id": "cross_project_sync_noted", + "instruction": "若影響 AwoooP、IwoooS、agent-bounty、監控或公開服務,需有跨專案同步 ref。" + } + ], + "schema_version": "cd_runner_secret_injection_change_evidence_acceptance_v1", + "source_paths": [ + "docs/security/source-control-workflow-secret-name-local-evidence.snapshot.json", + "docs/security/source-control-workflow-secret-name-export-request.snapshot.json", + "docs/security/source-control-workflow-secret-name-owner-response.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": "change_evidence_acceptance_ledger_ready_no_runtime_action", + "summary": { + "action_button_count": 0, + "blocked_action_count": 32, + "c0_change_evidence_candidate_count": 4, + "c1_change_evidence_candidate_count": 1, + "change_evidence_accepted_count": 0, + "change_evidence_candidate_count": 5, + "change_evidence_received_count": 0, + "deploy_marker_readback_accepted_count": 0, + "export_lane_count": 5, + "export_request_count": 9, + "gitea_workflow_file_count": 12, + "gitea_workflow_runner_coverage_percent_after_acceptance": 72, + "gitea_workflow_runner_coverage_percent_before_acceptance": 70, + "github_workflow_file_count": 21, + "guard_result_accepted_count": 0, + "local_referenced_secret_name_count": 42, + "local_workflow_file_count": 33, + "outcome_lane_count": 8, + "owner_response_accepted_count": 0, + "owner_response_received_count": 0, + "owner_response_template_count": 5, + "postcheck_evidence_accepted_count": 0, + "required_evidence_field_count": 19, + "reviewer_check_count": 19, + "runner_attestation_accepted_count": 0, + "runner_label_count": 5, + "runtime_approval_package_ready_count": 0, + "runtime_gate_count": 0, + "secret_injection_route_accepted_count": 0, + "secret_metadata_coverage_percent_after_acceptance": 68, + "secret_metadata_coverage_percent_before_acceptance": 66, + "secret_name_parity_accepted_count": 0, + "workflow_diff_accepted_count": 0, + "write_capable_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 4bce594a8..24f92b8a2 100644 --- a/docs/security/high-value-config-control-coverage.snapshot.json +++ b/docs/security/high-value-config-control-coverage.snapshot.json @@ -131,16 +131,20 @@ "action_buttons_allowed": false, "category_id": "secret_metadata", "control_tier": "C0", - "coverage_percent": 66, - "coverage_status": "metadata_policy_ready", - "current_gap": "只允許 secret name / metadata;仍缺 owner response 與 parity acceptance。", + "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。", "evidence_refs": [ "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", "docs/security/source-control-workflow-secret-name-inventory.snapshot.json", + "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-OWNER-RESPONSE.md", + "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/SECRETS_REFERENCE.md" ], "label": "Secret metadata / injection / redaction", - "next_owner_action": "只回覆 secret name owner、rotation owner、injection owner 與 redacted evidence refs。", + "next_owner_action": "補 secret name parity ref、injection route owner、rotation owner、guard result ref、rollback owner、post-check evidence 與 redacted evidence refs。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -169,16 +173,18 @@ "action_buttons_allowed": false, "category_id": "gitea_workflow_runner_source_control", "control_tier": "C0", - "coverage_percent": 70, - "coverage_status": "metadata_inventory_ready", - "current_gap": "workflow / runner / deploy key / webhook / branch protection 仍待 owner response;不得改 workflow。", + "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。", "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/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md" ], "label": "Gitea workflow / runner / deploy key / webhook / branch protection", - "next_owner_action": "補 runner label、webhook、deploy key、branch protection 與 workflow parity owner metadata。", + "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。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -601,8 +607,8 @@ "websocket_route_change_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-06-15T02:06:00+08:00", - "git_commit": "26e5f1d0", + "generated_at": "2026-06-15T03:20:00+08:00", + "git_commit": "a8ade565", "lowest_coverage_categories": [ { "category_id": "docker_compose_systemd_host_config", @@ -663,7 +669,7 @@ "c3_category_count": 1, "category_count": 14, "lowest_coverage_category_count": 4, - "needs_live_evidence_count": 6, + "needs_live_evidence_count": 8, "owner_response_accepted_count": 0, "owner_response_received_count": 0, "owner_response_required_count": 14, diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json index 53d4007e8..b206b1650 100644 --- a/docs/security/iwooos-posture-projection.snapshot.json +++ b/docs/security/iwooos-posture-projection.snapshot.json @@ -8415,7 +8415,9 @@ "apps/web/src/app/[locale]/code-review/page.tsx", "apps/web/src/components/command-palette/CommandPalette.tsx", "docs/security/K8S-ARGOCD-CHANGE-EVIDENCE-ACCEPTANCE.md", - "docs/security/k8s-argocd-change-evidence-acceptance.snapshot.json" + "docs/security/k8s-argocd-change-evidence-acceptance.snapshot.json", + "docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md", + "docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json" ], "status": "draft", "summary": { @@ -8471,6 +8473,39 @@ "backup_restore_escrow_inventory_velero_surface_count": 5, "backup_restore_escrow_inventory_write_capable_surface_count": 27, "block_candidate_count": 1, + "cd_runner_secret_injection_change_evidence_acceptance_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_action_button_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_blocked_action_count": 32, + "cd_runner_secret_injection_change_evidence_acceptance_c0_candidate_count": 4, + "cd_runner_secret_injection_change_evidence_acceptance_c1_candidate_count": 1, + "cd_runner_secret_injection_change_evidence_acceptance_candidate_count": 5, + "cd_runner_secret_injection_change_evidence_acceptance_deploy_marker_readback_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_export_lane_count": 5, + "cd_runner_secret_injection_change_evidence_acceptance_export_request_count": 9, + "cd_runner_secret_injection_change_evidence_acceptance_first_layer": true, + "cd_runner_secret_injection_change_evidence_acceptance_gitea_workflow_file_count": 12, + "cd_runner_secret_injection_change_evidence_acceptance_gitea_workflow_runner_coverage_percent_after_acceptance": 72, + "cd_runner_secret_injection_change_evidence_acceptance_gitea_workflow_runner_coverage_percent_before_acceptance": 70, + "cd_runner_secret_injection_change_evidence_acceptance_github_workflow_file_count": 21, + "cd_runner_secret_injection_change_evidence_acceptance_guard_result_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_local_referenced_secret_name_count": 42, + "cd_runner_secret_injection_change_evidence_acceptance_local_workflow_file_count": 33, + "cd_runner_secret_injection_change_evidence_acceptance_outcome_lane_count": 8, + "cd_runner_secret_injection_change_evidence_acceptance_owner_response_template_count": 5, + "cd_runner_secret_injection_change_evidence_acceptance_postcheck_evidence_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_received_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_required_evidence_field_count": 19, + "cd_runner_secret_injection_change_evidence_acceptance_reviewer_check_count": 19, + "cd_runner_secret_injection_change_evidence_acceptance_runner_attestation_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_runner_label_count": 5, + "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_change_evidence_acceptance_secret_injection_route_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_secret_metadata_coverage_percent_after_acceptance": 68, + "cd_runner_secret_injection_change_evidence_acceptance_secret_metadata_coverage_percent_before_acceptance": 66, + "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, "command_map_above_first_progress_unlock_path": true, "command_map_default_mode": "unlock", "command_map_default_visible": false, @@ -8581,7 +8616,7 @@ "high_value_config_control_coverage_first_layer": true, "high_value_config_control_coverage_item_count": 4, "high_value_config_control_coverage_lowest_category_count": 4, - "high_value_config_control_coverage_needs_live_evidence_count": 6, + "high_value_config_control_coverage_needs_live_evidence_count": 8, "high_value_config_control_coverage_owner_response_accepted_count": 0, "high_value_config_control_coverage_owner_response_received_count": 0, "high_value_config_control_coverage_owner_response_required_count": 14, diff --git a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md index 0ac1de15b..1a29d5d1e 100644 --- a/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md +++ b/docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md @@ -4902,6 +4902,18 @@ Trigger commit `f5cd37b7` 與 deploy marker `0ba92357` 已把 governance UI 的 **裁決:** 這是 K8s / ArgoCD GitOps 變更證據的只讀驗收帳本,不是 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;所有執行仍需獨立人工批准。 +### 2026-06-15 03:20 (台北) — §3.2 / §5 — 新增 CD / Runner / Secret 注入變更證據驗收只讀帳本 — 把 workflow、runner、secret injection 變更前證據固定成 guard artifact + +**觸發**:Gitea workflow、runner label、deploy key、webhook、branch protection、CODEOWNERS、repository secret name 與 CD / K8s secret injection path 都屬於 P0 高價值配置;任何未驗收的 workflow diff、runner attestation、secret parity、deploy marker readback 或 guard result 都不能被誤判成 workflow 修改、runner 啟用、secret rotation、Gitea action dispatch 或 production deploy 授權。 + +**已推進:** +- 新增 `scripts/security/cd-runner-secret-injection-change-evidence-acceptance.py`,讀取 workflow / secret name local evidence、export request 與 owner response snapshot,產生 5 份 CD / runner / secret injection change evidence candidate。 +- 新增 `docs/security/cd-runner-secret-injection-change-evidence-acceptance.snapshot.json`,固定 `change_evidence_candidate_count=5`、`c0_change_evidence_candidate_count=4`、`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`。 +- 新增 `docs/security/CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md`,說明 workflow diff ref、runner attestation ref、secret name parity ref、secret injection route ref、deploy marker readback ref、Gitea run ref、guard result ref、log redaction review ref、notification route owner、blast radius、maintenance window、rollback owner 與 post-check evidence。 +- 高價值配置 coverage、IwoooS 配置控管總清單、P0 主控板、供應鏈進度、posture source paths 與前端 evidence marker 已同步;`secret_metadata` 只讀治理成熟度從 `66%` 推進到 `68%`,`gitea_workflow_runner_source_control` 只讀治理成熟度從 `70%` 推進到 `72%`,但整體平均仍 `68%`,IwoooS headline 仍 `64%`,runtime gate 仍為 `0`。 + +**裁決:** 這是 CD / runner / secret injection 變更證據的只讀驗收帳本,不是 change evidence received / accepted、workflow diff accepted、runner attestation accepted、secret name parity accepted、secret injection route accepted、deploy marker readback accepted、guard result accepted、post-check accepted、runtime approval package、workflow modification、runner change、repo secret change、secret value / hash / partial token collection、secret store read、secret rotation、Gitea action dispatch、production deploy 或 runtime gate;所有執行仍需獨立人工批准。 + ### 2026-06-15 00:36 (台北) — §3.2 / §5 — 新增端口 / 防火牆變更證據驗收只讀帳本 — 把 port close / firewall change 事故證據納入可驗收 guard artifact **觸發**:110 端口關閉曾造成多個服務異常,顯示 SSH / network owner response acceptance 仍不足以追溯「誰改了端口 / 防火牆、為什麼、影響哪些服務、如何回復、如何驗證、是否同步其他專案」。需要補一層端口 / 防火牆變更證據驗收帳本,防止未來把 incident evidence、port list 或 UI 可見性誤判成 firewall / port 操作授權。 diff --git a/docs/workplans/2026-06-04-iwooos-security-governance-p0.md b/docs/workplans/2026-06-04-iwooos-security-governance-p0.md index f9f755068..8df999da0 100644 --- a/docs/workplans/2026-06-04-iwooos-security-governance-p0.md +++ b/docs/workplans/2026-06-04-iwooos-security-governance-p0.md @@ -27,6 +27,7 @@ | 最新 P1 SSH / Firewall / Network Access 配置控管基準 | repo-only inventory 已固定 `surface=16`、`write_capable=6`、`live_evidence_required=16`、成熟度 `48% -> 54%`;本輪新增 owner request draft,固定 `drafts=16`、`owner_fields=13`、`blocked_actions=16`、request sent / received / accepted / live access state / firewall / port change / NetworkPolicy / NodePort / WireGuard / host write / runtime gate 全部 `0` | | 最新 P1 Backup / Restore / Escrow 配置控管基準 | repo-only inventory 已固定 `surface=38`、`write_capable=27`、`live_evidence_required=38`、成熟度 `52% -> 58%`;本輪新增 owner request draft,固定 `drafts=38`、`owner_fields=14`、`blocked_actions=18`、request sent / received / accepted / backup run / restore run / offsite sync / remote delete / escrow marker / retention change / runtime gate 全部 `0` | | 最新 P1 Monitoring / Alerting / Observability 配置控管基準 | repo-only inventory 已固定 `surface=60`、`write_capable=11`、`live_evidence_required=60`、成熟度 `56% -> 62%`;本輪新增 owner request draft,固定 `drafts=60`、`owner_fields=14`、`blocked_actions=24`、request sent / received / accepted / live evidence / reload / receiver route change / Telegram send / alert chain smoke / runtime gate 全部 `0` | +| 最新 P0 CD / Runner / Secret 注入變更證據驗收基準 | 已新增 `CD-RUNNER-SECRET-INJECTION-CHANGE-EVIDENCE-ACCEPTANCE.md`、snapshot 與產生器;固定 `candidates=5`、`c0=4`、`c1=1`、`write_capable=5`、`workflow_files=33`、`referenced_secret_names=42`、`runner_labels=5`、`evidence_fields=19`、`reviewer_checks=19`、`outcome_lanes=8`、`blocked_actions=32`;secret metadata 成熟度 `66% -> 68%`,workflow / runner 成熟度 `70% -> 72%`;workflow diff / runner attestation / secret name parity / secret injection route / deploy marker readback / guard result / postcheck evidence accepted、workflow modification、runner change、repo secret change、secret rotation、Gitea action dispatch、production deploy、runtime gate 全部 `0` | | 最新 AI Agent automation P1-305 / P1-306 基準 | code `4f0787f8`、deploy marker `af3a9d48`、CD `2592`、code-review `2593`;任務批准邊界與進度彙總已正式驗證;backlog `70%`、done `16/23`、下一步 `P1-001` | | 最新 AI Agent automation P1-001 基準 | code `de3007b7`、stability fix `fd33591c`、deploy marker `8caba233`、LOGBOOK / marker 對齊 `37c0e171`;runtime surface `22`、Secret surface `4`、live gaps `6`、backlog `74%`、done `17/23`、下一步 `P1-002` | | 最新 AI Agent automation P1-002 基準 | code `943faaee`、stability fix `ff266926`、deploy marker `01b8712d`、LOGBOOK / marker 對齊 `70c01003`;Gitea workflows `9`、runner contracts `4`、需 runner attestation workflows `8`、backlog `78%`、done `18/23`、下一步 `P1-003` | @@ -95,6 +96,7 @@ | P0-20 | K8s / ArgoCD manifest repo-only 清冊 | 100% | 已新增 `k8s-argocd-manifest-inventory.py`、snapshot 與文件,把 `k8s/awoooi-prod`、`k8s/argocd`、`k8s/velero`、`k8s/monitoring` 轉成 repo-only manifest inventory;files `49`、C0 `36`、YAML `45`、unique kinds `20`、blocked actions `13`;owner response、rendered diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate 仍全部為 `0` | `K8S_ARGOCD_MANIFEST_INVENTORY_OK files=49 c0=36 yaml=45 kinds=20 runtime_gate=0`;progress guard 固定 snapshot schema、summary、group ids、kind counts、blocked actions 與每列 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | | P0-21 | K8s / ArgoCD owner request draft | 100% | 已新增 `k8s-argocd-owner-request-draft.py`、snapshot 與文件,把 P0-20 四個 scan group 轉成 4 份 request draft;C0 `3`、C1 `1`、request fields `20`、owner fields `11`、evidence gaps `8`、blocked actions `13`;request sent、recipient confirmed、owner response received / accepted、rendered manifest diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、runtime gate 仍全部為 `0` | `K8S_ARGOCD_OWNER_REQUEST_DRAFT_OK drafts=4 c0=3 fields=11 sent=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、request ids、blocked actions 與每份草稿 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | | P0-25 | K8s / ArgoCD owner response acceptance 只讀帳本 | 100% | 已新增 `k8s-argocd-owner-response-acceptance.py`、snapshot 與文件,把 K8s / ArgoCD manifest inventory 與 owner request draft 串成 4 份 owner response acceptance candidate;C0 `3`、required owner fields `11`、reviewer checks `12`、outcome lanes `7`、blocked actions `18`;owner response received / accepted、rendered manifest diff、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate 仍全部為 `0` | `K8S_ARGOCD_OWNER_RESPONSE_ACCEPTANCE_OK candidates=4 c0=3 checks=12 lanes=7 accepted=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、candidate ids、reviewer checks、outcome lanes、blocked actions 與每份候選 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | +| P0-28 | CD / Runner / Secret 注入變更證據驗收只讀帳本 | 100% | 已新增 `cd-runner-secret-injection-change-evidence-acceptance.py`、snapshot 與文件,把 CD pipeline、程式碼審查、部署通知、執行器證明與 repository secret name parity / injection owner 串成 5 份 change evidence candidate;C0 `4`、write-capable `5`、workflow files `33`、referenced secret names `42`、runner labels `5`、required evidence fields `19`、reviewer checks `19`、outcome lanes `8`、blocked actions `32`;secret metadata 成熟度 `66% -> 68%`,workflow / runner 成熟度 `70% -> 72%`;change evidence received / accepted、workflow diff、runner attestation、secret name parity、secret injection route、deploy marker readback、guard result、postcheck evidence、runtime approval package、workflow modification、runner change、repo secret change、secret rotation、Gitea action dispatch、production deploy、runtime gate 仍全部為 `0` | `CD_RUNNER_SECRET_INJECTION_CHANGE_EVIDENCE_ACCEPTANCE_OK candidates=5 c0=4 write_capable=5 checks=19 lanes=8 accepted=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、candidate ids、reviewer checks、outcome lanes、blocked actions 與每份候選 false flags;涉及 `/zh-TW/iwooos` 前端 marker,完成後需 production desktop / mobile smoke | | P0-22 | P0-21 push readback / 同步基線回填 | 100% | 已將 `gitea/main=e8de19d7`、P0-21 commit、AwoooP 平行 Session 同步狀態與 0 / false 邊界回填到 P0 主控板,避免後續工作用舊 `551d8144` 判讀 | 只改 P0 總帳、LOGBOOK 與進度文件;需跑 progress guard、owner response guard、doc secret sanity、diff check 與新增行工作溝通污染掃描;不需要 production browser smoke | ## 3. S4.9 Owner Response Gate 規範 diff --git a/scripts/security/cd-runner-secret-injection-change-evidence-acceptance.py b/scripts/security/cd-runner-secret-injection-change-evidence-acceptance.py new file mode 100644 index 000000000..8af95d018 --- /dev/null +++ b/scripts/security/cd-runner-secret-injection-change-evidence-acceptance.py @@ -0,0 +1,515 @@ +#!/usr/bin/env python3 +""" +IwoooS CD / Runner / Secret 注入變更證據驗收只讀帳本產生器。 + +本工具讀取 repo 內既有 workflow / secret 名稱 snapshot 與 `.gitea/workflows` +檔案 metadata,建立未來 CD、runner、secret injection 變更證據如何收件、 +補件、拒收或交給 reviewer 的 metadata-only ledger。它不呼叫 Gitea / GitHub +API、不讀 secret store、不讀 secret value、不修改 workflow、不啟用 runner、 +不 rotate secret、不 dispatch workflow、不觸發部署。 +""" + +from __future__ import annotations + +import argparse +import json +import re +import subprocess +import sys +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any + + +TAIPEI = timezone(timedelta(hours=8)) + +CHANGE_EVIDENCE_FIELDS = [ + "change_evidence_candidate_id", + "source_refs", + "control_tier", + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval", +] + +REQUIRED_EVIDENCE_FIELDS = [ + "proposed_workflow_or_config_change_ref", + "workflow_diff_ref", + "runner_attestation_ref", + "secret_name_parity_ref", + "secret_injection_route_ref", + "deploy_marker_readback_ref", + "gitea_action_run_ref", + "guard_result_ref", + "log_redaction_review_ref", + "notification_route_owner_ref", + "blast_radius", + "maintenance_window", + "rollback_owner", + "rollback_plan_ref", + "postcheck_evidence_ref", + "affected_scope", + "redacted_evidence_refs", + "reviewer_outcome", + "not_approval", +] + +REVIEWER_CHECKS = [ + { + "check_id": "change_ref_present", + "instruction": "必須有 proposed workflow / config / policy change ref,不能只寫口頭同意。", + }, + { + "check_id": "workflow_diff_ref_only", + "instruction": "只能收 workflow diff ref 或 committed patch ref,不保存未脫敏 workflow payload。", + }, + { + "check_id": "gitea_actions_run_readback_ref_shape", + "instruction": "Gitea Actions run readback 只能是 run id / job id / status ref,不保存 token 或 cookie。", + }, + { + "check_id": "deploy_marker_not_runtime_approval", + "instruction": "deploy marker 只能當部署證據,不代表資安 runtime approval。", + }, + { + "check_id": "runner_owner_attestation_present", + "instruction": "runner label、executor、host alias、owner 與維護窗口必須可追溯。", + }, + { + "check_id": "hosted_minutes_risk_review_present", + "instruction": "涉及 hosted runner 時必須標出額度與供應鏈風險,不得自動啟用。", + }, + { + "check_id": "secret_name_parity_ref_only", + "instruction": "secret parity 只能保存 secret name / scope / present-absent / owner metadata。", + }, + { + "check_id": "no_secret_value_or_hash", + "instruction": "不得出現 secret value、hash、masked token、partial token 或 credential derivative。", + }, + { + "check_id": "secret_injection_path_called_out", + "instruction": "涉及 CD / K8s secret injection 時必須標出 injection path 與 owner,不得讀 value。", + }, + { + "check_id": "step_env_with_secret_guard_result_present", + "instruction": "必須附 `check-gitea-step-env-secrets` 或等價 guard result ref。", + }, + { + "check_id": "telegram_route_owner_present", + "instruction": "涉及通知時必須確認 SRE route owner,不得新增 legacy Telegram route。", + }, + { + "check_id": "deploy_key_and_webhook_material_absent", + "instruction": "不得保存 webhook secret、deploy key private material、runner token 或 write token。", + }, + { + "check_id": "branch_protection_or_required_checks_impact_called_out", + "instruction": "影響 required checks / CODEOWNERS / branch protection 時必須標出影響。", + }, + { + "check_id": "blast_radius_present", + "instruction": "必須列出 repo、workflow、runner、secret metadata、notification、deploy path 影響範圍。", + }, + { + "check_id": "maintenance_window_present", + "instruction": "任何 future workflow / runner / secret injection 變更都必須另有維護窗口。", + }, + { + "check_id": "rollback_owner_present", + "instruction": "必須有 rollback owner 與回復方式;不能只寫『可回復』。", + }, + { + "check_id": "postcheck_evidence_present", + "instruction": "需有 post-check evidence ref,例如 guard result、run status、route smoke 或 notification receipt。", + }, + { + "check_id": "no_execution_claim", + "instruction": "不能把本帳本、owner response、CD success 或 AwoooP approval 當執行批准。", + }, + { + "check_id": "cross_project_sync_noted", + "instruction": "若影響 AwoooP、IwoooS、agent-bounty、監控或公開服務,需有跨專案同步 ref。", + }, +] + +OUTCOME_LANES = [ + { + "lane_id": "waiting_change_evidence", + "meaning": "尚未收到 CD / runner / secret injection 變更證據;所有 accepted / runtime count 維持 0。", + }, + { + "lane_id": "quarantine_sensitive_payload", + "meaning": "收到 secret value、hash、runner token、webhook secret、private key 或未脫敏截圖時只能隔離。", + }, + { + "lane_id": "reject_unredacted_or_runtime_claim", + "meaning": "出現未脫敏 payload 或把 evidence 誤當執行批准時直接拒收。", + }, + { + "lane_id": "request_supplement", + "meaning": "缺 workflow diff、runner owner、secret parity、guard result、rollback 或 post-check 時要求補件。", + }, + { + "lane_id": "ready_for_reviewer_acceptance", + "meaning": "metadata 合格後只能進 reviewer acceptance,不得自動修改 workflow / secret / runner。", + }, + { + "lane_id": "ready_for_runtime_approval_package", + "meaning": "reviewer 接受後也只能形成 runtime approval package,不自動打開 gate。", + }, + { + "lane_id": "waiting_maintenance_window", + "meaning": "若未來要改 workflow / runner / secret injection,仍需獨立維護窗口。", + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "change evidence 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", + "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", + "add_action_button", +] + +EXECUTION_BOUNDARIES = { + "runtime_execution_authorized": False, + "workflow_modification_authorized": False, + "webhook_modification_authorized": False, + "runner_change_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, + "secret_rotation_authorized": False, + "secret_store_read_authorized": False, + "secret_injection_change_authorized": False, + "step_env_secret_allowed": False, + "github_hosted_runner_enable_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, +} + +CANDIDATE_DEFINITIONS = [ + { + "candidate_id": "cd_pipeline_deploy_marker_and_k8s_secret_injection", + "title": "CD pipeline / deploy marker / K8s secret 注入路徑", + "control_tier": "C0", + "risk": "HIGH", + "source_refs": [".gitea/workflows/cd.yaml", "scripts/ci/check-gitea-step-env-secrets.js"], + "affected_scope": "main push CD、Harbor build / push、K8s secret injection、ArgoCD deploy marker、post-deploy checks", + }, + { + "candidate_id": "code_review_pipeline_secret_and_notification_surface", + "title": "Code Review workflow / notification / secret 使用面", + "control_tier": "C0", + "risk": "HIGH", + "source_refs": [".gitea/workflows/code-review.yaml", "scripts/ci/check-gitea-step-env-secrets.js"], + "affected_scope": "Code Review、Telegram / AWOOI API notification、deterministic review report、Gitea Actions status", + }, + { + "candidate_id": "deploy_alerts_and_monitoring_route", + "title": "Deploy alerts workflow / monitoring notification route", + "control_tier": "C1", + "risk": "MEDIUM", + "source_refs": [".gitea/workflows/deploy-alerts.yaml", "scripts/ops/deploy-alerts.sh"], + "affected_scope": "Prometheus / Alertmanager rule deploy、notification route、SRE receipt evidence", + }, + { + "candidate_id": "runner_label_and_executor_attestation", + "title": "Runner label / executor / hosted minutes owner attestation", + "control_tier": "C0", + "risk": "HIGH", + "source_refs": ["docs/security/source-control-workflow-secret-name-local-evidence.snapshot.json"], + "affected_scope": "awoooi-host、self-hosted、ubuntu-latest、harbor、k8s runner labels 與 executor owner", + }, + { + "candidate_id": "repository_secret_name_parity_and_injection_owner", + "title": "Repository secret name parity / injection owner", + "control_tier": "C0", + "risk": "HIGH", + "source_refs": [ + "docs/security/source-control-workflow-secret-name-export-request.snapshot.json", + "docs/security/source-control-workflow-secret-name-owner-response.snapshot.json", + ], + "affected_scope": "9 個 in-scope repos 的 secret name parity、rotation owner、CD / K8s injection owner", + }, +] + + +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 workflow_secret_names(root: Path, source_refs: list[str]) -> list[str]: + names: set[str] = set() + expression_re = re.compile(r"\$\{\{(.+?)\}\}") + secret_re = re.compile( + r"secrets(?:\.([A-Za-z_][A-Za-z0-9_]*)|\[['\"]([^'\"]+)['\"]\])" + ) + for ref in source_refs: + path = root / ref + if not path.exists() or not path.is_file(): + continue + if ".gitea/workflows/" not in ref and ".github/workflows/" not in ref: + continue + text = path.read_text(encoding="utf-8", errors="replace") + for expression in expression_re.findall(text): + if "secrets" not in expression: + continue + for match in secret_re.finditer(expression): + names.update(name for name in match.groups() if name) + return sorted(names) + + +def build_candidate(root: Path, definition: dict[str, Any]) -> dict[str, Any]: + source_refs = list(definition["source_refs"]) + return { + "change_evidence_candidate_id": f"cd_runner_secret_injection:{definition['candidate_id']}", + "status": "waiting_change_evidence", + "title": definition["title"], + "control_tier": definition["control_tier"], + "risk": definition["risk"], + "source_refs": source_refs, + "workflow_secret_name_refs": workflow_secret_names(root, source_refs), + "write_capable": True, + "requires_runtime_approval_package": True, + "affected_scope": definition["affected_scope"], + "change_evidence_fields": CHANGE_EVIDENCE_FIELDS, + "required_evidence_fields": REQUIRED_EVIDENCE_FIELDS, + "reviewer_checks": [item["check_id"] for item in REVIEWER_CHECKS], + "outcome_lanes": [item["lane_id"] for item in OUTCOME_LANES], + "blocked_actions": BLOCKED_ACTIONS, + "proposed_workflow_or_config_change_ref": None, + "workflow_diff_ref": None, + "runner_attestation_ref": None, + "secret_name_parity_ref": None, + "secret_injection_route_ref": None, + "deploy_marker_readback_ref": None, + "gitea_action_run_ref": None, + "guard_result_ref": None, + "log_redaction_review_ref": None, + "notification_route_owner_ref": None, + "blast_radius": "pending_change_evidence", + "maintenance_window": "pending_change_evidence", + "rollback_owner": "pending_change_evidence", + "rollback_plan_ref": None, + "postcheck_evidence_ref": None, + "redacted_evidence_refs": [], + "reviewer_outcome": "waiting_change_evidence", + "not_approval": True, + "change_evidence_received": False, + "change_evidence_accepted": False, + "change_evidence_rejected": False, + "change_evidence_quarantined": False, + "workflow_diff_accepted": False, + "runner_attestation_accepted": False, + "secret_name_parity_accepted": False, + "secret_injection_route_accepted": False, + "deploy_marker_readback_accepted": False, + "guard_result_accepted": False, + "postcheck_evidence_accepted": False, + "runtime_approval_package_ready": 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]: + local_evidence = load_json( + root / "docs/security/source-control-workflow-secret-name-local-evidence.snapshot.json" + ) + export_request = load_json( + root / "docs/security/source-control-workflow-secret-name-export-request.snapshot.json" + ) + owner_response = load_json( + root / "docs/security/source-control-workflow-secret-name-owner-response.snapshot.json" + ) + local_summary = local_evidence["summary"] + export_summary = export_request["summary"] + owner_summary = owner_response["summary"] + candidates = [build_candidate(root, item) for item in CANDIDATE_DEFINITIONS] + 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_change_evidence_acceptance_v1", + "generated_at": report_time, + "git_commit": git_short_sha(root), + "status": "change_evidence_acceptance_ledger_ready_no_runtime_action", + "mode": "metadata_only_no_secret_value_no_workflow_change", + "source_paths": [ + "docs/security/source-control-workflow-secret-name-local-evidence.snapshot.json", + "docs/security/source-control-workflow-secret-name-export-request.snapshot.json", + "docs/security/source-control-workflow-secret-name-owner-response.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": { + "change_evidence_candidate_count": len(candidates), + "c0_change_evidence_candidate_count": len(c0_candidates), + "c1_change_evidence_candidate_count": len(c1_candidates), + "write_capable_candidate_count": sum(1 for item in candidates if item["write_capable"]), + "local_workflow_file_count": local_summary["workflow_file_count"], + "gitea_workflow_file_count": local_summary["gitea_workflow_file_count"], + "github_workflow_file_count": local_summary["github_workflow_file_count"], + "local_referenced_secret_name_count": local_summary["unique_secret_name_count"], + "runner_label_count": local_summary["runner_label_count"], + "export_request_count": export_summary["export_request_count"], + "export_lane_count": export_summary["export_lane_count"], + "owner_response_template_count": owner_summary["response_template_count"], + "owner_response_received_count": owner_summary["received_response_count"], + "owner_response_accepted_count": owner_summary["accepted_response_count"], + "required_evidence_field_count": len(REQUIRED_EVIDENCE_FIELDS), + "reviewer_check_count": len(REVIEWER_CHECKS), + "outcome_lane_count": len(OUTCOME_LANES), + "blocked_action_count": len(BLOCKED_ACTIONS), + "change_evidence_received_count": 0, + "change_evidence_accepted_count": 0, + "workflow_diff_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, + "guard_result_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "runtime_approval_package_ready_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "secret_metadata_coverage_percent_before_acceptance": 66, + "secret_metadata_coverage_percent_after_acceptance": 68, + "gitea_workflow_runner_coverage_percent_before_acceptance": 70, + "gitea_workflow_runner_coverage_percent_after_acceptance": 72, + }, + "execution_boundaries": EXECUTION_BOUNDARIES, + "change_evidence_fields": CHANGE_EVIDENCE_FIELDS, + "required_evidence_fields": REQUIRED_EVIDENCE_FIELDS, + "reviewer_checks": REVIEWER_CHECKS, + "outcome_lanes": OUTCOME_LANES, + "blocked_actions": BLOCKED_ACTIONS, + "change_evidence_candidates": candidates, + "operator_interpretation": [ + "此帳本只描述 CD / runner / secret injection 變更證據如何收件與拒收,不是 workflow 變更批准。", + "secret 只能以名稱、scope、present-absent、owner 與 redacted evidence ref 呈現,不得保存 value、hash 或 partial token。", + "deploy marker、Gitea Actions success、AwoooP approval 與 UI 可見狀態都不能被解讀成 runtime gate 已開。", + "未來若要修改 workflow、runner、secret injection、webhook、deploy key 或 branch protection,仍需獨立 owner response、維護窗口、rollback owner 與 runtime approval package。", + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser(description="CD / Runner / Secret 注入變更證據驗收只讀帳本") + 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_CHANGE_EVIDENCE_ACCEPTANCE_OK " + f"candidates={summary['change_evidence_candidate_count']} " + f"c0={summary['c0_change_evidence_candidate_count']} " + f"write_capable={summary['write_capable_candidate_count']} " + f"checks={summary['reviewer_check_count']} " + f"lanes={summary['outcome_lane_count']} " + f"accepted={summary['change_evidence_accepted_count']} " + f"runtime_gate={summary['runtime_gate_count']}", + file=sys.stderr, + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/security/high-value-config-control-coverage.py b/scripts/security/high-value-config-control-coverage.py index bb543500e..1c5781e68 100644 --- a/scripts/security/high-value-config-control-coverage.py +++ b/scripts/security/high-value-config-control-coverage.py @@ -73,26 +73,32 @@ CONTROL_STATUS_BY_CATEGORY = { "next_owner_action": "補 GitOps owner 回覆、proposed commit ref、rendered manifest diff ref、ArgoCD app / sync revision ref、health before / after、rollout、route smoke、metrics / alert、blast radius、rollback revision、maintenance window 與 post-check owner。", }, "secret_metadata": { - "coverage_status": "metadata_policy_ready", - "coverage_percent": 66, + "coverage_status": "secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", + "coverage_percent": 68, "evidence_refs": [ "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", "docs/security/source-control-workflow-secret-name-inventory.snapshot.json", + "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-OWNER-RESPONSE.md", + "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/SECRETS_REFERENCE.md", ], - "current_gap": "只允許 secret name / metadata;仍缺 owner response 與 parity acceptance。", - "next_owner_action": "只回覆 secret name owner、rotation owner、injection owner 與 redacted evidence refs。", + "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。", }, "gitea_workflow_runner_source_control": { - "coverage_status": "metadata_inventory_ready", - "coverage_percent": 70, + "coverage_status": "cd_runner_secret_injection_change_evidence_acceptance_ready_needs_owner_evidence", + "coverage_percent": 72, "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/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md", ], - "current_gap": "workflow / runner / deploy key / webhook / branch protection 仍待 owner response;不得改 workflow。", - "next_owner_action": "補 runner label、webhook、deploy key、branch protection 與 workflow parity owner metadata。", + "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。", }, "public_admin_api_runtime_config": { "coverage_status": "policy_ready_needs_change_scoped_smoke", @@ -339,6 +345,8 @@ def build_report(root: Path, generated_at: str | None) -> dict[str, Any]: "rendered_diff_acceptance_ledger_ready_needs_owner_live_diff", "owner_response_acceptance_ledger_ready_needs_runtime_evidence", "change_evidence_acceptance_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", "owner_response_acceptance_ledger_ready_needs_restore_drill_owner", "owner_response_acceptance_ledger_ready_needs_network_owner", "change_evidence_acceptance_ready_needs_network_owner_evidence", diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 76ad91546..7e4f12a01 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -146,6 +146,9 @@ def validate(root: Path) -> None: k8s_argocd_change_evidence_acceptance = load_json( security_dir / "k8s-argocd-change-evidence-acceptance.snapshot.json" ) + cd_runner_secret_injection_change_evidence_acceptance = load_json( + security_dir / "cd-runner-secret-injection-change-evidence-acceptance.snapshot.json" + ) public_gateway_preflight_inventory = load_json( security_dir / "public-gateway-preflight-inventory.snapshot.json" ) @@ -2503,7 +2506,7 @@ def validate(root: Path) -> None: assert_equal( "high_value_config_coverage.summary.needs_live_evidence_count", high_value_config_coverage["summary"]["needs_live_evidence_count"], - 6, + 8, ) for key in [ "owner_response_received_count", @@ -2824,6 +2827,62 @@ def validate(root: Path) -> None: k8s_gitops_category["evidence_refs"], evidence_ref, ) + secret_metadata_category = next( + item + for item in high_value_config_coverage["coverage_categories"] + if item["category_id"] == "secret_metadata" + ) + assert_equal( + "high_value_config_coverage.coverage_categories.secret_metadata.coverage_percent", + secret_metadata_category["coverage_percent"], + 68, + ) + 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", + ) + for evidence_ref in [ + "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-INVENTORY.md", + "docs/security/source-control-workflow-secret-name-inventory.snapshot.json", + "docs/security/SOURCE-CONTROL-WORKFLOW-SECRET-NAME-OWNER-RESPONSE.md", + "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/SECRETS_REFERENCE.md", + ]: + assert_contains( + "high_value_config_coverage.coverage_categories.secret_metadata.evidence_refs", + secret_metadata_category["evidence_refs"], + evidence_ref, + ) + workflow_runner_category = next( + item + for item in high_value_config_coverage["coverage_categories"] + if item["category_id"] == "gitea_workflow_runner_source_control" + ) + assert_equal( + "high_value_config_coverage.coverage_categories.workflow_runner.coverage_percent", + workflow_runner_category["coverage_percent"], + 72, + ) + 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", + ) + 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/SOURCE-CONTROL-PRIMARY-READINESS-GATE.md", + ]: + assert_contains( + "high_value_config_coverage.coverage_categories.workflow_runner.evidence_refs", + workflow_runner_category["evidence_refs"], + evidence_ref, + ) assert_contains( "high_value_config_coverage.lowest_coverage_categories.docker", [item["category_id"] for item in high_value_config_coverage["lowest_coverage_categories"]], @@ -5731,7 +5790,7 @@ def validate(root: Path) -> None: "high_value_config_control_coverage_c0_category_count": 8, "high_value_config_control_coverage_c1_category_count": 4, "high_value_config_control_coverage_average_percent": 68, - "high_value_config_control_coverage_needs_live_evidence_count": 6, + "high_value_config_control_coverage_needs_live_evidence_count": 8, "high_value_config_control_coverage_owner_response_required_count": 14, "high_value_config_control_coverage_owner_response_received_count": 0, "high_value_config_control_coverage_owner_response_accepted_count": 0, @@ -5851,6 +5910,39 @@ def validate(root: Path) -> None: "k8s_argocd_change_evidence_acceptance_runtime_gate_count": 0, "k8s_argocd_change_evidence_acceptance_action_button_count": 0, "k8s_argocd_change_evidence_acceptance_coverage_percent_after_acceptance": 64, + "cd_runner_secret_injection_change_evidence_acceptance_first_layer": True, + "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_c1_candidate_count": 1, + "cd_runner_secret_injection_change_evidence_acceptance_write_capable_candidate_count": 5, + "cd_runner_secret_injection_change_evidence_acceptance_local_workflow_file_count": 33, + "cd_runner_secret_injection_change_evidence_acceptance_gitea_workflow_file_count": 12, + "cd_runner_secret_injection_change_evidence_acceptance_github_workflow_file_count": 21, + "cd_runner_secret_injection_change_evidence_acceptance_local_referenced_secret_name_count": 42, + "cd_runner_secret_injection_change_evidence_acceptance_runner_label_count": 5, + "cd_runner_secret_injection_change_evidence_acceptance_export_request_count": 9, + "cd_runner_secret_injection_change_evidence_acceptance_export_lane_count": 5, + "cd_runner_secret_injection_change_evidence_acceptance_owner_response_template_count": 5, + "cd_runner_secret_injection_change_evidence_acceptance_required_evidence_field_count": 19, + "cd_runner_secret_injection_change_evidence_acceptance_reviewer_check_count": 19, + "cd_runner_secret_injection_change_evidence_acceptance_outcome_lane_count": 8, + "cd_runner_secret_injection_change_evidence_acceptance_blocked_action_count": 32, + "cd_runner_secret_injection_change_evidence_acceptance_received_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_workflow_diff_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_runner_attestation_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_secret_name_parity_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_secret_injection_route_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_deploy_marker_readback_accepted_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_guard_result_accepted_count": 0, + "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_change_evidence_acceptance_action_button_count": 0, + "cd_runner_secret_injection_change_evidence_acceptance_secret_metadata_coverage_percent_before_acceptance": 66, + "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, } for key, expected in expected_ssh_network_projection_summary.items(): assert_equal( @@ -15441,7 +15533,7 @@ def validate(root: Path) -> None: "high_value_config_control_coverage_c0_category_count=8", "high_value_config_control_coverage_c1_category_count=4", "high_value_config_control_coverage_average_percent=68", - "high_value_config_control_coverage_needs_live_evidence_count=6", + "high_value_config_control_coverage_needs_live_evidence_count=8", "high_value_config_control_coverage_owner_response_required_count=14", "high_value_config_control_coverage_owner_response_received_count=0", "high_value_config_control_coverage_owner_response_accepted_count=0", @@ -15449,6 +15541,32 @@ def validate(root: Path) -> None: "high_value_config_control_coverage_action_button_count=0", "nginx_public_gateway_coverage_percent=88", "k8s_production_gitops_coverage_percent=64", + "secret_metadata_coverage_percent=68", + "gitea_workflow_runner_source_control_coverage_percent=72", + "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_c1_candidate_count=1", + "cd_runner_secret_injection_change_evidence_acceptance_write_capable_candidate_count=5", + "cd_runner_secret_injection_change_evidence_acceptance_local_workflow_file_count=33", + "cd_runner_secret_injection_change_evidence_acceptance_gitea_workflow_file_count=12", + "cd_runner_secret_injection_change_evidence_acceptance_github_workflow_file_count=21", + "cd_runner_secret_injection_change_evidence_acceptance_local_referenced_secret_name_count=42", + "cd_runner_secret_injection_change_evidence_acceptance_runner_label_count=5", + "cd_runner_secret_injection_change_evidence_acceptance_required_evidence_field_count=19", + "cd_runner_secret_injection_change_evidence_acceptance_reviewer_check_count=19", + "cd_runner_secret_injection_change_evidence_acceptance_outcome_lane_count=8", + "cd_runner_secret_injection_change_evidence_acceptance_blocked_action_count=32", + "cd_runner_secret_injection_change_evidence_acceptance_received_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_workflow_diff_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_runner_attestation_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_secret_name_parity_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_secret_injection_route_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_deploy_marker_readback_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_guard_result_accepted_count=0", + "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", "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", @@ -15572,6 +15690,27 @@ def validate(root: Path) -> None: "live_alert_fire_authorized=false", "alert_chain_smoke_authorized=false", "workflow_modification_authorized=false", + "webhook_modification_authorized=false", + "runner_change_authorized=false", + "deploy_key_change_authorized=false", + "branch_protection_change_authorized=false", + "codeowners_change_authorized=false", + "repo_secret_change_authorized=false", + "secret_hash_collection_allowed=false", + "partial_token_collection_allowed=false", + "secret_rotation_authorized=false", + "secret_store_read_authorized=false", + "secret_injection_change_authorized=false", + "github_hosted_runner_enable_authorized=false", + "gitea_action_dispatch_authorized=false", + "cd_pipeline_run_authorized=false", + "deploy_marker_write_authorized=false", + "k8s_secret_injection_authorized=false", + "production_deploy_authorized=false", + "refs_sync_authorized=false", + "force_push_authorized=false", + "github_primary_switch_authorized=false", + "disable_gitea_authorized=false", "active_scan_authorized=false", "agent_bounty_runtime_authorized=false", ]: @@ -15600,6 +15739,11 @@ def validate(root: Path) -> None: iwooos_projection_page, "{ key: 'k8sArgocd', rank: 'P0-3', state: '64% / sync 0'", ) + assert_text_contains( + "iwooos_page.critical_config_priority_workflow_secret_percent", + iwooos_projection_page, + "{ key: 'workflowSecret', rank: 'P0-4', state: '68% / 72%'", + ) for text in [ "critical_config_priority_frontstage_summary_count=4", "critical_config_priority_item_count=6", @@ -15614,6 +15758,23 @@ def validate(root: Path) -> None: "nginx_public_gateway_rendered_diff_accepted=false", "nginx_public_gateway_rendered_diff_acceptance_candidate_count=3", "nginx_public_gateway_nginx_test_evidence_count=0", + "secret_metadata_coverage_percent=68", + "gitea_workflow_runner_source_control_coverage_percent=72", + "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", + "cd_runner_secret_injection_change_evidence_acceptance_required_evidence_field_count=19", + "cd_runner_secret_injection_change_evidence_acceptance_reviewer_check_count=19", + "cd_runner_secret_injection_change_evidence_acceptance_outcome_lane_count=8", + "cd_runner_secret_injection_change_evidence_acceptance_blocked_action_count=32", + "cd_runner_secret_injection_change_evidence_acceptance_received_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_workflow_diff_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_runner_attestation_accepted_count=0", + "cd_runner_secret_injection_change_evidence_acceptance_secret_name_parity_accepted_count=0", + "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", "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", @@ -15632,6 +15793,14 @@ def validate(root: Path) -> None: "network_policy_apply_authorized=false", "nodeport_change_authorized=false", "rbac_change_authorized=false", + "runner_change_authorized=false", + "repo_secret_change_authorized=false", + "secret_injection_change_authorized=false", + "gitea_action_dispatch_authorized=false", + "cd_pipeline_run_authorized=false", + "production_deploy_authorized=false", + "force_push_authorized=false", + "github_primary_switch_authorized=false", "runtime_execution_authorized=false", "active_runtime_gate_count=0", "action_buttons_allowed=false", @@ -17004,6 +17173,174 @@ def validate(root: Path) -> None: f"k8s_argocd_change_evidence_acceptance.{item['change_evidence_candidate_id']}.{false_key}", item[false_key], ) + assert_equal( + "cd_runner_secret_injection_change_evidence_acceptance.schema", + cd_runner_secret_injection_change_evidence_acceptance["schema_version"], + "cd_runner_secret_injection_change_evidence_acceptance_v1", + ) + assert_equal( + "cd_runner_secret_injection_change_evidence_acceptance.status", + cd_runner_secret_injection_change_evidence_acceptance["status"], + "change_evidence_acceptance_ledger_ready_no_runtime_action", + ) + assert_equal( + "cd_runner_secret_injection_change_evidence_acceptance.mode", + cd_runner_secret_injection_change_evidence_acceptance["mode"], + "metadata_only_no_secret_value_no_workflow_change", + ) + expected_cd_runner_secret_injection_summary = { + "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, + "gitea_workflow_file_count": 12, + "github_workflow_file_count": 21, + "local_referenced_secret_name_count": 42, + "runner_label_count": 5, + "export_request_count": 9, + "export_lane_count": 5, + "owner_response_template_count": 5, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "required_evidence_field_count": 19, + "reviewer_check_count": 19, + "outcome_lane_count": 8, + "blocked_action_count": 32, + "change_evidence_received_count": 0, + "change_evidence_accepted_count": 0, + "workflow_diff_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, + "guard_result_accepted_count": 0, + "postcheck_evidence_accepted_count": 0, + "runtime_approval_package_ready_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + "secret_metadata_coverage_percent_before_acceptance": 66, + "secret_metadata_coverage_percent_after_acceptance": 68, + "gitea_workflow_runner_coverage_percent_before_acceptance": 70, + "gitea_workflow_runner_coverage_percent_after_acceptance": 72, + } + for key, expected in expected_cd_runner_secret_injection_summary.items(): + assert_equal( + f"cd_runner_secret_injection_change_evidence_acceptance.summary.{key}", + cd_runner_secret_injection_change_evidence_acceptance["summary"][key], + expected, + ) + for key, value in cd_runner_secret_injection_change_evidence_acceptance["execution_boundaries"].items(): + if key == "not_authorization": + assert_true(f"cd_runner_secret_injection_change_evidence_acceptance.execution_boundaries.{key}", value) + else: + assert_false(f"cd_runner_secret_injection_change_evidence_acceptance.execution_boundaries.{key}", value) + expected_cd_runner_secret_injection_ids = [ + "cd_runner_secret_injection:cd_pipeline_deploy_marker_and_k8s_secret_injection", + "cd_runner_secret_injection:code_review_pipeline_secret_and_notification_surface", + "cd_runner_secret_injection:deploy_alerts_and_monitoring_route", + "cd_runner_secret_injection:runner_label_and_executor_attestation", + "cd_runner_secret_injection:repository_secret_name_parity_and_injection_owner", + ] + assert_equal( + "cd_runner_secret_injection_change_evidence_acceptance.candidate_ids", + [ + item["change_evidence_candidate_id"] + for item in cd_runner_secret_injection_change_evidence_acceptance["change_evidence_candidates"] + ], + expected_cd_runner_secret_injection_ids, + ) + assert_equal( + "cd_runner_secret_injection_change_evidence_acceptance.reviewer_checks.count", + len(cd_runner_secret_injection_change_evidence_acceptance["reviewer_checks"]), + 19, + ) + assert_equal( + "cd_runner_secret_injection_change_evidence_acceptance.outcome_lanes.count", + len(cd_runner_secret_injection_change_evidence_acceptance["outcome_lanes"]), + 8, + ) + assert_equal( + "cd_runner_secret_injection_change_evidence_acceptance.blocked_actions.count", + len(cd_runner_secret_injection_change_evidence_acceptance["blocked_actions"]), + 32, + ) + for item in cd_runner_secret_injection_change_evidence_acceptance["change_evidence_candidates"]: + assert_equal( + f"cd_runner_secret_injection_change_evidence_acceptance.{item['change_evidence_candidate_id']}.change_evidence_fields", + len(item["change_evidence_fields"]), + 22, + ) + assert_equal( + f"cd_runner_secret_injection_change_evidence_acceptance.{item['change_evidence_candidate_id']}.required_evidence_fields", + len(item["required_evidence_fields"]), + 19, + ) + assert_equal( + f"cd_runner_secret_injection_change_evidence_acceptance.{item['change_evidence_candidate_id']}.reviewer_checks", + len(item["reviewer_checks"]), + 19, + ) + assert_equal( + f"cd_runner_secret_injection_change_evidence_acceptance.{item['change_evidence_candidate_id']}.outcome_lanes", + len(item["outcome_lanes"]), + 8, + ) + assert_equal( + f"cd_runner_secret_injection_change_evidence_acceptance.{item['change_evidence_candidate_id']}.blocked_actions", + len(item["blocked_actions"]), + 32, + ) + assert_true( + f"cd_runner_secret_injection_change_evidence_acceptance.{item['change_evidence_candidate_id']}.not_approval", + item["not_approval"], + ) + for false_key in [ + "change_evidence_received", + "change_evidence_accepted", + "change_evidence_rejected", + "change_evidence_quarantined", + "workflow_diff_accepted", + "runner_attestation_accepted", + "secret_name_parity_accepted", + "secret_injection_route_accepted", + "deploy_marker_readback_accepted", + "guard_result_accepted", + "postcheck_evidence_accepted", + "runtime_approval_package_ready", + "runtime_execution_authorized", + "workflow_modification_authorized", + "webhook_modification_authorized", + "runner_change_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", + "secret_rotation_authorized", + "secret_store_read_authorized", + "secret_injection_change_authorized", + "step_env_secret_allowed", + "github_hosted_runner_enable_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_change_evidence_acceptance.{item['change_evidence_candidate_id']}.{false_key}", + item[false_key], + ) assert_equal( "iwooos_projection.summary.domain_tls_certbot_inventory_managed_domain_count", iwooos_projection["summary"]["domain_tls_certbot_inventory_managed_domain_count"],