diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 2974bddfa..f8339828d 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,35 @@ +## 2026-06-15|K8s / ArgoCD owner response acceptance 只讀帳本本地完成 + +**背景**:K8s / ArgoCD / Velero / monitoring manifests 屬於 P0 GitOps 風險面,任何 ArgoCD sync、kubectl action、secret collection、RBAC / NetworkPolicy change 或 restore backup 都可能影響 production。既有 manifest inventory 與 owner request draft 已完成,本段補 owner response acceptance 只讀帳本,避免把未驗收回覆誤判成 live cluster read、sync 或 kubectl 授權。 + +**完成項目**: +- 新增 `scripts/security/k8s-argocd-owner-response-acceptance.py`,從 K8s / ArgoCD manifest inventory 與 owner request draft 兩份 snapshot 產生 metadata-only acceptance ledger。 +- 新增 `docs/security/k8s-argocd-owner-response-acceptance.snapshot.json`,固定 `acceptance_candidate_count=4`、`c0_acceptance_candidate_count=3`、`c1_acceptance_candidate_count=1`、`acceptance_field_count=20`、`required_owner_field_count=11`、`reviewer_check_count=12`、`outcome_lane_count=7`、`blocked_action_count=18`。 +- 新增 `docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md`,說明 owner 必填欄位、reviewer checks、outcome lanes、blocked actions、完成度與 0 / false 邊界。 +- `security-mirror-progress-guard.py` 已鎖住新 snapshot 的 schema、summary、execution false flags、candidate ids、reviewer checks、outcome lanes、blocked actions 與每份候選 false flags。 +- `HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md`、`IWOOOS-CONFIG-CONTROL-INVENTORY.md`、`SECURITY-SUPPLY-CHAIN-PROGRESS.md`、P0 主控板與 MASTER 已同步。 + +**本地驗證**: +- `python3 -m json.tool docs/security/k8s-argocd-owner-response-acceptance.snapshot.json` 通過。 +- `python3 -m json.tool docs/security/high-value-config-control-coverage.snapshot.json` 通過。 +- `python3 -m json.tool docs/security/iwooos-posture-projection.snapshot.json` 通過。 +- `python3 -m py_compile scripts/security/k8s-argocd-owner-response-acceptance.py scripts/security/high-value-config-control-coverage.py scripts/security/security-mirror-progress-guard.py` 通過。 +- 產生器 smoke:`K8S_ARGOCD_OWNER_RESPONSE_ACCEPTANCE_OK candidates=4 c0=3 checks=12 lanes=7 accepted=0 runtime_gate=0`。 +- high-value config coverage 重產:`HIGH_VALUE_CONFIG_CONTROL_COVERAGE_OK categories=14 c0=8 avg=66 runtime_gate=0`。 +- K8s / ArgoCD owner response acceptance snapshot 斷言:`K8S_ARGOCD_OWNER_RESPONSE_ACCEPTANCE_ASSERTIONS_OK candidates=4 c0=3 fields=11 checks=12 lanes=7 accepted=0 runtime_gate=0`。 +- `python3 scripts/security/security-mirror-progress-guard.py --root .` → `SECURITY_MIRROR_PROGRESS_GUARD_OK`。 +- `python3 scripts/security/source-control-owner-response-guard.py --root .` → `SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK`。 +- `python3 scripts/ops/doc-secrets-sanity-check.py docs .gitea` → `DOC_SECRET_SANITY_OK scanned_files=838`。 +- `git diff --check` 通過。 +- 新增行工作視窗溝通片語掃描:無命中。 + +**完成度與邊界**: +- K8s / ArgoCD owner response acceptance ledger artifact:`100%`。 +- K8s / ArgoCD 只讀治理成熟度:`58% -> 62%`。 +- IwoooS headline:維持 `64%`;active runtime gate:維持 `0`。 +- Production browser verification:不適用;本輪只改 repo 內文件、snapshot、guard 與產生器,不變更前端 bundle 或 runtime。 +- request sent、recipient confirmed、owner response received / accepted、rendered manifest diff candidate / ready、ArgoCD health readback、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret value collection、maintenance window accepted、rollback revision accepted、production write、runtime gate、action button 全部維持 `0 / false`。 + ## 2026-06-14|Public Gateway owner response acceptance 只讀帳本本地完成 **背景**:Nginx public gateway 是 C0 公開入口配置,手改 live conf 會直接影響網站、admin route、API、WebSocket、TLS 與 ACME。既有 live conf export、redacted export intake 與 rendered diff gate 已完成,本段補 owner response acceptance 只讀帳本,避免把未驗收回覆誤判成 `nginx -t`、reload 或 route smoke 授權。 diff --git a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md index 02ab1acdb..7dd9d1ea2 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -34,6 +34,8 @@ 2026-06-14 P0-21 再新增 `docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md` 與 `docs/security/k8s-argocd-owner-request-draft.snapshot.json`,將四個 scan group 轉成 `request_draft_count=4`、`c0_request_draft_count=3`、`required_owner_field_count=11`、`evidence_gap_count=8`、`blocked_action_count=13` 的 request draft。此更新仍不是 request sent、owner response received / accepted、ArgoCD readback、sync、kubectl action 或 runtime gate。 +2026-06-15 P0-25 再新增 `docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md` 與 `docs/security/k8s-argocd-owner-response-acceptance.snapshot.json`,將 manifest inventory 與 owner request draft 轉成 `acceptance_candidate_count=4`、`c0_acceptance_candidate_count=3`、`required_owner_field_count=11`、`reviewer_check_count=12`、`outcome_lane_count=7`、`blocked_action_count=18` 的 owner response acceptance 只讀帳本。此更新讓 `k8s_production_gitops` 從 `58%` 推進到 `62%`;owner response received / accepted、rendered manifest diff、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate 與 action button 仍全部為 `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。 diff --git a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md index 2a1a5430a..f30fa12fa 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -156,7 +156,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公 | P2 | Package / supply-chain baselines | `pnpm-lock.yaml`、`package.json`、Dockerfiles、inventory snapshots | repo owner | lockfile drift, CVE / license policy, image digest evidence | | P3 | Runbook / endpoint docs / snapshots | `docs/reference/*`、`docs/runbooks/*`、`docs/security/*.snapshot.json` | doc owner | no secret value, stale endpoint flag, owner-reviewed evidence refs | -2026-06-14 P0-20 已新增 `docs/security/K8S-ARGOCD-MANIFEST-INVENTORY.md` 與 `docs/security/k8s-argocd-manifest-inventory.snapshot.json`,把 K8s / ArgoCD / Velero / monitoring repo source 固定為 `files=49`、`c0=36`、`yaml=45`、`unique_kinds=20`、`blocked_actions=13` 的只讀清冊。P0-21 再新增 `docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md` 與 `docs/security/k8s-argocd-owner-request-draft.snapshot.json`,將四個 scan group 轉成 `drafts=4`、`c0=3`、`owner_fields=11` 的 owner request draft。這些都不是 live cluster read、ArgoCD API read、ArgoCD sync、kubectl action、Helm upgrade、secret collection、manual pod restart、scale workload、RBAC / NetworkPolicy change、restore backup、production write 或 runtime gate。 +2026-06-14 P0-20 已新增 `docs/security/K8S-ARGOCD-MANIFEST-INVENTORY.md` 與 `docs/security/k8s-argocd-manifest-inventory.snapshot.json`,把 K8s / ArgoCD / Velero / monitoring repo source 固定為 `files=49`、`c0=36`、`yaml=45`、`unique_kinds=20`、`blocked_actions=13` 的只讀清冊。P0-21 再新增 `docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md` 與 `docs/security/k8s-argocd-owner-request-draft.snapshot.json`,將四個 scan group 轉成 `drafts=4`、`c0=3`、`owner_fields=11` 的 owner request draft。2026-06-15 P0-25 再新增 `docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md` 與 `docs/security/k8s-argocd-owner-response-acceptance.snapshot.json`,固定 `candidates=4`、`c0=3`、`owner_fields=11`、`reviewer_checks=12`、`outcome_lanes=7`、`blocked_actions=18` 的 owner response acceptance 只讀帳本。這些都不是 live cluster read、ArgoCD API read、ArgoCD sync、kubectl action、Helm upgrade、secret collection、manual pod restart、scale workload、RBAC / NetworkPolicy change、restore backup、production write 或 runtime gate。 ## 4. 新增規範 diff --git a/docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md b/docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md new file mode 100644 index 000000000..fe4fdfb4b --- /dev/null +++ b/docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md @@ -0,0 +1,134 @@ +# IwoooS K8s / ArgoCD Owner Response Acceptance 只讀帳本 + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-15 | +| 狀態 | `owner_response_acceptance_ledger_ready_no_runtime_action` | +| 工具 | `scripts/security/k8s-argocd-owner-response-acceptance.py` | +| Snapshot | `docs/security/k8s-argocd-owner-response-acceptance.snapshot.json` | +| 來源 | `k8s-argocd-manifest-inventory.snapshot.json`、`k8s-argocd-owner-request-draft.snapshot.json` | +| runtime gate | `0` | + +## 1. 目的 + +本文件把 K8s / ArgoCD manifest repo-only 清冊與 owner request draft 串成 owner response acceptance 只讀帳本。目的不是讀 live cluster,也不是執行 ArgoCD sync 或 `kubectl`,而是固定未來 owner 回覆要如何被 reviewer 收件、補件、隔離、拒收或進入 rendered manifest review。 + +本階段不呼叫 ArgoCD API、不讀 live cluster、不執行 `kubectl`、不套用 manifest、不跑 Helm、不讀 Secret value、不重啟 Pod、不 scale workload、不改 RBAC / NetworkPolicy、不 restore backup、不寫 production。 + +## 2. 摘要 + +| 指標 | 目前值 | 說明 | +|------|--------|------| +| source scan group | `4` | production、ArgoCD、Velero、monitoring | +| source request draft | `4` | 承接 owner request draft | +| acceptance candidate | `4` | 對應四個 scan group | +| C0 / C1 acceptance candidate | `3 / 1` | production、ArgoCD、Velero 為 C0;monitoring 為 C1 | +| acceptance field | `20` | 每份 acceptance candidate 固定欄位數 | +| required owner field | `11` | 承接 owner request draft 的必填欄位 | +| reviewer check | `12` | reviewer 收件前必檢項 | +| outcome lane | `7` | 等待、隔離、拒收、補件、review、只讀更新、等待 runtime gate | +| blocked action | `18` | 驗收前全部禁止 | +| owner response received / accepted | `0 / 0` | 不得假性拉高 | +| ArgoCD API read / sync / kubectl | `0` | 未授權且未執行 | +| runtime gate / action button | `0 / 0` | 不開任何執行入口 | + +## 3. Owner 必填欄位 + +| 欄位 | 說明 | +|------|------| +| `owner_role_or_team` | GitOps / Kubernetes / ArgoCD owner role 或 team | +| `decision` | 對本 scan group 的回覆判定 | +| `decision_reason` | 決策理由,不得包含機敏值 | +| `affected_scope` | 受影響 namespace、Application、manifest group 或 workload scope | +| `redacted_evidence_refs` | 文件、hash、ticket、commit 或脫敏 artifact pointer | +| `argocd_health_readback_ref` | owner-provided health readback ref;不得觸發 live API read | +| `argocd_sync_revision_ref` | sync revision / desired revision ref;不代表 sync 授權 | +| `rollback_revision` | rollback revision 或明確禁止窗口 | +| `followup_owner` | 補件、隔離、拒收或下一步 review owner | +| `maintenance_window` | 維護窗口或禁止窗口 | +| `validation_plan` | health、rollout、metric、alert、rollback post-check plan | + +## 4. Reviewer Checks + +| Check | 規則 | +|-------|------| +| `owner_identity_present` | owner role / team 必須可追溯 | +| `decision_reason_present` | decision 與 decision reason 必須同時存在 | +| `affected_scope_matches_group` | affected scope 必須能對回 committed scan group 與 root path | +| `redacted_refs_only` | evidence 只能是脫敏 ref、hash、ticket、commit 或 artifact pointer | +| `secret_value_absent` | 不得出現 Secret value、token、cookie、private key、完整 kubeconfig 或 credential derivative | +| `argocd_health_readback_ref_shape` | ArgoCD health readback 只能是 owner-provided redacted ref | +| `argocd_sync_revision_ref_not_execution` | sync revision ref 只做 rollback / diff 判讀,不得自動 sync | +| `rollback_revision_present` | C0 / C1 回覆都必須有 rollback revision 或明確禁止窗口 | +| `rendered_manifest_diff_ref_not_payload` | rendered manifest diff 只能是 ref,不得貼 manifest payload | +| `maintenance_window_present` | 未來 ArgoCD sync / kubectl action 必須另有維護窗口 | +| `validation_plan_present` | validation plan 必須列 health、rollout、metric、alert 與 rollback post-check | +| `counts_transition_safe` | 只有 reviewer record 可更新 received / accepted / rejected;不得同時開 runtime gate | + +## 5. Outcome Lanes + +| Lane | 意義 | +|------|------| +| `waiting_owner_response` | 尚未收到 owner response;所有 accepted / runtime count 維持 0 | +| `quarantine_raw_payload` | 收到 raw manifest、kubeconfig、Secret value 或不可保存內容時只能隔離 | +| `reject_secret_or_unredacted_manifest` | 出現 secret value、未脫敏 manifest payload 或 credential derivative 時直接拒收 | +| `request_supplement` | 欄位不足、scope 不清、rollback 缺失或 evidence ref 不可追溯時要求補件 | +| `ready_for_rendered_manifest_review` | metadata 合格後,只能進 rendered manifest diff reviewer review | +| `owner_review_only_update` | 只允許更新只讀 owner review ledger | +| `waiting_runtime_gate` | 即使 owner response accepted,runtime gate 仍等待獨立人工批准 | + +## 6. Blocked Actions + +```text +argocd_api_read_without_approval +live_cluster_read_without_approval +argocd_sync +kubectl_apply +kubectl_patch +kubectl_delete +helm_upgrade +secret_value_collection +live_cluster_write +manual_pod_restart +scale_workload +change_network_policy +change_rbac +restore_backup +render_manifest_diff_from_untrusted_payload +mark_owner_response_accepted_without_reviewer_record +open_runtime_gate +add_action_button +``` + +## 7. 指令 + +固定 committed snapshot: + +```bash +python3 scripts/security/k8s-argocd-owner-response-acceptance.py \ + --root . \ + --output docs/security/k8s-argocd-owner-response-acceptance.snapshot.json \ + --generated-at 2026-06-15T00:08:00+08:00 +``` + +只讀 guard: + +```bash +python3 scripts/security/security-mirror-progress-guard.py --root . +python3 scripts/security/source-control-owner-response-guard.py --root . +``` + +## 8. 完成度 + +| 工作 | 完成度 | 說明 | +|------|--------|------| +| owner response acceptance ledger artifact | `100%` | 4 個 scan group 已有只讀收件判定帳本 | +| owner response received / accepted | `0%` | 尚未收到或接受任何 owner response | +| rendered manifest diff / ArgoCD readback | `0%` | 未產生、未接收、未讀 live API | +| ArgoCD sync / kubectl / Helm | `0%` | 未授權且未執行 | +| Secret / live cluster / production write | `0%` | 未讀 Secret value、未寫 cluster | +| runtime gate / production write | `0%` | 無 action button,無 production write | + +## 9. 邊界 + +這份帳本不是 live cluster truth、不是 ArgoCD health readback、不是 ArgoCD sync 批准、不是 `kubectl` 授權、不是 Helm upgrade、不是 Secret collection、不是 RBAC / NetworkPolicy 變更,也不是 restore backup 或 runtime gate。不得把 owner response acceptance ledger、snapshot、LOGBOOK、IwoooS UI 或 AwoooP approval 解讀成可以讀 live cluster、sync ArgoCD、套用 manifest、重啟 Pod、scale workload、讀 secret、寫 production 或開 action button。 diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index 550a5ee7a..730fa69c2 100644 --- a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md +++ b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md @@ -7,7 +7,7 @@ | 本階段完成 | 資安供應鏈 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`;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`;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`;Monitoring / Alerting / Observability Owner Request Draft 已新增 `drafts=60 / write_capable=11 / fields=14 / blocked=24 / sent=0 / runtime=0`;上述全部仍是人工送件前草稿,不是 owner response、live evidence、reload、restart、backup、restore、Telegram send、alert smoke、host write 或 runtime gate | | 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary | @@ -398,6 +398,7 @@ headline 要再往上,需要 S4.9 / S4.10 / S4.11 / S4.12 任一 owner respons | DNS / TLS / certbot Owner Confirmation Request | 本地完成 | `domain-tls-certbot-owner-confirmation-request.snapshot.json` 已固定 `owner_confirmation_request_count=4`、`c0_owner_confirmation_request_count=4`、`required_owner_field_count=9`、`confirmation_question_count=5`、`rejection_guard_count=12`、`owner_response_received_count=0`、`owner_response_accepted_count=0`、`runtime_gate_count=0`,並由 `security-mirror-progress-guard.py` 鎖住 request ids、confirmation questions、rejection guards 與 false flags | 這是 SAN / wildcard / 共用憑證覆蓋關係的 owner confirmation request 草稿,不是 request sent、recipient confirmed、owner response received / accepted、DNS query、TLS probe、certbot renew、Nginx reload、route smoke、host write、production write 或 runtime gate;不需要 production browser smoke | | K8s / ArgoCD manifest repo-only 清冊 | 本地完成 | `k8s-argocd-manifest-inventory.snapshot.json` 已固定 `file_count=49`、`c0_file_count=36`、`yaml_manifest_file_count=45`、`unique_kind_count=20`、`top_level_kind_marker_count=56`、`required_owner_field_count=11`、`evidence_gap_count=8`、`blocked_action_count=13`,並由 `security-mirror-progress-guard.py` 鎖住 group ids、kind counts、blocked actions 與 false flags | 這是 repo-only manifest inventory,不是 live cluster read、ArgoCD API read、ArgoCD sync、kubectl apply / patch / delete、Helm upgrade、secret collection、manual pod restart、scale workload、RBAC / NetworkPolicy change、restore backup、production write 或 runtime gate;不需要 production browser smoke | | K8s / ArgoCD Owner Request Draft | 已推送 / 已同步 | `e8de19d7` 已進 `gitea/main`;`k8s-argocd-owner-request-draft.snapshot.json` 已固定 `request_draft_count=4`、`c0_request_draft_count=3`、`request_field_count=20`、`required_owner_field_count=11`、`evidence_gap_count=8`、`blocked_action_count=13`、`request_sent_count=0`、`owner_response_received_count=0`、`runtime_gate_count=0`,並由 `security-mirror-progress-guard.py` 鎖住 request ids、blocked actions 與 false flags;AwoooP 平行 Session 已同步 | 這是人工送件前 request draft,不是 request sent、recipient confirmed、owner response received / accepted、rendered manifest diff、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、production write 或 runtime gate;不需要 production browser smoke | +| K8s / ArgoCD Owner Response Acceptance | 本地完成 | `k8s-argocd-owner-response-acceptance.snapshot.json` 已固定 `acceptance_candidate_count=4`、`c0_acceptance_candidate_count=3`、`required_owner_field_count=11`、`reviewer_check_count=12`、`outcome_lane_count=7`、`blocked_action_count=18`、`owner_response_received_count=0`、`owner_response_accepted_count=0`、`runtime_gate_count=0`,並由 `security-mirror-progress-guard.py` 鎖住 candidate ids、reviewer checks、outcome lanes、blocked actions 與 false flags | 這是 owner response 收件驗收帳本,不是 owner response received / accepted、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、production write 或 runtime gate;不需要 production browser smoke | | Docker / systemd / Host Service Owner Request Draft | 本地完成 | `host-service-owner-request-draft.snapshot.json` 已固定 `request_draft_count=9`、`write_capable_request_draft_count=3`、`live_evidence_required_request_count=8`、`request_field_count=22`、`required_owner_field_count=12`、`blocked_action_count=14`、`request_sent_count=0`、`owner_response_received_count=0`、`runtime_gate_count=0`,並由 `security-mirror-progress-guard.py` 鎖住 request ids、blocked actions 與 false flags | 這是 Docker Compose、systemd / repair-bot、Ansible role 與 host config backup 的人工送件前 request draft,不是 request sent、owner response received / accepted、live host read、Docker Compose action、systemctl action、repair-bot execution、Ansible apply、secret collection、host write、production write 或 runtime gate;不需要 production browser smoke | | SSH / Firewall / Network Access Owner Request Draft | 本地完成 | `ssh-network-owner-request-draft.snapshot.json` 已固定 `request_draft_count=16`、`write_capable_request_draft_count=6`、`live_evidence_required_request_count=16`、`request_field_count=23`、`required_owner_field_count=13`、`blocked_action_count=16`、`request_sent_count=0`、`owner_response_received_count=0`、`runtime_gate_count=0`,並由 `security-mirror-progress-guard.py` 鎖住 request ids、blocked actions 與 false flags | 這是 SSH target、known_hosts、CI deploy SSH、monitoring SSH、backup SSH、sudoers、NetworkPolicy、NodePort、WireGuard 與 alert SSH action 的人工送件前 request draft,不是 request sent、owner response received / accepted、live host read、host keyscan、known_hosts patch、firewall / port change、NetworkPolicy apply、NodePort change、WireGuard change、secret collection、host write、production write 或 runtime gate;不需要 production browser smoke | | Backup / Restore / Escrow Owner Request Draft | 本地完成 | `backup-restore-owner-request-draft.snapshot.json` 已固定 `request_draft_count=38`、`write_capable_request_draft_count=27`、`live_evidence_required_request_count=38`、`request_field_count=24`、`required_owner_field_count=14`、`blocked_action_count=18`、`request_sent_count=0`、`owner_response_received_count=0`、`runtime_gate_count=0`,並由 `security-mirror-progress-guard.py` 鎖住 request ids、blocked actions 與 false flags | 這是 backup、restore、offsite、credential escrow、retention、Velero、alert / health 與 DR runbook 的人工送件前 request draft,不是 request sent、owner response received / accepted、live backup evidence、backup run、restore run、offsite sync、remote delete、escrow marker write、retention change、restic prune、rclone config、Velero restore / backup、secret collection、host write、production write 或 runtime gate;不需要 production browser smoke | diff --git a/docs/security/high-value-config-control-coverage.snapshot.json b/docs/security/high-value-config-control-coverage.snapshot.json index 75f67fb94..f85e6f5f0 100644 --- a/docs/security/high-value-config-control-coverage.snapshot.json +++ b/docs/security/high-value-config-control-coverage.snapshot.json @@ -85,16 +85,18 @@ "action_buttons_allowed": false, "category_id": "k8s_production_gitops", "control_tier": "C0", - "coverage_percent": 58, - "coverage_status": "gate_defined_needs_runtime_evidence", - "current_gap": "尚未把 ArgoCD health / sync readback 與 rollback revision 收成 owner packet。", + "coverage_percent": 62, + "coverage_status": "owner_response_acceptance_ledger_ready_needs_runtime_evidence", + "current_gap": "已固定 owner response acceptance 只讀帳本;ArgoCD health / sync readback、rollback revision、rendered manifest diff 與 post-deploy validation 仍全部為 0。", "evidence_refs": [ "docs/security/HIGH-VALUE-CONFIG-CHANGE-GATE.md", + "docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/k8s-argocd-owner-response-acceptance.snapshot.json", "k8s/awoooi-prod", "k8s/argocd" ], "label": "K8s / ArgoCD / production manifests", - "next_owner_action": "補 GitOps owner、rollback revision、health readback 與 post-deploy validation plan。", + "next_owner_action": "補 GitOps owner 回覆、rollback revision、health readback、rendered manifest diff 與 post-deploy validation plan。", "owner_response_accepted": false, "owner_response_received": false, "owner_response_required": true, @@ -572,8 +574,8 @@ "websocket_route_change_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-06-14T23:58:00+08:00", - "git_commit": "233ee934", + "generated_at": "2026-06-15T00:08:00+08:00", + "git_commit": "070e9c56", "lowest_coverage_categories": [ { "category_id": "docker_compose_systemd_host_config", @@ -589,19 +591,19 @@ "label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort", "next_owner_action": "補 owner-provided live hash / disposition、host key pinning、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 post-check 指標。" }, - { - "category_id": "k8s_production_gitops", - "coverage_percent": 58, - "current_gap": "尚未把 ArgoCD health / sync readback 與 rollback revision 收成 owner packet。", - "label": "K8s / ArgoCD / production manifests", - "next_owner_action": "補 GitOps owner、rollback revision、health readback 與 post-deploy validation plan。" - }, { "category_id": "backup_restore_credential", "coverage_percent": 58, "current_gap": "repo-only 清冊已納入 38 個 backup / restore / escrow / retention surface;restore drill、offsite sync、credential escrow、retention change、live evidence 與 owner response 仍全部為 0。", "label": "Backup / restore / escrow / retention", "next_owner_action": "補 restore drill approval package、offsite owner、escrow owner、retention owner、rollback owner 與 no-secret-value evidence。" + }, + { + "category_id": "ai_provider_model_routing", + "coverage_percent": 60, + "current_gap": "模型 / provider / Ollama proxy 切換需 dry-run、benchmark、成本與 privacy review;目前不切 production。", + "label": "AI provider / model routing / Ollama proxy / cost and privacy", + "next_owner_action": "補 provider owner、fallback order、cost review、privacy review、benchmark 與 rollback owner。" } ], "next_collection_order": [ diff --git a/docs/security/iwooos-posture-projection.snapshot.json b/docs/security/iwooos-posture-projection.snapshot.json index 68984adde..7b22f59a7 100644 --- a/docs/security/iwooos-posture-projection.snapshot.json +++ b/docs/security/iwooos-posture-projection.snapshot.json @@ -27,6 +27,8 @@ "docs/security/public-gateway-owner-response-acceptance.snapshot.json", "docs/security/PUBLIC-GATEWAY-OWNER-RESPONSE-ACCEPTANCE.md", "docs/schemas/public_gateway_preflight_inventory_v1.schema.json", + "docs/security/k8s-argocd-owner-response-acceptance.snapshot.json", + "docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/domain-tls-certbot-inventory.snapshot.json", "docs/security/DOMAIN-TLS-CERTBOT-INVENTORY.md", "docs/schemas/domain_tls_certbot_inventory_v1.schema.json", diff --git a/docs/security/k8s-argocd-owner-response-acceptance.snapshot.json b/docs/security/k8s-argocd-owner-response-acceptance.snapshot.json new file mode 100644 index 000000000..7411533f2 --- /dev/null +++ b/docs/security/k8s-argocd-owner-response-acceptance.snapshot.json @@ -0,0 +1,705 @@ +{ + "acceptance_candidates": [ + { + "acceptance_candidate_id": "k8s_argocd_owner_response_acceptance:awoooi_prod", + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "group_id", + "root", + "control_tier", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "rendered_manifest_diff_ref", + "maintenance_window", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "action_buttons_allowed": false, + "affected_scope": "pending_owner_response", + "argocd_api_read_authorized": false, + "argocd_api_read_executed": false, + "argocd_health_readback_received": false, + "argocd_health_readback_ref": null, + "argocd_sync_authorized": false, + "argocd_sync_executed": false, + "argocd_sync_revision_ref": null, + "blocked_actions": [ + "argocd_api_read_without_approval", + "live_cluster_read_without_approval", + "argocd_sync", + "kubectl_apply", + "kubectl_patch", + "kubectl_delete", + "helm_upgrade", + "secret_value_collection", + "live_cluster_write", + "manual_pod_restart", + "scale_workload", + "change_network_policy", + "change_rbac", + "restore_backup", + "render_manifest_diff_from_untrusted_payload", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "control_tier": "C0", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "followup_owner": "pending_owner_response", + "group_id": "awoooi_prod", + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "maintenance_window": "pending_owner_response", + "maintenance_window_accepted": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_raw_payload", + "reject_secret_or_unredacted_manifest", + "request_supplement", + "ready_for_rendered_manifest_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "owner_response_accepted": false, + "owner_response_quarantined": false, + "owner_response_received": false, + "owner_response_ref": null, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_response", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "rendered_manifest_diff_candidate": false, + "rendered_manifest_diff_ready": false, + "rendered_manifest_diff_ref": null, + "request_id": "k8s_argocd_owner_request:awoooi_prod", + "request_sent": false, + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "followup_owner", + "maintenance_window", + "validation_plan" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_group", + "redacted_refs_only", + "secret_value_absent", + "argocd_health_readback_ref_shape", + "argocd_sync_revision_ref_not_execution", + "rollback_revision_present", + "rendered_manifest_diff_ref_not_payload", + "maintenance_window_present", + "validation_plan_present", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_owner_response", + "rollback_revision": "pending_owner_response", + "rollback_revision_accepted": false, + "root": "k8s/awoooi-prod", + "runtime_gate": false, + "secret_value_collection_allowed": false, + "status": "waiting_owner_response", + "supplement_requested": false, + "validation_plan": "pending_owner_response" + }, + { + "acceptance_candidate_id": "k8s_argocd_owner_response_acceptance:argocd", + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "group_id", + "root", + "control_tier", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "rendered_manifest_diff_ref", + "maintenance_window", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "action_buttons_allowed": false, + "affected_scope": "pending_owner_response", + "argocd_api_read_authorized": false, + "argocd_api_read_executed": false, + "argocd_health_readback_received": false, + "argocd_health_readback_ref": null, + "argocd_sync_authorized": false, + "argocd_sync_executed": false, + "argocd_sync_revision_ref": null, + "blocked_actions": [ + "argocd_api_read_without_approval", + "live_cluster_read_without_approval", + "argocd_sync", + "kubectl_apply", + "kubectl_patch", + "kubectl_delete", + "helm_upgrade", + "secret_value_collection", + "live_cluster_write", + "manual_pod_restart", + "scale_workload", + "change_network_policy", + "change_rbac", + "restore_backup", + "render_manifest_diff_from_untrusted_payload", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "control_tier": "C0", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "followup_owner": "pending_owner_response", + "group_id": "argocd", + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "maintenance_window": "pending_owner_response", + "maintenance_window_accepted": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_raw_payload", + "reject_secret_or_unredacted_manifest", + "request_supplement", + "ready_for_rendered_manifest_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "owner_response_accepted": false, + "owner_response_quarantined": false, + "owner_response_received": false, + "owner_response_ref": null, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_response", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "rendered_manifest_diff_candidate": false, + "rendered_manifest_diff_ready": false, + "rendered_manifest_diff_ref": null, + "request_id": "k8s_argocd_owner_request:argocd", + "request_sent": false, + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "followup_owner", + "maintenance_window", + "validation_plan" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_group", + "redacted_refs_only", + "secret_value_absent", + "argocd_health_readback_ref_shape", + "argocd_sync_revision_ref_not_execution", + "rollback_revision_present", + "rendered_manifest_diff_ref_not_payload", + "maintenance_window_present", + "validation_plan_present", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_owner_response", + "rollback_revision": "pending_owner_response", + "rollback_revision_accepted": false, + "root": "k8s/argocd", + "runtime_gate": false, + "secret_value_collection_allowed": false, + "status": "waiting_owner_response", + "supplement_requested": false, + "validation_plan": "pending_owner_response" + }, + { + "acceptance_candidate_id": "k8s_argocd_owner_response_acceptance:velero", + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "group_id", + "root", + "control_tier", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "rendered_manifest_diff_ref", + "maintenance_window", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "action_buttons_allowed": false, + "affected_scope": "pending_owner_response", + "argocd_api_read_authorized": false, + "argocd_api_read_executed": false, + "argocd_health_readback_received": false, + "argocd_health_readback_ref": null, + "argocd_sync_authorized": false, + "argocd_sync_executed": false, + "argocd_sync_revision_ref": null, + "blocked_actions": [ + "argocd_api_read_without_approval", + "live_cluster_read_without_approval", + "argocd_sync", + "kubectl_apply", + "kubectl_patch", + "kubectl_delete", + "helm_upgrade", + "secret_value_collection", + "live_cluster_write", + "manual_pod_restart", + "scale_workload", + "change_network_policy", + "change_rbac", + "restore_backup", + "render_manifest_diff_from_untrusted_payload", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "control_tier": "C0", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "followup_owner": "pending_owner_response", + "group_id": "velero", + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "maintenance_window": "pending_owner_response", + "maintenance_window_accepted": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_raw_payload", + "reject_secret_or_unredacted_manifest", + "request_supplement", + "ready_for_rendered_manifest_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "owner_response_accepted": false, + "owner_response_quarantined": false, + "owner_response_received": false, + "owner_response_ref": null, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_response", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "rendered_manifest_diff_candidate": false, + "rendered_manifest_diff_ready": false, + "rendered_manifest_diff_ref": null, + "request_id": "k8s_argocd_owner_request:velero", + "request_sent": false, + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "followup_owner", + "maintenance_window", + "validation_plan" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_group", + "redacted_refs_only", + "secret_value_absent", + "argocd_health_readback_ref_shape", + "argocd_sync_revision_ref_not_execution", + "rollback_revision_present", + "rendered_manifest_diff_ref_not_payload", + "maintenance_window_present", + "validation_plan_present", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_owner_response", + "rollback_revision": "pending_owner_response", + "rollback_revision_accepted": false, + "root": "k8s/velero", + "runtime_gate": false, + "secret_value_collection_allowed": false, + "status": "waiting_owner_response", + "supplement_requested": false, + "validation_plan": "pending_owner_response" + }, + { + "acceptance_candidate_id": "k8s_argocd_owner_response_acceptance:monitoring", + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "group_id", + "root", + "control_tier", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "rendered_manifest_diff_ref", + "maintenance_window", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "action_buttons_allowed": false, + "affected_scope": "pending_owner_response", + "argocd_api_read_authorized": false, + "argocd_api_read_executed": false, + "argocd_health_readback_received": false, + "argocd_health_readback_ref": null, + "argocd_sync_authorized": false, + "argocd_sync_executed": false, + "argocd_sync_revision_ref": null, + "blocked_actions": [ + "argocd_api_read_without_approval", + "live_cluster_read_without_approval", + "argocd_sync", + "kubectl_apply", + "kubectl_patch", + "kubectl_delete", + "helm_upgrade", + "secret_value_collection", + "live_cluster_write", + "manual_pod_restart", + "scale_workload", + "change_network_policy", + "change_rbac", + "restore_backup", + "render_manifest_diff_from_untrusted_payload", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "control_tier": "C1", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "followup_owner": "pending_owner_response", + "group_id": "monitoring", + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "maintenance_window": "pending_owner_response", + "maintenance_window_accepted": false, + "not_approval": true, + "outcome_lanes": [ + "waiting_owner_response", + "quarantine_raw_payload", + "reject_secret_or_unredacted_manifest", + "request_supplement", + "ready_for_rendered_manifest_review", + "owner_review_only_update", + "waiting_runtime_gate" + ], + "owner_response_accepted": false, + "owner_response_quarantined": false, + "owner_response_received": false, + "owner_response_ref": null, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_response", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "rendered_manifest_diff_candidate": false, + "rendered_manifest_diff_ready": false, + "rendered_manifest_diff_ref": null, + "request_id": "k8s_argocd_owner_request:monitoring", + "request_sent": false, + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "followup_owner", + "maintenance_window", + "validation_plan" + ], + "reviewer_checks": [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_group", + "redacted_refs_only", + "secret_value_absent", + "argocd_health_readback_ref_shape", + "argocd_sync_revision_ref_not_execution", + "rollback_revision_present", + "rendered_manifest_diff_ref_not_payload", + "maintenance_window_present", + "validation_plan_present", + "counts_transition_safe" + ], + "reviewer_outcome": "waiting_owner_response", + "rollback_revision": "pending_owner_response", + "rollback_revision_accepted": false, + "root": "k8s/monitoring", + "runtime_gate": false, + "secret_value_collection_allowed": false, + "status": "waiting_owner_response", + "supplement_requested": false, + "validation_plan": "pending_owner_response" + } + ], + "acceptance_fields": [ + "acceptance_candidate_id", + "request_id", + "group_id", + "root", + "control_tier", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "rendered_manifest_diff_ref", + "maintenance_window", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval" + ], + "blocked_actions": [ + "argocd_api_read_without_approval", + "live_cluster_read_without_approval", + "argocd_sync", + "kubectl_apply", + "kubectl_patch", + "kubectl_delete", + "helm_upgrade", + "secret_value_collection", + "live_cluster_write", + "manual_pod_restart", + "scale_workload", + "change_network_policy", + "change_rbac", + "restore_backup", + "render_manifest_diff_from_untrusted_payload", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button" + ], + "execution_boundaries": { + "action_buttons_allowed": false, + "argocd_api_read_authorized": false, + "argocd_api_read_executed": false, + "argocd_sync_authorized": false, + "argocd_sync_executed": false, + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "not_authorization": true, + "owner_response_accepted": false, + "production_write_authorized": false, + "rendered_manifest_diff_ready": false, + "request_dispatch_authorized": false, + "runtime_execution_authorized": false, + "secret_value_collection_allowed": false + }, + "generated_at": "2026-06-15T00:08:00+08:00", + "git_commit": "070e9c56", + "next_steps": [ + "等待 owner response;未收到前不得更新 accepted count。", + "收到回覆後先走 raw payload / secret / scope / rollback / evidence ref 檢查,不合格即隔離、拒收或補件。", + "metadata 合格也只能進 rendered manifest diff reviewer review;ArgoCD API read、sync、kubectl action、secret collection 與 production write 仍需獨立人工批准。" + ], + "outcome_lanes": [ + { + "lane_id": "waiting_owner_response", + "meaning": "尚未收到 owner response;所有 accepted / runtime count 維持 0。" + }, + { + "lane_id": "quarantine_raw_payload", + "meaning": "收到 raw manifest、kubeconfig、Secret value 或不可保存內容時只能隔離。" + }, + { + "lane_id": "reject_secret_or_unredacted_manifest", + "meaning": "出現 secret value、未脫敏 manifest payload 或 credential derivative 時直接拒收。" + }, + { + "lane_id": "request_supplement", + "meaning": "欄位不足、scope 不清、rollback 缺失或 evidence ref 不可追溯時要求補件。" + }, + { + "lane_id": "ready_for_rendered_manifest_review", + "meaning": "metadata 合格後,只能進 rendered manifest diff reviewer review。" + }, + { + "lane_id": "owner_review_only_update", + "meaning": "只允許更新只讀 owner review ledger,不得改 K8s、ArgoCD、Helm 或 secret。" + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "即使 owner response accepted,runtime gate 仍等待獨立人工批准。" + } + ], + "required_owner_fields": [ + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "followup_owner", + "maintenance_window", + "validation_plan" + ], + "reviewer_checks": [ + { + "check_id": "owner_identity_present", + "instruction": "owner role / team 必須可追溯,不能只寫聊天同意或模糊職稱。" + }, + { + "check_id": "decision_reason_present", + "instruction": "decision 與 decision reason 必須同時存在,且不得包含機敏值。" + }, + { + "check_id": "affected_scope_matches_group", + "instruction": "affected scope 必須能對回 committed scan group 與 root path。" + }, + { + "check_id": "redacted_refs_only", + "instruction": "evidence 只能是脫敏 ref、hash、ticket、commit 或 artifact pointer。" + }, + { + "check_id": "secret_value_absent", + "instruction": "不得出現 Secret value、token、cookie、private key、完整 kubeconfig 或 credential derivative。" + }, + { + "check_id": "argocd_health_readback_ref_shape", + "instruction": "ArgoCD health readback 只能是 owner-provided redacted ref,不得觸發 live API read。" + }, + { + "check_id": "argocd_sync_revision_ref_not_execution", + "instruction": "sync revision ref 只做 rollback / diff 判讀,不得自動 sync。" + }, + { + "check_id": "rollback_revision_present", + "instruction": "C0 / C1 回覆都必須有 rollback revision 或明確禁止窗口。" + }, + { + "check_id": "rendered_manifest_diff_ref_not_payload", + "instruction": "rendered manifest diff 只能是 ref,不得把 manifest payload 貼入回覆。" + }, + { + "check_id": "maintenance_window_present", + "instruction": "任何未來 ArgoCD sync / kubectl action 都必須另有維護窗口。" + }, + { + "check_id": "validation_plan_present", + "instruction": "validation plan 必須列 health、rollout、metric、alert 與 rollback post-check。" + }, + { + "check_id": "counts_transition_safe", + "instruction": "只有 reviewer record 可更新 received / accepted / rejected;不得同時開 runtime gate。" + } + ], + "schema_version": "k8s_argocd_owner_response_acceptance_v1", + "source_inventory_schema_version": "k8s_argocd_manifest_inventory_v1", + "source_inventory_status": "repo_only_inventory_ready_no_live_cluster_read", + "source_owner_request_schema_version": "k8s_argocd_owner_request_draft_v1", + "source_owner_request_status": "owner_request_draft_ready_not_dispatched", + "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "summary": { + "acceptance_candidate_count": 4, + "acceptance_field_count": 20, + "action_button_count": 0, + "argocd_api_read_authorized_count": 0, + "argocd_api_read_executed_count": 0, + "argocd_health_readback_received_count": 0, + "argocd_sync_authorized_count": 0, + "argocd_sync_executed_count": 0, + "blocked_action_count": 18, + "c0_acceptance_candidate_count": 3, + "c1_acceptance_candidate_count": 1, + "kubectl_action_authorized_count": 0, + "kubectl_action_executed_count": 0, + "live_cluster_read_authorized_count": 0, + "live_cluster_read_executed_count": 0, + "maintenance_window_accepted_count": 0, + "outcome_lane_count": 7, + "owner_response_accepted_count": 0, + "owner_response_quarantined_count": 0, + "owner_response_received_count": 0, + "owner_response_rejected_count": 0, + "recipient_confirmed_count": 0, + "rendered_manifest_diff_candidate_count": 0, + "rendered_manifest_diff_ready_count": 0, + "request_sent_count": 0, + "required_owner_field_count": 11, + "reviewer_check_count": 12, + "rollback_revision_accepted_count": 0, + "runtime_gate_count": 0, + "secret_value_collection_allowed_count": 0, + "source_request_draft_count": 4, + "source_scan_group_count": 4, + "supplement_requested_count": 0 + } +} 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 352fb1e48..ed56f5d11 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 @@ -696,6 +696,7 @@ Alert / Sentry / SigNoz / Gitea / Market Watch / Operator | `docs/security/domain-tls-certbot-owner-confirmation-request.snapshot.json` + `scripts/security/domain-tls-certbot-owner-confirmation-request.py` | DNS / TLS / certbot Owner Confirmation Request 已本地完成;承接 domain / TLS / certbot repo-only 清冊,固定 4 份 owner confirmation request、4 份 C0、9 欄 required owner fields、16 欄 request fields、5 題 confirmation questions 與 12 類 rejection guard;request sent、recipient confirmed、owner response received / accepted、DNS query、TLS probe、certbot renew、Nginx reload、runtime gate、action buttons 仍全部為 `0` | 這是 SAN / wildcard / 共用憑證覆蓋關係的 owner confirmation request 草稿,不是 request sent、owner response received / accepted、DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、host write、production write 或 runtime gate | | `docs/security/k8s-argocd-manifest-inventory.snapshot.json` + `scripts/security/k8s-argocd-manifest-inventory.py` | K8s / ArgoCD manifest repo-only 清冊已本地完成;掃描 `k8s/awoooi-prod`、`k8s/argocd`、`k8s/velero`、`k8s/monitoring`,固定 4 個 scan groups、49 個 files、36 個 C0 files、45 個 YAML manifests、20 個 unique top-level kind markers、11 欄 required owner fields、8 個 evidence gaps 與 13 類 blocked action;owner response、rendered manifest diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、runtime gate、action buttons 仍全部為 `0` | 這是 repo-only manifest inventory,不是 live cluster read、ArgoCD API read、ArgoCD sync、kubectl apply / patch / delete、Helm upgrade、secret collection、manual pod restart、scale workload、RBAC / NetworkPolicy change、restore backup、production write 或 runtime gate | | `docs/security/k8s-argocd-owner-request-draft.snapshot.json` + `scripts/security/k8s-argocd-owner-request-draft.py` | K8s / ArgoCD Owner Request Draft 已本地完成;承接 manifest repo-only 清冊,固定 4 份 request draft、3 份 C0、1 份 C1、20 欄 request fields、11 欄 required owner fields、8 個 evidence gaps 與 13 類 blocked action;request sent、recipient confirmed、owner response received / accepted、rendered manifest diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、runtime gate、action buttons 仍全部為 `0` | 這是人工送件前 request draft,不是 request sent、owner response received / accepted、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、production write 或 runtime gate | +| `docs/security/k8s-argocd-owner-response-acceptance.snapshot.json` + `scripts/security/k8s-argocd-owner-response-acceptance.py` | K8s / ArgoCD Owner Response Acceptance 只讀帳本已本地完成;承接 manifest inventory 與 owner request draft,固定 4 份 acceptance candidate、3 份 C0、1 份 C1、20 欄 acceptance field、11 欄 required owner field、12 個 reviewer check、7 條 outcome lane 與 18 類 blocked action;owner response received / accepted、rendered manifest diff、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate、action buttons 仍全部為 `0` | 這是 owner response 收件驗收帳本,不是 owner response received / accepted、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、production write 或 runtime gate | | `docs/security/host-service-owner-request-draft.snapshot.json` + `scripts/security/host-service-owner-request-draft.py` | Docker / systemd / Host Service Owner Request Draft 已本地完成;承接 host-service repo-only 清冊,固定 9 份 request draft、3 份 write-capable request draft、8 份需 live evidence request、22 欄 request fields、12 欄 required owner fields 與 14 類 blocked action;request sent、recipient confirmed、owner response received / accepted、live evidence、restart window、rollback owner、host write、runtime gate、action buttons 仍全部為 `0` | 這是人工送件前 request draft,不是 request sent、owner response received / accepted、live host read、Docker Compose action、systemctl action、repair-bot execution、Ansible apply、secret collection、host write、production write 或 runtime gate | | `docs/security/ssh-network-owner-request-draft.snapshot.json` + `scripts/security/ssh-network-owner-request-draft.py` | SSH / Firewall / Network Access Owner Request Draft 已本地完成;承接 SSH / network repo-only 清冊,固定 16 份 request draft、6 份 write-capable request draft、16 份需 live evidence request、23 欄 request fields、13 欄 required owner fields 與 16 類 blocked action;request sent、recipient confirmed、owner response received / accepted、live access state、firewall / port change、NetworkPolicy apply、NodePort change、WireGuard change、host write、runtime gate、action buttons 仍全部為 `0` | 這是人工送件前 request draft,不是 request sent、owner response received / accepted、live host read、host keyscan、known_hosts patch、firewall / port change、NetworkPolicy apply、NodePort change、WireGuard change、secret collection、host write、production write 或 runtime gate | | `docs/security/backup-restore-owner-request-draft.snapshot.json` + `scripts/security/backup-restore-owner-request-draft.py` | Backup / Restore / Escrow Owner Request Draft 已本地完成;承接 backup / restore repo-only 清冊,固定 38 份 request draft、27 份 write-capable request draft、38 份需 live evidence request、24 欄 request fields、14 欄 required owner fields 與 18 類 blocked action;request sent、recipient confirmed、owner response received / accepted、live backup evidence、backup run、restore run、offsite sync、escrow marker write、retention change、runtime gate、action buttons 仍全部為 `0` | 這是人工送件前 request draft,不是 request sent、owner response received / accepted、backup run、restore run、offsite sync、remote delete、credential escrow marker write、retention change、restic prune、rclone config、Velero restore / backup、secret collection、host write、production write 或 runtime gate | @@ -853,6 +854,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 82. 建立 Monitoring / Alerting / Observability Owner Request Draft。✅ 本地完成;新增 `monitoring-owner-request-draft.py`、snapshot 與說明文件,將 60 個 monitoring / alerting / observability surface 轉成 `request_draft_count=60`、`write_capable_request_draft_count=11`、`live_evidence_required_request_count=60`、`request_field_count=24`、`required_owner_field_count=14`、`blocked_action_count=24` 的人工送件前草稿;request sent、recipient confirmed、owner response received / accepted、live evidence、Prometheus reload、Alertmanager reload、Grafana import、SigNoz apply、Sentry deploy、Langfuse change、OTEL reload、receiver route change、silence change、Telegram send、live alert fire、alert chain smoke、secret collection、host write、runtime gate、action buttons 仍全部為 `0`。這不是 request sent、owner response received / accepted、reload、deploy、receiver route change、silence change、Telegram send、alert chain smoke、host write、production write 或 runtime gate。 83. 建立 agent-bounty-protocol Owner Request Draft。✅ 本地完成;新增 `agent-bounty-owner-request-draft.py`、snapshot 與說明文件,將 repo / refs、deployment、data classification、MCP / A2A、cron / daemon、admin / treasury、webhook / traffic 轉成 `request_draft_count=11`、`control_boundary_request_count=4`、`product_surface_request_count=7`、`write_capable_request_draft_count=8`、`treasury_related_request_draft_count=4`、`mcp_a2a_related_request_draft_count=5`、`required_owner_field_count=22`、`forbidden_input_count=25`、`blocked_action_count=28` 的人工送件前草稿;request sent、recipient confirmed、owner response received / accepted、repo push、refs sync、workflow 修改、secret collection、deploy、compose restart、DB migration、claim / submit、payout / withdrawal、cron / daemon、external send、host write、runtime gate、action buttons 仍全部為 `0`。這不是 request sent、owner response received / accepted、repo / refs / workflow action、deployment、MCP / A2A runtime、financial action、production write 或 runtime gate。 84. 建立 Public Gateway Owner Response Acceptance 只讀帳本。✅ 本地完成;新增 `public-gateway-owner-response-acceptance.py`、snapshot 與說明文件,將 live conf export、redacted export intake 與 rendered diff / `nginx -t` gate 草稿串成 `acceptance_candidate_count=3`、`c0_acceptance_candidate_count=2`、`required_owner_response_field_count=12`、`reviewer_check_count=12`、`outcome_lane_count=7`、`blocked_action_count=18` 的 owner response acceptance ledger;owner response received / accepted、redacted export、rendered diff、`nginx -t`、reload、route smoke、DNS / TLS probe、certbot renew、runtime gate、action buttons 仍全部為 `0`。這不是 owner response received / accepted、live gateway truth、rendered diff ready、`nginx -t`、Nginx reload、DNS / TLS probe、certbot renew、host write、production write 或 runtime gate。 +85. 建立 K8s / ArgoCD Owner Response Acceptance 只讀帳本。✅ 本地完成;新增 `k8s-argocd-owner-response-acceptance.py`、snapshot 與說明文件,將 manifest inventory 與 owner request draft 串成 `acceptance_candidate_count=4`、`c0_acceptance_candidate_count=3`、`required_owner_field_count=11`、`reviewer_check_count=12`、`outcome_lane_count=7`、`blocked_action_count=18` 的 owner response acceptance ledger;owner response received / accepted、rendered manifest diff、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate、action buttons 仍全部為 `0`。這不是 owner response received / accepted、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、production write 或 runtime gate。 #### 3.2.1d 2026-06-11 Agent 互動、學習與成長證據面 @@ -4830,6 +4832,19 @@ Trigger commit `f5cd37b7` 與 deploy marker `0ba92357` 已把 governance UI 的 **裁決:** 這是人工送件前 request draft,不是 request sent、recipient confirmed、owner response received / accepted、live evidence、Prometheus reload、Alertmanager reload、Grafana import、SigNoz apply、Sentry deploy、Langfuse change、OTEL reload、receiver route change、silence change、Telegram send、live alert fire、alert chain smoke、secret collection、host write、active scan、production write 或 runtime gate;IwoooS headline 仍維持 `64%`,active runtime gate 仍 `0`。 +### 2026-06-15 00:08 (台北) — §3.2 / §5 — 新增 K8s / ArgoCD Owner Response Acceptance 只讀帳本 — 把 GitOps owner 回覆收件驗收固定成可 guard artifact + +**觸發**:K8s / ArgoCD / Velero / monitoring manifests 屬於 P0 GitOps 風險面,任何 ArgoCD sync、kubectl action、secret collection、RBAC / NetworkPolicy change 或 restore backup 都可能影響 production。既有 manifest inventory 與 owner request draft 已完成,但仍缺 owner response acceptance ledger,防止未驗收回覆被誤判成 live cluster read、sync 或 kubectl 授權。 + +**已推進:** +- 新增 `scripts/security/k8s-argocd-owner-response-acceptance.py`,讀取 manifest inventory 與 owner request draft 兩份 snapshot,產生 4 份 owner response acceptance candidate。 +- 新增 `docs/security/k8s-argocd-owner-response-acceptance.snapshot.json`,固定 `acceptance_candidate_count=4`、`c0_acceptance_candidate_count=3`、`c1_acceptance_candidate_count=1`、`required_owner_field_count=11`、`reviewer_check_count=12`、`outcome_lane_count=7`、`blocked_action_count=18`。 +- 新增 `docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md`,說明 owner 必填欄位、reviewer checks、outcome lanes、blocked actions、完成度與 0 / false 邊界。 +- `security-mirror-progress-guard.py` 已鎖住新 snapshot 的 schema、summary、execution false flags、candidate ids、reviewer checks、outcome lanes、blocked actions 與每份候選 false flags。 +- 高價值配置 coverage、IwoooS 配置控管總清單、P0 主控板、供應鏈進度與 MASTER artifact 表已同步 P0-25;`k8s_production_gitops` 只讀治理成熟度從 `58%` 推進到 `62%`,但 runtime gate 仍為 `0`。 + +**裁決:** 這是 owner response acceptance 只讀帳本,不是 owner response received / accepted、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、host write、active scan、production write 或 runtime gate;IwoooS headline 仍維持 `64%`,active runtime gate 仍 `0`。 + ### 2026-06-14 23:58 (台北) — §3.2 / §5 — 新增 Public Gateway Owner Response Acceptance 只讀帳本 — 把 Nginx owner 回覆收件驗收固定成可 guard artifact **觸發**:Nginx public gateway 是 C0 公開入口配置,手改 live conf 會直接影響網站、admin route、API、WebSocket、TLS 與 ACME。既有 live conf export、redacted export intake 與 rendered diff gate 已完成,但還缺一個明確的 owner response acceptance ledger,防止把未驗收回覆誤判成 `nginx -t`、reload 或 route smoke 授權。 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 5e163d2d5..6e2efc805 100644 --- a/docs/workplans/2026-06-04-iwooos-security-governance-p0.md +++ b/docs/workplans/2026-06-04-iwooos-security-governance-p0.md @@ -21,7 +21,7 @@ | 最新 P2-D2 Code Review 候選分類基準 | code `292cfec9`、deploy marker `4cfe5ff7`、CD `2586`、code-review `2587`;Code Review route 可見文案已搬到 `codeReview` i18n namespace,四類候選分類與人工批准流程已正式驗證 | | 最新 P2-D2 AwoooP Runs fallback 文案基準 | code `7f6028c3`、deploy marker `bf016e91`、CD `2590`、code-review `2591`;Runs / Callback / Source Flow fallback 文案已正式驗證 | | 最新 AwoooP Tenants 全域產品資產台帳 D1 基準 | code `fef94df8`、deploy marker `180a6543`、code-review `2967`、CD `2966`;正式 API 顯示產品 / 專案 `16`、網站 / 服務入口 `31`、source-control candidate repo `10`,已納入 `2026fifa.wooo.work`、WOOO Open Design、n8n、Grist、Vault、Ollama、Monitor 與 AWOOOI API / AIOps 服務入口;owner response / runtime gate / action button 仍 `0` | -| 最新 P0 Public Gateway / DNS TLS / K8s 配置控管基準 | P0-15 `5068654d` live conf 匯出請求包、P0-16 `f856df1c` redacted export 收件預檢、P0-17 `762f73a6` rendered diff / nginx gate 草稿、P0-19 `551d8144` DNS / TLS / certbot owner confirmation request 草稿、P0-20 `e8876c45` K8s / ArgoCD manifest repo-only 清冊、P0-21 `e8de19d7` K8s / ArgoCD owner request draft;本輪新增 P0-24 Public Gateway owner response acceptance 只讀帳本;Public Gateway 四段固定 requests / candidates `3`、C0 `2`、owner response acceptance fields `12`、reviewer checks `12`、outcome lanes `7`,DNS / TLS 固定 owner confirmation requests `4`、C0 `4`,K8s manifest 固定 files `49`、C0 `36`、YAML `45`、kinds `20`,K8s owner request 固定 drafts `4`、C0 `3`;request sent、owner response received / accepted、redacted export received / accepted、raw conf stored、rendered diff ready、`nginx -t`、reload、DNS query、TLS probe、certbot renew、ArgoCD sync、kubectl action、route smoke、runtime gate、action button 全部 `0` | +| 最新 P0 Public Gateway / DNS TLS / K8s 配置控管基準 | P0-15 `5068654d` live conf 匯出請求包、P0-16 `f856df1c` redacted export 收件預檢、P0-17 `762f73a6` rendered diff / nginx gate 草稿、P0-19 `551d8144` DNS / TLS / certbot owner confirmation request 草稿、P0-20 `e8876c45` K8s / ArgoCD manifest repo-only 清冊、P0-21 `e8de19d7` K8s / ArgoCD owner request draft;本輪新增 P0-24 Public Gateway owner response acceptance 只讀帳本與 P0-25 K8s / ArgoCD owner response acceptance 只讀帳本;Public Gateway 四段固定 requests / candidates `3`、C0 `2`、owner response acceptance fields `12`、reviewer checks `12`、outcome lanes `7`,DNS / TLS 固定 owner confirmation requests `4`、C0 `4`,K8s manifest 固定 files `49`、C0 `36`、YAML `45`、kinds `20`,K8s owner request 固定 drafts `4`、C0 `3`,K8s owner response acceptance 固定 candidates `4`、C0 `3`、reviewer checks `12`、outcome lanes `7`;request sent、owner response received / accepted、redacted export received / accepted、raw conf stored、rendered diff ready、`nginx -t`、reload、DNS query、TLS probe、certbot renew、ArgoCD API read、ArgoCD sync、kubectl action、route smoke、runtime gate、action button 全部 `0` | | 最新 P0 agent-bounty-protocol 配置控管基準 | onboarding handoff 已固定 `product_scope_handoff_only`、owner response / runtime gate 全部 `false`;本輪新增 owner request draft,固定 `drafts=11`、`control=4`、`surface=7`、`write_capable=8`、`treasury=4`、`mcp_a2a=5`、`owner_fields=22`、`forbidden_inputs=25`、`blocked_actions=28`、request sent / received / accepted / repo push / refs sync / deploy / claim / submit / payout / daemon / cron / runtime gate 全部 `0` | | 最新 P1 Docker / systemd / Host Service 配置控管基準 | repo-only inventory 已固定 `surface=9`、`write_capable=3`、`live_evidence_required=8`、成熟度 `42% -> 50%`;本輪新增 owner request draft,固定 `drafts=9`、`owner_fields=12`、`blocked_actions=14`、request sent / received / accepted / live evidence / restart window / rollback owner / host write / runtime gate 全部 `0` | | 最新 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` | @@ -93,6 +93,7 @@ | P0-19 | DNS / TLS / certbot owner confirmation request | 100% | 已新增 `domain-tls-certbot-owner-confirmation-request.py`、snapshot 與文件,把 4 個 certificate path 需確認 domain 轉成 owner confirmation request 草稿;全部 `C0`,必填 owner 欄位 `9`,confirmation questions `5`,rejection guards `12`;request sent、recipient confirmed、owner response received / accepted、DNS query、TLS probe、certbot renew、Nginx reload、host write、runtime gate 仍全部為 `0` | `DOMAIN_TLS_CERTBOT_OWNER_CONFIRMATION_REQUEST_OK requests=4 c0=4 fields=9 received=0 runtime_gate=0`;progress guard 固定 snapshot schema、summary、false flags、request ids、confirmation questions、rejection guards 與每份草稿 false flags;純 repo 內文件 / snapshot / guard,不需要 production browser smoke | | 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-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 規範 @@ -311,6 +312,7 @@ P1 只讀重盤階段整體完成度:`70%`。它代表 freshness / inventory / | P1-13 | Monitoring / Alerting / Observability owner request draft | 已新增 `MONITORING-OWNER-REQUEST-DRAFT.md`、`monitoring-owner-request-draft.snapshot.json` 與產生器;60 個 surface、11 個 write-capable、60 個需 live evidence、14 個 owner 必填欄位、24 類 blocked action | 草稿 artifact `100%`;request sent / received / accepted、live evidence、Prometheus / Alertmanager reload、receiver route change、silence change、Telegram send、alert chain smoke、runtime gate 仍全部 `0 / false` | | P0-23 | agent-bounty-protocol owner request draft | 已新增 `AGENT-BOUNTY-OWNER-REQUEST-DRAFT.md`、`agent-bounty-owner-request-draft.snapshot.json` 與產生器;11 份 request draft、4 份 control boundary、7 份 product surface、8 份 write-capable、4 份 treasury-related、5 份 MCP / A2A-related、22 個 owner 必填欄位、25 類 forbidden input、28 類 blocked action | 草稿 artifact `100%`;request sent / received / accepted、repo push、refs sync、workflow change、secret collection、deploy、compose restart、DB migration、claim / submit、payout / withdrawal、cron / daemon、host write、runtime gate 仍全部 `0 / false` | | P0-24 | Public Gateway owner response acceptance 只讀帳本 | 已新增 `PUBLIC-GATEWAY-OWNER-RESPONSE-ACCEPTANCE.md`、`public-gateway-owner-response-acceptance.snapshot.json` 與產生器;3 份 acceptance candidate、2 份 C0、12 個 owner 必填欄位、12 個 reviewer checks、7 條 outcome lanes、18 類 blocked action | 帳本 artifact `100%`;owner response received / accepted、redacted export、rendered diff、`nginx -t`、reload、route smoke、DNS / TLS probe、certbot renew、host write、runtime gate 仍全部 `0 / false` | +| P0-25 | K8s / ArgoCD owner response acceptance 只讀帳本 | 已新增 `K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md`、`k8s-argocd-owner-response-acceptance.snapshot.json` 與產生器;4 份 acceptance candidate、3 份 C0、11 個 owner 必填欄位、12 個 reviewer checks、7 條 outcome lanes、18 類 blocked action | 帳本 artifact `100%`;owner response received / accepted、rendered manifest diff、ArgoCD API read、ArgoCD sync、kubectl action、live cluster read、secret collection、host write、runtime gate 仍全部 `0 / false` | ## 7. 2026-06-04 本輪驗證紀錄 diff --git a/scripts/security/high-value-config-control-coverage.py b/scripts/security/high-value-config-control-coverage.py index 1c416c069..a4e132ede 100644 --- a/scripts/security/high-value-config-control-coverage.py +++ b/scripts/security/high-value-config-control-coverage.py @@ -50,15 +50,17 @@ CONTROL_STATUS_BY_CATEGORY = { "next_owner_action": "確認 SAN / 共用憑證關係、renewal owner、ACME smoke 與 rollback owner。", }, "k8s_production_gitops": { - "coverage_status": "gate_defined_needs_runtime_evidence", - "coverage_percent": 58, + "coverage_status": "owner_response_acceptance_ledger_ready_needs_runtime_evidence", + "coverage_percent": 62, "evidence_refs": [ "docs/security/HIGH-VALUE-CONFIG-CHANGE-GATE.md", + "docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/k8s-argocd-owner-response-acceptance.snapshot.json", "k8s/awoooi-prod", "k8s/argocd", ], - "current_gap": "尚未把 ArgoCD health / sync readback 與 rollback revision 收成 owner packet。", - "next_owner_action": "補 GitOps owner、rollback revision、health readback 與 post-deploy validation plan。", + "current_gap": "已固定 owner response acceptance 只讀帳本;ArgoCD health / sync readback、rollback revision、rendered manifest diff 與 post-deploy validation 仍全部為 0。", + "next_owner_action": "補 GitOps owner 回覆、rollback revision、health readback、rendered manifest diff 與 post-deploy validation plan。", }, "secret_metadata": { "coverage_status": "metadata_policy_ready", @@ -307,6 +309,7 @@ def build_report(root: Path, generated_at: str | None) -> dict[str, Any]: "repo_only_inventory_ready_needs_live_route_evidence", "repo_only_preflight_contract_ready_needs_owner_live_diff", "owner_response_acceptance_ledger_ready_needs_owner_live_diff", + "owner_response_acceptance_ledger_ready_needs_runtime_evidence", "policy_ready_needs_drift_evidence", "inventory_needed", "repo_only_inventory_ready_needs_live_owner_evidence", diff --git a/scripts/security/k8s-argocd-owner-response-acceptance.py b/scripts/security/k8s-argocd-owner-response-acceptance.py new file mode 100644 index 000000000..af39e27d0 --- /dev/null +++ b/scripts/security/k8s-argocd-owner-response-acceptance.py @@ -0,0 +1,358 @@ +#!/usr/bin/env python3 +""" +IwoooS K8s / ArgoCD owner response acceptance 只讀帳本產生器。 + +本工具讀取 K8s / ArgoCD manifest inventory 與 owner request draft,建立未來 +owner response 如何收件、補件、隔離、拒收或進 rendered manifest review 的 +metadata-only acceptance ledger。它不讀 live cluster、不呼叫 ArgoCD API、不 +sync、不執行 kubectl、不套用 manifest、不讀 secret value。 +""" + +from __future__ import annotations + +import argparse +import json +import subprocess +import sys +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Any + + +TAIPEI = timezone(timedelta(hours=8)) + +ACCEPTANCE_FIELDS = [ + "acceptance_candidate_id", + "request_id", + "group_id", + "root", + "control_tier", + "owner_response_ref", + "owner_role_or_team", + "decision", + "decision_reason", + "affected_scope", + "redacted_evidence_refs", + "argocd_health_readback_ref", + "argocd_sync_revision_ref", + "rollback_revision", + "rendered_manifest_diff_ref", + "maintenance_window", + "validation_plan", + "reviewer_outcome", + "followup_owner", + "not_approval", +] + +REVIEWER_CHECKS = [ + { + "check_id": "owner_identity_present", + "instruction": "owner role / team 必須可追溯,不能只寫聊天同意或模糊職稱。", + }, + { + "check_id": "decision_reason_present", + "instruction": "decision 與 decision reason 必須同時存在,且不得包含機敏值。", + }, + { + "check_id": "affected_scope_matches_group", + "instruction": "affected scope 必須能對回 committed scan group 與 root path。", + }, + { + "check_id": "redacted_refs_only", + "instruction": "evidence 只能是脫敏 ref、hash、ticket、commit 或 artifact pointer。", + }, + { + "check_id": "secret_value_absent", + "instruction": "不得出現 Secret value、token、cookie、private key、完整 kubeconfig 或 credential derivative。", + }, + { + "check_id": "argocd_health_readback_ref_shape", + "instruction": "ArgoCD health readback 只能是 owner-provided redacted ref,不得觸發 live API read。", + }, + { + "check_id": "argocd_sync_revision_ref_not_execution", + "instruction": "sync revision ref 只做 rollback / diff 判讀,不得自動 sync。", + }, + { + "check_id": "rollback_revision_present", + "instruction": "C0 / C1 回覆都必須有 rollback revision 或明確禁止窗口。", + }, + { + "check_id": "rendered_manifest_diff_ref_not_payload", + "instruction": "rendered manifest diff 只能是 ref,不得把 manifest payload 貼入回覆。", + }, + { + "check_id": "maintenance_window_present", + "instruction": "任何未來 ArgoCD sync / kubectl action 都必須另有維護窗口。", + }, + { + "check_id": "validation_plan_present", + "instruction": "validation plan 必須列 health、rollout、metric、alert 與 rollback post-check。", + }, + { + "check_id": "counts_transition_safe", + "instruction": "只有 reviewer record 可更新 received / accepted / rejected;不得同時開 runtime gate。", + }, +] + +OUTCOME_LANES = [ + { + "lane_id": "waiting_owner_response", + "meaning": "尚未收到 owner response;所有 accepted / runtime count 維持 0。", + }, + { + "lane_id": "quarantine_raw_payload", + "meaning": "收到 raw manifest、kubeconfig、Secret value 或不可保存內容時只能隔離。", + }, + { + "lane_id": "reject_secret_or_unredacted_manifest", + "meaning": "出現 secret value、未脫敏 manifest payload 或 credential derivative 時直接拒收。", + }, + { + "lane_id": "request_supplement", + "meaning": "欄位不足、scope 不清、rollback 缺失或 evidence ref 不可追溯時要求補件。", + }, + { + "lane_id": "ready_for_rendered_manifest_review", + "meaning": "metadata 合格後,只能進 rendered manifest diff reviewer review。", + }, + { + "lane_id": "owner_review_only_update", + "meaning": "只允許更新只讀 owner review ledger,不得改 K8s、ArgoCD、Helm 或 secret。", + }, + { + "lane_id": "waiting_runtime_gate", + "meaning": "即使 owner response accepted,runtime gate 仍等待獨立人工批准。", + }, +] + +BLOCKED_ACTIONS = [ + "argocd_api_read_without_approval", + "live_cluster_read_without_approval", + "argocd_sync", + "kubectl_apply", + "kubectl_patch", + "kubectl_delete", + "helm_upgrade", + "secret_value_collection", + "live_cluster_write", + "manual_pod_restart", + "scale_workload", + "change_network_policy", + "change_rbac", + "restore_backup", + "render_manifest_diff_from_untrusted_payload", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", +] + + +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 acceptance_candidate(request: dict[str, Any]) -> dict[str, Any]: + group_id = request["group_id"] + return { + "acceptance_candidate_id": f"k8s_argocd_owner_response_acceptance:{group_id}", + "status": "waiting_owner_response", + "request_id": request["request_id"], + "group_id": group_id, + "root": request["root"], + "control_tier": request["control_tier"], + "owner_response_ref": None, + "owner_role_or_team": "pending_owner_response", + "decision": "pending_owner_response", + "decision_reason": "pending_owner_response", + "affected_scope": "pending_owner_response", + "redacted_evidence_refs": [], + "argocd_health_readback_ref": None, + "argocd_sync_revision_ref": None, + "rollback_revision": "pending_owner_response", + "rendered_manifest_diff_ref": None, + "maintenance_window": "pending_owner_response", + "validation_plan": "pending_owner_response", + "reviewer_outcome": "waiting_owner_response", + "followup_owner": "pending_owner_response", + "acceptance_fields": ACCEPTANCE_FIELDS, + "required_owner_fields": request["required_owner_fields"], + "reviewer_checks": [item["check_id"] for item in REVIEWER_CHECKS], + "outcome_lanes": [item["lane_id"] for item in OUTCOME_LANES], + "blocked_actions": BLOCKED_ACTIONS, + "not_approval": True, + "request_sent": False, + "recipient_confirmed": False, + "owner_response_received": False, + "owner_response_accepted": False, + "owner_response_rejected": False, + "owner_response_quarantined": False, + "supplement_requested": False, + "rendered_manifest_diff_candidate": False, + "rendered_manifest_diff_ready": False, + "argocd_health_readback_received": False, + "argocd_api_read_authorized": False, + "argocd_api_read_executed": False, + "argocd_sync_authorized": False, + "argocd_sync_executed": False, + "kubectl_action_authorized": False, + "kubectl_action_executed": False, + "live_cluster_read_authorized": False, + "live_cluster_read_executed": False, + "secret_value_collection_allowed": False, + "maintenance_window_accepted": False, + "rollback_revision_accepted": False, + "production_write_authorized": False, + "runtime_gate": False, + "action_buttons_allowed": False, + } + + +def build_report( + root: Path, + inventory: dict[str, Any], + request_draft_report: dict[str, Any], + generated_at: str | None, +) -> dict[str, Any]: + report_time = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds") + requests = request_draft_report.get("request_drafts", []) + acceptance_candidates = [acceptance_candidate(item) for item in requests] + c0_candidates = [item for item in acceptance_candidates if item["control_tier"] == "C0"] + c1_candidates = [item for item in acceptance_candidates if item["control_tier"] == "C1"] + + return { + "schema_version": "k8s_argocd_owner_response_acceptance_v1", + "generated_at": report_time, + "git_commit": git_short_sha(root), + "source_inventory_schema_version": inventory.get("schema_version"), + "source_inventory_status": inventory.get("status"), + "source_owner_request_schema_version": request_draft_report.get("schema_version"), + "source_owner_request_status": request_draft_report.get("status"), + "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "summary": { + "source_scan_group_count": inventory.get("summary", {}).get("scan_group_count", 0), + "source_request_draft_count": request_draft_report.get("summary", {}).get("request_draft_count", 0), + "acceptance_candidate_count": len(acceptance_candidates), + "c0_acceptance_candidate_count": len(c0_candidates), + "c1_acceptance_candidate_count": len(c1_candidates), + "acceptance_field_count": len(ACCEPTANCE_FIELDS), + "required_owner_field_count": len(inventory["required_owner_fields"]), + "reviewer_check_count": len(REVIEWER_CHECKS), + "outcome_lane_count": len(OUTCOME_LANES), + "blocked_action_count": len(BLOCKED_ACTIONS), + "request_sent_count": 0, + "recipient_confirmed_count": 0, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "owner_response_rejected_count": 0, + "owner_response_quarantined_count": 0, + "supplement_requested_count": 0, + "rendered_manifest_diff_candidate_count": 0, + "rendered_manifest_diff_ready_count": 0, + "argocd_health_readback_received_count": 0, + "argocd_api_read_authorized_count": 0, + "argocd_api_read_executed_count": 0, + "argocd_sync_authorized_count": 0, + "argocd_sync_executed_count": 0, + "kubectl_action_authorized_count": 0, + "kubectl_action_executed_count": 0, + "live_cluster_read_authorized_count": 0, + "live_cluster_read_executed_count": 0, + "secret_value_collection_allowed_count": 0, + "maintenance_window_accepted_count": 0, + "rollback_revision_accepted_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + }, + "execution_boundaries": { + "request_dispatch_authorized": False, + "owner_response_accepted": False, + "argocd_api_read_authorized": False, + "argocd_api_read_executed": False, + "argocd_sync_authorized": False, + "argocd_sync_executed": False, + "kubectl_action_authorized": False, + "kubectl_action_executed": False, + "live_cluster_read_authorized": False, + "live_cluster_read_executed": False, + "secret_value_collection_allowed": False, + "rendered_manifest_diff_ready": False, + "production_write_authorized": False, + "runtime_execution_authorized": False, + "action_buttons_allowed": False, + "not_authorization": True, + }, + "acceptance_fields": ACCEPTANCE_FIELDS, + "required_owner_fields": inventory["required_owner_fields"], + "reviewer_checks": REVIEWER_CHECKS, + "outcome_lanes": OUTCOME_LANES, + "blocked_actions": BLOCKED_ACTIONS, + "acceptance_candidates": acceptance_candidates, + "next_steps": [ + "等待 owner response;未收到前不得更新 accepted count。", + "收到回覆後先走 raw payload / secret / scope / rollback / evidence ref 檢查,不合格即隔離、拒收或補件。", + "metadata 合格也只能進 rendered manifest diff reviewer review;ArgoCD API read、sync、kubectl action、secret collection 與 production write 仍需獨立人工批准。", + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser(description="IwoooS K8s / ArgoCD owner response acceptance 只讀帳本產生器") + parser.add_argument("--root", default=".", help="repo root") + parser.add_argument( + "--inventory-report", + default="docs/security/k8s-argocd-manifest-inventory.snapshot.json", + help="k8s-argocd-manifest-inventory.py 輸出的 JSON", + ) + parser.add_argument( + "--owner-request-report", + default="docs/security/k8s-argocd-owner-request-draft.snapshot.json", + help="k8s-argocd-owner-request-draft.py 輸出的 JSON", + ) + parser.add_argument("--output", help="寫出 JSON 報告") + parser.add_argument("--generated-at", help="固定報告時間,供 committed snapshot 使用") + args = parser.parse_args() + + root = Path(args.root).resolve() + inventory = load_json(root / args.inventory_report) + request_draft_report = load_json(root / args.owner_request_report) + report = build_report(root, inventory, request_draft_report, args.generated_at) + payload = json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + + if args.output: + output = Path(args.output) + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(payload + "\n", encoding="utf-8") + else: + print(payload) + + summary = report["summary"] + print( + "K8S_ARGOCD_OWNER_RESPONSE_ACCEPTANCE_OK " + f"candidates={summary['acceptance_candidate_count']} " + f"c0={summary['c0_acceptance_candidate_count']} " + f"checks={summary['reviewer_check_count']} " + f"lanes={summary['outcome_lane_count']} " + f"accepted={summary['owner_response_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/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 646988922..c82be90c5 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -125,6 +125,9 @@ def validate(root: Path) -> None: k8s_argocd_owner_request_draft = load_json( security_dir / "k8s-argocd-owner-request-draft.snapshot.json" ) + k8s_argocd_owner_response_acceptance = load_json( + security_dir / "k8s-argocd-owner-response-acceptance.snapshot.json" + ) public_gateway_preflight_inventory = load_json( security_dir / "public-gateway-preflight-inventory.snapshot.json" ) @@ -2733,6 +2736,33 @@ def validate(root: Path) -> None: nginx_gateway_category["evidence_refs"], evidence_ref, ) + k8s_gitops_category = next( + item + for item in high_value_config_coverage["coverage_categories"] + if item["category_id"] == "k8s_production_gitops" + ) + assert_equal( + "high_value_config_coverage.coverage_categories.k8s.coverage_percent", + k8s_gitops_category["coverage_percent"], + 62, + ) + assert_equal( + "high_value_config_coverage.coverage_categories.k8s.coverage_status", + k8s_gitops_category["coverage_status"], + "owner_response_acceptance_ledger_ready_needs_runtime_evidence", + ) + for evidence_ref in [ + "docs/security/HIGH-VALUE-CONFIG-CHANGE-GATE.md", + "docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md", + "docs/security/k8s-argocd-owner-response-acceptance.snapshot.json", + "k8s/awoooi-prod", + "k8s/argocd", + ]: + assert_contains( + "high_value_config_coverage.coverage_categories.k8s.evidence_refs", + k8s_gitops_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"]], @@ -4568,6 +4598,8 @@ def validate(root: Path) -> None: "docs/security/public-gateway-owner-response-acceptance.snapshot.json", "docs/security/PUBLIC-GATEWAY-OWNER-RESPONSE-ACCEPTANCE.md", "docs/schemas/public_gateway_preflight_inventory_v1.schema.json", + "docs/security/k8s-argocd-owner-response-acceptance.snapshot.json", + "docs/security/K8S-ARGOCD-OWNER-RESPONSE-ACCEPTANCE.md", "docs/security/host-service-config-inventory.snapshot.json", "docs/security/HOST-SERVICE-CONFIG-INVENTORY.md", "docs/schemas/host_service_config_inventory_v1.schema.json", @@ -15015,6 +15047,207 @@ def validate(root: Path) -> None: f"k8s_argocd_owner_request_draft.{draft['request_id']}.{false_key}", draft[false_key], ) + k8s_argocd_owner_response_acceptance_summary = k8s_argocd_owner_response_acceptance[ + "summary" + ] + assert_equal( + "k8s_argocd_owner_response_acceptance.schema", + k8s_argocd_owner_response_acceptance["schema_version"], + "k8s_argocd_owner_response_acceptance_v1", + ) + assert_equal( + "k8s_argocd_owner_response_acceptance.source_inventory_schema_version", + k8s_argocd_owner_response_acceptance["source_inventory_schema_version"], + "k8s_argocd_manifest_inventory_v1", + ) + assert_equal( + "k8s_argocd_owner_response_acceptance.source_owner_request_schema_version", + k8s_argocd_owner_response_acceptance["source_owner_request_schema_version"], + "k8s_argocd_owner_request_draft_v1", + ) + assert_equal( + "k8s_argocd_owner_response_acceptance.status", + k8s_argocd_owner_response_acceptance["status"], + "owner_response_acceptance_ledger_ready_no_runtime_action", + ) + expected_k8s_argocd_owner_response_acceptance_summary = { + "source_scan_group_count": 4, + "source_request_draft_count": 4, + "acceptance_candidate_count": 4, + "c0_acceptance_candidate_count": 3, + "c1_acceptance_candidate_count": 1, + "acceptance_field_count": 20, + "required_owner_field_count": 11, + "reviewer_check_count": 12, + "outcome_lane_count": 7, + "blocked_action_count": 18, + "request_sent_count": 0, + "recipient_confirmed_count": 0, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "owner_response_rejected_count": 0, + "owner_response_quarantined_count": 0, + "supplement_requested_count": 0, + "rendered_manifest_diff_candidate_count": 0, + "rendered_manifest_diff_ready_count": 0, + "argocd_health_readback_received_count": 0, + "argocd_api_read_authorized_count": 0, + "argocd_api_read_executed_count": 0, + "argocd_sync_authorized_count": 0, + "argocd_sync_executed_count": 0, + "kubectl_action_authorized_count": 0, + "kubectl_action_executed_count": 0, + "live_cluster_read_authorized_count": 0, + "live_cluster_read_executed_count": 0, + "secret_value_collection_allowed_count": 0, + "maintenance_window_accepted_count": 0, + "rollback_revision_accepted_count": 0, + "runtime_gate_count": 0, + "action_button_count": 0, + } + for key, expected in expected_k8s_argocd_owner_response_acceptance_summary.items(): + assert_equal( + f"k8s_argocd_owner_response_acceptance.summary.{key}", + k8s_argocd_owner_response_acceptance_summary[key], + expected, + ) + for key, value in k8s_argocd_owner_response_acceptance["execution_boundaries"].items(): + if key == "not_authorization": + assert_true(f"k8s_argocd_owner_response_acceptance.execution_boundaries.{key}", value) + else: + assert_false(f"k8s_argocd_owner_response_acceptance.execution_boundaries.{key}", value) + expected_k8s_argocd_owner_response_acceptance_ids = [ + "k8s_argocd_owner_response_acceptance:awoooi_prod", + "k8s_argocd_owner_response_acceptance:argocd", + "k8s_argocd_owner_response_acceptance:velero", + "k8s_argocd_owner_response_acceptance:monitoring", + ] + assert_equal( + "k8s_argocd_owner_response_acceptance.acceptance_candidate_ids", + [ + item["acceptance_candidate_id"] + for item in k8s_argocd_owner_response_acceptance["acceptance_candidates"] + ], + expected_k8s_argocd_owner_response_acceptance_ids, + ) + expected_k8s_argocd_owner_response_reviewer_checks = [ + "owner_identity_present", + "decision_reason_present", + "affected_scope_matches_group", + "redacted_refs_only", + "secret_value_absent", + "argocd_health_readback_ref_shape", + "argocd_sync_revision_ref_not_execution", + "rollback_revision_present", + "rendered_manifest_diff_ref_not_payload", + "maintenance_window_present", + "validation_plan_present", + "counts_transition_safe", + ] + assert_equal( + "k8s_argocd_owner_response_acceptance.reviewer_check_ids", + [item["check_id"] for item in k8s_argocd_owner_response_acceptance["reviewer_checks"]], + expected_k8s_argocd_owner_response_reviewer_checks, + ) + expected_k8s_argocd_owner_response_outcome_lanes = [ + "waiting_owner_response", + "quarantine_raw_payload", + "reject_secret_or_unredacted_manifest", + "request_supplement", + "ready_for_rendered_manifest_review", + "owner_review_only_update", + "waiting_runtime_gate", + ] + assert_equal( + "k8s_argocd_owner_response_acceptance.outcome_lane_ids", + [item["lane_id"] for item in k8s_argocd_owner_response_acceptance["outcome_lanes"]], + expected_k8s_argocd_owner_response_outcome_lanes, + ) + expected_k8s_argocd_owner_response_blocked_actions = [ + "argocd_api_read_without_approval", + "live_cluster_read_without_approval", + "argocd_sync", + "kubectl_apply", + "kubectl_patch", + "kubectl_delete", + "helm_upgrade", + "secret_value_collection", + "live_cluster_write", + "manual_pod_restart", + "scale_workload", + "change_network_policy", + "change_rbac", + "restore_backup", + "render_manifest_diff_from_untrusted_payload", + "mark_owner_response_accepted_without_reviewer_record", + "open_runtime_gate", + "add_action_button", + ] + assert_equal( + "k8s_argocd_owner_response_acceptance.blocked_actions", + k8s_argocd_owner_response_acceptance["blocked_actions"], + expected_k8s_argocd_owner_response_blocked_actions, + ) + for item in k8s_argocd_owner_response_acceptance["acceptance_candidates"]: + assert_equal( + f"k8s_argocd_owner_response_acceptance.{item['acceptance_candidate_id']}.field_count", + len(item["acceptance_fields"]), + 20, + ) + assert_equal( + f"k8s_argocd_owner_response_acceptance.{item['acceptance_candidate_id']}.required_owner_fields", + len(item["required_owner_fields"]), + 11, + ) + assert_equal( + f"k8s_argocd_owner_response_acceptance.{item['acceptance_candidate_id']}.reviewer_checks", + len(item["reviewer_checks"]), + 12, + ) + assert_equal( + f"k8s_argocd_owner_response_acceptance.{item['acceptance_candidate_id']}.outcome_lanes", + len(item["outcome_lanes"]), + 7, + ) + assert_equal( + f"k8s_argocd_owner_response_acceptance.{item['acceptance_candidate_id']}.blocked_actions", + len(item["blocked_actions"]), + 18, + ) + assert_true( + f"k8s_argocd_owner_response_acceptance.{item['acceptance_candidate_id']}.not_approval", + item["not_approval"], + ) + for false_key in [ + "request_sent", + "recipient_confirmed", + "owner_response_received", + "owner_response_accepted", + "owner_response_rejected", + "owner_response_quarantined", + "supplement_requested", + "rendered_manifest_diff_candidate", + "rendered_manifest_diff_ready", + "argocd_health_readback_received", + "argocd_api_read_authorized", + "argocd_api_read_executed", + "argocd_sync_authorized", + "argocd_sync_executed", + "kubectl_action_authorized", + "kubectl_action_executed", + "live_cluster_read_authorized", + "live_cluster_read_executed", + "secret_value_collection_allowed", + "maintenance_window_accepted", + "rollback_revision_accepted", + "production_write_authorized", + "runtime_gate", + "action_buttons_allowed", + ]: + assert_false( + f"k8s_argocd_owner_response_acceptance.{item['acceptance_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"],