diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 00d95fdb..f32705e5 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,30 @@ +## 2026-06-14|K8s / ArgoCD owner request draft 本地完成 + +**背景**:P0-20 已建立 K8s / ArgoCD manifest repo-only 清冊,但清冊不能當成 owner response,也不能授權 ArgoCD API read、sync 或 `kubectl` action。下一步需要把四個 scan group 轉成人工可核對的 owner request draft,讓 production、ArgoCD、Velero、monitoring 各自具備 owner、rollback、maintenance window 與 validation 欄位。 + +**完成項目**: +- 新增 `scripts/security/k8s-argocd-owner-request-draft.py`,從 committed K8s / ArgoCD manifest inventory snapshot 產生 metadata-only request draft。 +- 新增 `docs/security/k8s-argocd-owner-request-draft.snapshot.json`,固定 `request_draft_count=4`、`c0_request_draft_count=3`、`c1_request_draft_count=1`、`request_field_count=20`、`required_owner_field_count=11`、`evidence_gap_count=8`、`blocked_action_count=13`。 +- 新增 `docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md`,說明四份 request draft、owner 必填欄位、evidence 缺口、blocked actions 與完成度。 +- `security-mirror-progress-guard.py` 已鎖住新 snapshot 的 schema、summary、execution false flags、request ids、blocked actions 與每份草稿 false flags。 +- `K8S-ARGOCD-MANIFEST-INVENTORY.md`、`SECURITY-SUPPLY-CHAIN-PROGRESS.md`、P0 主控板、`HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md`、`IWOOOS-CONFIG-CONTROL-INVENTORY.md` 與 MASTER 已同步 P0-21。 + +**本地驗證**: +- `python3 -m json.tool docs/security/k8s-argocd-owner-request-draft.snapshot.json` 通過。 +- `python3 -m py_compile scripts/security/k8s-argocd-owner-request-draft.py scripts/security/security-mirror-progress-guard.py` 通過。 +- 產生器 smoke:`K8S_ARGOCD_OWNER_REQUEST_DRAFT_OK drafts=4 c0=3 fields=11 sent=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=824`。 +- `git diff --check` 通過。 +- diff-only 工作溝通片語掃描通過;未加入工作溝通原文、委派 XML、內嵌瀏覽器上下文或內部抱怨內容。 +- Snapshot assertion 通過:`K8S_ARGOCD_OWNER_REQUEST_DRAFT_ASSERTIONS_OK drafts=4 c0=3 fields=11 sent=0 runtime_gate=0`。 + +**完成度與邊界**: +- P0-21 K8s / ArgoCD owner request draft:`100%`。 +- Production browser verification:不適用;本輪只改 repo 內文件、snapshot、guard 與產生器,不變更前端 bundle 或 runtime。 +- request sent、recipient confirmed、owner response received / accepted、rendered manifest diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、secret collection、manual pod restart、scale workload、RBAC / NetworkPolicy change、restore backup、live evidence、runtime gate、action buttons、production write 全部維持 `0 / false`。 + ## 2026-06-14|K8s / ArgoCD manifest repo-only 清冊本地完成 **背景**:K8s / ArgoCD / production manifests 會直接影響 Deployment、CronJob、RBAC、NetworkPolicy、Secret metadata、Velero restore 與 monitoring rule。高價值配置 coverage 已指出尚未把 ArgoCD health / sync readback 與 rollback revision 收成 owner packet;因此先建立 repo-only manifest inventory,避免之後把 ArgoCD sync 或 `kubectl` 操作當成低風險變更。 diff --git a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md index 50566ce9..aa241c84 100644 --- a/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md +++ b/docs/security/HIGH-VALUE-CONFIG-CONTROL-COVERAGE.md @@ -32,6 +32,8 @@ 目前固定為 `file_count=49`、`c0_file_count=36`、`yaml_manifest_file_count=45`、`unique_kind_count=20`、`top_level_kind_marker_count=56`、`blocked_action_count=13`、`runtime_gate_count=0`。此 artifact 只補上 K8s / ArgoCD source inventory 的可重跑基線;owner request、rendered manifest diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read 與 production write 仍全部未授權。 +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。 + ## 2. 覆蓋摘要 | 指標 | 目前值 | 說明 | diff --git a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md index 92f0cfaf..d6c08947 100644 --- a/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md +++ b/docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md @@ -146,7 +146,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` 的只讀清冊。這只是 repo-only manifest inventory,不是 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。這些都不是 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-MANIFEST-INVENTORY.md b/docs/security/K8S-ARGOCD-MANIFEST-INVENTORY.md index c14124d9..51fca3d4 100644 --- a/docs/security/K8S-ARGOCD-MANIFEST-INVENTORY.md +++ b/docs/security/K8S-ARGOCD-MANIFEST-INVENTORY.md @@ -89,7 +89,15 @@ K8s / ArgoCD / production manifests 會直接影響部署、replica、cronjob、 12. `restore_backup` 13. `open_runtime_gate` -## 7. 指令 +## 7. 2026-06-14 Owner Request Draft + +已新增 `docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md` 與 `docs/security/k8s-argocd-owner-request-draft.snapshot.json`,將四個 scan group 轉成人工送件前 request draft。 + +目前固定為 `request_draft_count=4`、`c0_request_draft_count=3`、`c1_request_draft_count=1`、`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`、`owner_response_accepted_count=0`、`runtime_gate_count=0`。 + +此 artifact 只表示 owner request 的 required shape,不代表 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。 + +## 8. 指令 產生 committed snapshot: @@ -106,12 +114,12 @@ python3 scripts/security/k8s-argocd-manifest-inventory.py \ python3 scripts/security/security-mirror-progress-guard.py --root . ``` -## 8. 完成度 +## 9. 完成度 | 工作 | 完成度 | 說明 | |------|--------|------| | repo-only manifest inventory | `100%` | 49 個 source files、45 個 YAML manifest、20 類 top-level kind marker 已固定 | -| owner request draft | `0%` | 尚未把清冊轉成逐 group owner request | +| owner request draft | `100%` | 已新增 4 份 request draft、snapshot、文件與 guard;request sent / received / accepted 仍為 0 | | live ArgoCD / K8s readback | `0%` | 尚未批准且未執行 | | rendered manifest diff | `0%` | 尚未產生 | | ArgoCD sync / kubectl action | `0%` | 未授權且未執行 | diff --git a/docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md b/docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md new file mode 100644 index 00000000..b14827b1 --- /dev/null +++ b/docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md @@ -0,0 +1,115 @@ +# IwoooS K8s / ArgoCD Owner Request Draft + +| 項目 | 內容 | +|------|------| +| 日期 | 2026-06-14 | +| 狀態 | `owner_request_draft_ready_not_dispatched` | +| 工具 | `scripts/security/k8s-argocd-owner-request-draft.py` | +| 輸入 | `docs/security/k8s-argocd-manifest-inventory.snapshot.json` | +| Snapshot | `docs/security/k8s-argocd-owner-request-draft.snapshot.json` | +| runtime gate | `0` | + +## 1. 目的 + +P0-20 已建立 K8s / ArgoCD manifest repo-only 清冊,但清冊本身不能當成 owner response,也不能授權 live cluster read、ArgoCD sync 或 `kubectl` action。本文件將四個 scan group 轉成人工送件前 request draft,讓後續可以按 production、ArgoCD、Velero、monitoring 分別收 owner 回覆與 rollback / validation 欄位。 + +本文件不是 request sent、不是 owner response received、不是 accepted response、不是 ArgoCD API read、不是 ArgoCD sync、不是 `kubectl apply`、不是 secret collection,也不是 production write 或 runtime gate。 + +## 2. 摘要 + +| 指標 | 值 | 說明 | +|------|----|------| +| request draft count | `4` | production、ArgoCD、Velero、monitoring 四組 | +| C0 / C1 request draft | `3 / 1` | production、ArgoCD、Velero 為 C0;monitoring 為 C1 | +| request field count | `20` | 每份 request draft 的 envelope 欄位 | +| required owner field count | `11` | owner、決策、ArgoCD readback、rollback、validation 等欄位 | +| evidence gap count | `8` | owner response、rendered diff、ArgoCD readback、rollback、post-check 等 | +| blocked action count | `13` | sync、kubectl、Helm、secret、restart、scale、restore 等全部阻擋 | +| request sent / recipient confirmed | `0 / 0` | 尚未送件 | +| owner response received / accepted | `0 / 0` | 尚未收到,尚未驗收 | +| rendered manifest diff / ArgoCD health readback | `0 / 0` | 尚未產生,尚未接收 | +| ArgoCD sync / kubectl action | `0 / 0` | 尚未批准且未執行 | +| runtime gate / action button | `0 / 0` | 未開啟 | + +## 3. 四份 Request Draft + +| Request | Tier | Root | Scope | +|---------|------|------|-------| +| `k8s_argocd_owner_request:awoooi_prod` | `C0` | `k8s/awoooi-prod` | production namespace manifests、Deployment、CronJob、Secret metadata、RBAC、NetworkPolicy、autoscaling | +| `k8s_argocd_owner_request:argocd` | `C0` | `k8s/argocd` | ArgoCD Application、metrics NetworkPolicy / NodePort | +| `k8s_argocd_owner_request:velero` | `C0` | `k8s/velero` | backup / restore manifests、Velero credentials metadata、metrics service | +| `k8s_argocd_owner_request:monitoring` | `C1` | `k8s/monitoring` | Prometheus rules、monitoring config、alert source 與支援腳本 | + +## 4. Owner 必填欄位 + +1. `owner_role_or_team` +2. `decision` +3. `decision_reason` +4. `affected_scope` +5. `redacted_evidence_refs` +6. `argocd_health_readback_ref` +7. `argocd_sync_revision_ref` +8. `rollback_revision` +9. `followup_owner` +10. `maintenance_window` +11. `validation_plan` + +## 5. Evidence 缺口 + +| 缺口 | 目前狀態 | +|------|----------| +| owner response | `0` | +| rendered manifest diff | `0` | +| ArgoCD health readback | `0` | +| ArgoCD sync revision | `0` | +| kubectl dry-run / server validation plan | `0` | +| rollout blast radius | `0` | +| rollback revision | `0` | +| postcheck metrics | `0` | + +## 6. 阻擋動作 + +以下動作不得由 request draft 直接授權: + +1. `argocd_sync` +2. `kubectl_apply` +3. `kubectl_patch` +4. `kubectl_delete` +5. `helm_upgrade` +6. `secret_value_collection` +7. `live_cluster_write` +8. `manual_pod_restart` +9. `scale_workload` +10. `change_network_policy` +11. `change_rbac` +12. `restore_backup` +13. `open_runtime_gate` + +## 7. 指令 + +產生 committed snapshot: + +```bash +python3 scripts/security/k8s-argocd-owner-request-draft.py \ + --root . \ + --inventory-report docs/security/k8s-argocd-manifest-inventory.snapshot.json \ + --output docs/security/k8s-argocd-owner-request-draft.snapshot.json \ + --generated-at 2026-06-14T21:35:00+08:00 +``` + +驗證 guard: + +```bash +python3 scripts/security/security-mirror-progress-guard.py --root . +``` + +## 8. 完成度 + +| 工作 | 完成度 | 說明 | +|------|--------|------| +| owner request draft artifact | `100%` | 4 份 request draft、snapshot、文件與 guard 已固定 | +| request dispatch | `0%` | 尚未送件 | +| owner response received / accepted | `0%` | 尚未收到,尚未驗收 | +| rendered manifest diff / ArgoCD readback | `0%` | 尚未產生或接收 | +| ArgoCD sync / kubectl action | `0%` | 未授權且未執行 | +| runtime gate / production write | `0%` | 未授權且未執行 | diff --git a/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md b/docs/security/SECURITY-SUPPLY-CHAIN-PROGRESS.md index 13635fde..354354a8 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`;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`;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`;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 | | 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary | | P0 主控板 | `docs/workplans/2026-06-04-iwooos-security-governance-p0.md` | @@ -394,6 +394,7 @@ headline 要再往上,需要 S4.9 / S4.10 / S4.11 / S4.12 任一 owner respons | Public Gateway rendered diff / nginx gate 草稿 | 本地完成 | `public-gateway-rendered-diff-gate-draft.snapshot.json` 已固定 `diff_gate_candidate_count=3`、`c0_diff_gate_candidate_count=2`、`preflight_stage_count=7`、`blocked_action_count=14`、`redacted_export_accepted_count=0`、`rendered_diff_ready_count=0`、`nginx_test_executed_count=0`、`runtime_gate_count=0`,並由 `security-mirror-progress-guard.py` 鎖住 diff gate ids、preflight stages、blocked actions 與 false flags | 這是 rendered diff / nginx / route smoke 分階段 gate 草稿,不是 redacted export accepted、rendered diff ready、`nginx -t`、Nginx reload、route smoke、DNS / TLS probe、certbot renew、host write、production write 或 runtime gate;不需要 production browser smoke | | 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 | 本地完成 | `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 | 這是人工送件前 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 | | S3 approval gate | 進行中 | `security_approval_gate_v1` 已建立 8 個人工 gate items:7 pending、1 block candidate、0 approved | 不得繞過人工批准;批准後仍需 follow-up runtime gate | | S3.0 人工批准 Gate 契約 | 完成草案 | 定義批准範圍、決策選項、required reviewers、still forbidden 與 follow-up runtime gate | AwoooP 可記錄決策,不可執行 gate item | | S3.1 人工決策紀錄契約 | 完成草案 | `security_approval_decision_record_v1` 已建立;目前 0 筆 decision records、0 個 runtime action 授權 | AwoooP 可稽核決策,不可把決策當執行 | diff --git a/docs/security/k8s-argocd-owner-request-draft.snapshot.json b/docs/security/k8s-argocd-owner-request-draft.snapshot.json new file mode 100644 index 00000000..1fa00726 --- /dev/null +++ b/docs/security/k8s-argocd-owner-request-draft.snapshot.json @@ -0,0 +1,588 @@ +{ + "blocked_actions": [ + "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", + "open_runtime_gate" + ], + "evidence_gaps": [ + "owner_response", + "rendered_manifest_diff", + "argocd_health_readback", + "argocd_sync_revision", + "kubectl_dry_run_or_server_validation_plan", + "rollout_blast_radius", + "rollback_revision", + "postcheck_metrics" + ], + "execution_boundaries": { + "action_buttons_allowed": false, + "argocd_api_read_authorized": 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, + "owner_response_received": false, + "production_write_authorized": false, + "recipient_confirmed": false, + "rendered_manifest_diff_ready": false, + "request_sent": false, + "runtime_execution_authorized": false, + "secret_value_collection_allowed": false + }, + "generated_at": "2026-06-14T21:35:00+08:00", + "git_commit": "e8876c45", + "next_steps": [ + "人工送件前確認 recipient role / team、snapshot 版本與 affected scope。", + "收到 owner response 後先做欄位完整性與敏感 payload 隔離,不得直接 sync 或 apply。", + "若未來要 live readback、ArgoCD sync 或 kubectl action,必須另開維護窗口、rollback revision 與 post-check gate。" + ], + "request_drafts": [ + { + "action_buttons_allowed": false, + "affected_scope": "pending_affected_scope", + "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_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", + "open_runtime_gate" + ], + "control_tier": "C0", + "decision": "pending_owner_decision", + "decision_reason": "pending_decision_reason", + "evidence_gaps": [ + "owner_response", + "rendered_manifest_diff", + "argocd_health_readback", + "argocd_sync_revision", + "kubectl_dry_run_or_server_validation_plan", + "rollout_blast_radius", + "rollback_revision", + "postcheck_metrics" + ], + "file_count": 25, + "followup_owner": "pending_followup_owner", + "gate_tags": [ + "availability_and_scaling", + "backup_restore", + "network_policy", + "rbac", + "secret_metadata", + "supporting_source", + "workload_or_schedule" + ], + "group_id": "awoooi_prod", + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "label": "AWOOOI production namespace manifests", + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "maintenance_window": "pending_maintenance_window", + "not_approval": true, + "owner_response_accepted": false, + "owner_response_received": false, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_role_or_team", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "rendered_manifest_diff_ready": false, + "request_fields": [ + "request_id", + "group_id", + "root", + "control_tier", + "file_count", + "yaml_manifest_file_count", + "supporting_source_file_count", + "top_level_kind_marker_count", + "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", + "not_approval" + ], + "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" + ], + "rollback_revision": "pending_rollback_revision", + "root": "k8s/awoooi-prod", + "runtime_gate": false, + "secret_value_collection_allowed": false, + "source_snapshot_ref": "docs/security/k8s-argocd-manifest-inventory.snapshot.json", + "status": "draft_not_dispatched", + "supporting_source_file_count": 1, + "top_level_kind_marker_count": 39, + "top_level_kinds": [ + "ClusterRole", + "ClusterRoleBinding", + "ConfigMap", + "CronJob", + "Deployment", + "HorizontalPodAutoscaler", + "Kustomization", + "LimitRange", + "Namespace", + "NetworkPolicy", + "PodDisruptionBudget", + "ResourceQuota", + "Secret", + "Service", + "ServiceAccount", + "VerticalPodAutoscaler" + ], + "validation_plan": "pending_validation_plan", + "yaml_manifest_file_count": 24 + }, + { + "action_buttons_allowed": false, + "affected_scope": "pending_affected_scope", + "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_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", + "open_runtime_gate" + ], + "control_tier": "C0", + "decision": "pending_owner_decision", + "decision_reason": "pending_decision_reason", + "evidence_gaps": [ + "owner_response", + "rendered_manifest_diff", + "argocd_health_readback", + "argocd_sync_revision", + "kubectl_dry_run_or_server_validation_plan", + "rollout_blast_radius", + "rollback_revision", + "postcheck_metrics" + ], + "file_count": 4, + "followup_owner": "pending_followup_owner", + "gate_tags": [ + "argocd_application", + "network_policy", + "supporting_source" + ], + "group_id": "argocd", + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "label": "ArgoCD application and metrics exposure", + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "maintenance_window": "pending_maintenance_window", + "not_approval": true, + "owner_response_accepted": false, + "owner_response_received": false, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_role_or_team", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "rendered_manifest_diff_ready": false, + "request_fields": [ + "request_id", + "group_id", + "root", + "control_tier", + "file_count", + "yaml_manifest_file_count", + "supporting_source_file_count", + "top_level_kind_marker_count", + "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", + "not_approval" + ], + "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" + ], + "rollback_revision": "pending_rollback_revision", + "root": "k8s/argocd", + "runtime_gate": false, + "secret_value_collection_allowed": false, + "source_snapshot_ref": "docs/security/k8s-argocd-manifest-inventory.snapshot.json", + "status": "draft_not_dispatched", + "supporting_source_file_count": 1, + "top_level_kind_marker_count": 5, + "top_level_kinds": [ + "Application", + "NetworkPolicy", + "Service" + ], + "validation_plan": "pending_validation_plan", + "yaml_manifest_file_count": 3 + }, + { + "action_buttons_allowed": false, + "affected_scope": "pending_affected_scope", + "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_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", + "open_runtime_gate" + ], + "control_tier": "C0", + "decision": "pending_owner_decision", + "decision_reason": "pending_decision_reason", + "evidence_gaps": [ + "owner_response", + "rendered_manifest_diff", + "argocd_health_readback", + "argocd_sync_revision", + "kubectl_dry_run_or_server_validation_plan", + "rollout_blast_radius", + "rollback_revision", + "postcheck_metrics" + ], + "file_count": 7, + "followup_owner": "pending_followup_owner", + "gate_tags": [ + "backup_restore", + "rbac", + "secret_metadata", + "workload_or_schedule" + ], + "group_id": "velero", + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "label": "Velero backup / restore manifests", + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "maintenance_window": "pending_maintenance_window", + "not_approval": true, + "owner_response_accepted": false, + "owner_response_received": false, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_role_or_team", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "rendered_manifest_diff_ready": false, + "request_fields": [ + "request_id", + "group_id", + "root", + "control_tier", + "file_count", + "yaml_manifest_file_count", + "supporting_source_file_count", + "top_level_kind_marker_count", + "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", + "not_approval" + ], + "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" + ], + "rollback_revision": "pending_rollback_revision", + "root": "k8s/velero", + "runtime_gate": false, + "secret_value_collection_allowed": false, + "source_snapshot_ref": "docs/security/k8s-argocd-manifest-inventory.snapshot.json", + "status": "draft_not_dispatched", + "supporting_source_file_count": 1, + "top_level_kind_marker_count": 8, + "top_level_kinds": [ + "BackupStorageLocation", + "ClusterRoleBinding", + "Deployment", + "List", + "Namespace", + "Secret", + "Service", + "ServiceAccount" + ], + "validation_plan": "pending_validation_plan", + "yaml_manifest_file_count": 6 + }, + { + "action_buttons_allowed": false, + "affected_scope": "pending_affected_scope", + "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_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", + "open_runtime_gate" + ], + "control_tier": "C1", + "decision": "pending_owner_decision", + "decision_reason": "pending_decision_reason", + "evidence_gaps": [ + "owner_response", + "rendered_manifest_diff", + "argocd_health_readback", + "argocd_sync_revision", + "kubectl_dry_run_or_server_validation_plan", + "rollout_blast_radius", + "rollback_revision", + "postcheck_metrics" + ], + "file_count": 13, + "followup_owner": "pending_followup_owner", + "gate_tags": [ + "apply_capable_script", + "monitoring_alerting", + "supporting_source" + ], + "group_id": "monitoring", + "kubectl_action_authorized": false, + "kubectl_action_executed": false, + "label": "K8s monitoring and alert source", + "live_cluster_read_authorized": false, + "live_cluster_read_executed": false, + "maintenance_window": "pending_maintenance_window", + "not_approval": true, + "owner_response_accepted": false, + "owner_response_received": false, + "owner_response_rejected": false, + "owner_role_or_team": "pending_owner_role_or_team", + "production_write_authorized": false, + "recipient_confirmed": false, + "redacted_evidence_refs": [], + "rendered_manifest_diff_ready": false, + "request_fields": [ + "request_id", + "group_id", + "root", + "control_tier", + "file_count", + "yaml_manifest_file_count", + "supporting_source_file_count", + "top_level_kind_marker_count", + "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", + "not_approval" + ], + "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" + ], + "rollback_revision": "pending_rollback_revision", + "root": "k8s/monitoring", + "runtime_gate": false, + "secret_value_collection_allowed": false, + "source_snapshot_ref": "docs/security/k8s-argocd-manifest-inventory.snapshot.json", + "status": "draft_not_dispatched", + "supporting_source_file_count": 1, + "top_level_kind_marker_count": 4, + "top_level_kinds": [ + "PrometheusRule" + ], + "validation_plan": "pending_validation_plan", + "yaml_manifest_file_count": 12 + } + ], + "request_fields": [ + "request_id", + "group_id", + "root", + "control_tier", + "file_count", + "yaml_manifest_file_count", + "supporting_source_file_count", + "top_level_kind_marker_count", + "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", + "not_approval" + ], + "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" + ], + "schema_version": "k8s_argocd_owner_request_draft_v1", + "source_inventory_schema_version": "k8s_argocd_manifest_inventory_v1", + "source_inventory_status": "repo_only_inventory_ready_no_live_cluster_read", + "status": "owner_request_draft_ready_not_dispatched", + "summary": { + "action_button_count": 0, + "argocd_health_readback_received_count": 0, + "argocd_sync_authorized_count": 0, + "argocd_sync_executed_count": 0, + "blocked_action_count": 13, + "c0_request_draft_count": 3, + "c1_request_draft_count": 1, + "evidence_gap_count": 8, + "kubectl_action_authorized_count": 0, + "kubectl_action_executed_count": 0, + "live_cluster_read_authorized_count": 0, + "live_cluster_read_executed_count": 0, + "owner_response_accepted_count": 0, + "owner_response_received_count": 0, + "owner_response_rejected_count": 0, + "recipient_confirmed_count": 0, + "rendered_manifest_diff_ready_count": 0, + "request_draft_count": 4, + "request_field_count": 20, + "request_sent_count": 0, + "required_owner_field_count": 11, + "runtime_gate_count": 0, + "secret_value_collection_allowed_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 c707c7e8..d051927c 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 @@ -694,6 +694,7 @@ Alert / Sentry / SigNoz / Gitea / Market Watch / Operator | `docs/security/public-gateway-rendered-diff-gate-draft.snapshot.json` + `scripts/security/public-gateway-rendered-diff-gate-draft.py` | Public Gateway rendered diff / nginx gate 草稿已本地完成;承接 redacted export intake preflight,固定 3 份 diff gate candidate、2 份 C0、1 份 C1、12 欄 diff gate field、7 個 preflight stage 與 14 類 blocked action;redacted export accepted、rendered diff ready、`nginx -t` executed、reload、route smoke、DNS / TLS probe、certbot renew、runtime gate、action buttons 仍全部為 `0` | 這是 rendered diff / nginx / route smoke 分階段 gate 草稿,不是 redacted export accepted、rendered diff ready、`nginx -t`、Nginx reload、DNS / TLS probe、certbot renew、route smoke、host write、production write 或 runtime gate | | `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/evaluations/ai_agent_live_read_model_gate_2026-06-11.json` + `GET /api/v1/agents/agent-live-read-model-gate` | P2-403B AgentSession / Redis Streams live read model gate;定義 safe fields、Redis envelope、worker gate、rollback plan 與 no-write smoke,不連 DB、不讀寫 Redis、不啟動 worker | #### 3.2.1c 2026-06-11 AI Agent 主動營運委派與版本生命週期契約 @@ -839,6 +840,7 @@ Repo / registry / release notes / K8s / host / observability / backup evidence 75. 建立 Public Gateway rendered diff / nginx gate 草稿。✅ 本地完成;新增 `public-gateway-rendered-diff-gate-draft.py`、snapshot 與說明文件,將三份 redacted export intake candidate 轉成 `diff_gate_candidate_count=3`、`c0_diff_gate_candidate_count=2`、`preflight_stage_count=7`、`blocked_action_count=14` 的 rendered diff / nginx / route smoke 分階段 gate 草稿;redacted export accepted、rendered diff ready、`nginx -t` executed、reload、route smoke、DNS / TLS probe、certbot renew、runtime gate、action buttons 仍全部為 `0`。這不是 redacted export accepted、rendered diff ready、`nginx -t`、Nginx reload、DNS / TLS probe、certbot renew、host write、production write 或 runtime gate。 76. 建立 DNS / TLS / certbot Owner Confirmation Request。✅ 本地完成;新增 `domain-tls-certbot-owner-confirmation-request.py`、snapshot 與說明文件,將 4 個 certificate path 需確認的 domain 轉成 `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 confirmation request 草稿;request sent、recipient confirmed、owner response received / accepted、DNS query、TLS probe、certbot renew、Nginx reload、host write、runtime gate、action buttons 仍全部為 `0`。這不是 request sent、owner response received / accepted、DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、production write 或 runtime gate。 77. 建立 K8s / ArgoCD manifest repo-only 清冊。✅ 本地完成;新增 `k8s-argocd-manifest-inventory.py`、snapshot 與說明文件,將 `k8s/awoooi-prod`、`k8s/argocd`、`k8s/velero`、`k8s/monitoring` 轉成 `file_count=49`、`c0_file_count=36`、`yaml_manifest_file_count=45`、`unique_kind_count=20`、`top_level_kind_marker_count=56`、`blocked_action_count=13` 的 repo-only manifest inventory;owner response、rendered manifest diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate、action buttons 仍全部為 `0`。這不是 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。 +78. 建立 K8s / ArgoCD Owner Request Draft。✅ 本地完成;新增 `k8s-argocd-owner-request-draft.py`、snapshot 與說明文件,將四個 scan group 轉成 `request_draft_count=4`、`c0_request_draft_count=3`、`c1_request_draft_count=1`、`request_field_count=20`、`required_owner_field_count=11`、`evidence_gap_count=8`、`blocked_action_count=13` 的人工送件前草稿;request sent、recipient confirmed、owner response received / accepted、rendered manifest diff、ArgoCD health readback、ArgoCD sync、kubectl action、live cluster read、secret collection、runtime gate、action buttons 仍全部為 `0`。這不是 request sent、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 互動、學習與成長證據面 @@ -4789,3 +4791,16 @@ Trigger commit `f5cd37b7` 與 deploy marker `0ba92357` 已把 governance UI 的 - P0 總帳、供應鏈進度、IwoooS 配置控管總清單與 MASTER artifact 表已同步 P0-20。 **裁決:** 這是 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、active scan、production write 或 runtime gate;IwoooS headline 仍維持 `64%`,active runtime gate 仍 `0`。 + +### 2026-06-14 21:35 (台北) — §3.2 / §5 — 新增 K8s / ArgoCD Owner Request Draft — 把 manifest 清冊轉成人工送件草稿 + +**觸發**:P0-20 已建立 repo-only manifest inventory;下一步需要將 production、ArgoCD、Velero、monitoring 四個 scan group 轉成人工可核對的 owner request draft,但仍不得送件、不得讀 live cluster、不得 ArgoCD sync 或執行 `kubectl`。 + +**已推進:** +- 新增 `scripts/security/k8s-argocd-owner-request-draft.py`,讀取 `docs/security/k8s-argocd-manifest-inventory.snapshot.json`,產生四份 owner request draft。 +- 新增 `docs/security/k8s-argocd-owner-request-draft.snapshot.json`,固定 `request_draft_count=4`、`c0_request_draft_count=3`、`c1_request_draft_count=1`、`request_field_count=20`、`required_owner_field_count=11`、`blocked_action_count=13`。 +- 新增 `docs/security/K8S-ARGOCD-OWNER-REQUEST-DRAFT.md`,說明四份 request、owner 必填欄位、evidence 缺口、blocked actions 與完成度。 +- `security-mirror-progress-guard.py` 已鎖住新 snapshot 的 schema、summary、execution false flags、request ids、blocked actions 與每份草稿 false flags。 +- P0 總帳、供應鏈進度、K8s manifest 清冊、IwoooS 配置控管總清單、coverage 矩陣與 MASTER artifact 表已同步 P0-21。 + +**裁決:** 這是人工送件前 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、active scan、production write 或 runtime gate;IwoooS headline 仍維持 `64%`,active runtime gate 仍 `0`。 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 1819dd9d..609f9c3a 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 本輪 K8s / ArgoCD manifest repo-only 清冊;Public Gateway 三段固定 requests / candidates `3`、C0 `2`,DNS / TLS 固定 owner confirmation requests `4`、C0 `4`,K8s manifest 固定 files `49`、C0 `36`、YAML `45`、kinds `20`;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 本輪 K8s / ArgoCD owner request draft;Public Gateway 三段固定 requests / candidates `3`、C0 `2`,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` | | 最新 AI Agent automation P1-305 / P1-306 基準 | code `4f0787f8`、deploy marker `af3a9d48`、CD `2592`、code-review `2593`;任務批准邊界與進度彙總已正式驗證;backlog `70%`、done `16/23`、下一步 `P1-001` | | 最新 AI Agent automation P1-001 基準 | code `de3007b7`、stability fix `fd33591c`、deploy marker `8caba233`、LOGBOOK / marker 對齊 `37c0e171`;runtime surface `22`、Secret surface `4`、live gaps `6`、backlog `74%`、done `17/23`、下一步 `P1-002` | | 最新 AI Agent automation P1-002 基準 | code `943faaee`、stability fix `ff266926`、deploy marker `01b8712d`、LOGBOOK / marker 對齊 `70c01003`;Gitea workflows `9`、runner contracts `4`、需 runner attestation workflows `8`、backlog `78%`、done `18/23`、下一步 `P1-003` | @@ -30,7 +30,7 @@ | 最新 S4.9 owner response intake form 基準 | `docs/security/S4-9-OWNER-RESPONSE-INTAKE-FORM.md`;五題可填表、六欄填寫規則、reviewer 收件欄與 outcome lanes 已固定;owner response gate 仍 `0%` | | 最新 S4.9 reviewer validation checklist 基準 | `docs/security/S4-9-REVIEWER-VALIDATION-CHECKLIST.md`;Reviewer 分工、V0-V8 gates、outcome 決策表、count transition 與 cross-packet consistency 已固定;owner response gate 仍 `0%` | | 最新 S4.9 security acceptance record template 基準 | `docs/security/S4-9-SECURITY-ACCEPTANCE-RECORD-TEMPLATE.md`;acceptance record 前置條件、欄位、count transition、decision outcome、evidence redaction 與不可授權聲明已固定;owner response gate 仍 `0%` | -| 目前平行 Session | AwoooP thread `019e9168-3e85-7053-a63f-471eb77b1457` 已同步 P0-15 `5068654d`、P0-16 `f856df1c`、P0-17 `762f73a6`、P0-18 `757f6a53`、P0-19 `551d8144`;P0-20 完成後需再同步本輪 commit 與 0 / false 邊界,後續進下一個 P0 / P1 前仍需重新 fetch / fast-forward,避免 LOGBOOK / workplan 衝突 | +| 目前平行 Session | AwoooP thread `019e9168-3e85-7053-a63f-471eb77b1457` 已同步 P0-15 `5068654d`、P0-16 `f856df1c`、P0-17 `762f73a6`、P0-18 `757f6a53`、P0-19 `551d8144`、P0-20 `e8876c45`;P0-21 完成後需再同步本輪 commit 與 0 / false 邊界,後續進下一個 P0 / P1 前仍需重新 fetch / fast-forward,避免 LOGBOOK / workplan 衝突 | | 前一個正式 IwoooS 候選基準 | code `7b8fc093`、deploy marker `45c63488`、LOGBOOK `02cadee6` | | 最新導航 IA 基準 | code `973fc7a4`、LOGBOOK `2555c811`、deploy marker `0260ec89` | | 禁止事項 | 不 force push、不 destructive git、不 SSH 修改主機、不 active scan、不收 secrets 明文、不把 AwoooP approval 當資安批准、不把 UI 可見當 runtime 授權 | @@ -86,6 +86,7 @@ | P0-18 | P0 主控板同步基線回填 | 100% | 已將本次 worktree、分支、最新 `gitea/main`、Public Gateway P0-15~P0-17 基準與平行 AwoooP Session 同步狀態回填,避免下一個 Session 用舊 2026-06-11 worktree / 舊 commit 判讀 | 只改 P0 總帳與 LOGBOOK;需跑 progress guard、owner response guard、doc secret sanity、diff check 與工作視窗片語掃描;不需要 production browser smoke | | 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 | ## 3. S4.9 Owner Response Gate 規範 diff --git a/scripts/security/k8s-argocd-owner-request-draft.py b/scripts/security/k8s-argocd-owner-request-draft.py new file mode 100644 index 00000000..c2fa4533 --- /dev/null +++ b/scripts/security/k8s-argocd-owner-request-draft.py @@ -0,0 +1,228 @@ +#!/usr/bin/env python3 +""" +IwoooS K8s / ArgoCD owner request draft 產生器。 + +本工具讀取 K8s / ArgoCD repo-only manifest inventory,將 scan groups 轉成 +人工送件前 request draft。它不讀 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)) + +REQUEST_FIELDS = [ + "request_id", + "group_id", + "root", + "control_tier", + "file_count", + "yaml_manifest_file_count", + "supporting_source_file_count", + "top_level_kind_marker_count", + "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", + "not_approval", +] + + +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 request_for(group: dict[str, Any], inventory: dict[str, Any]) -> dict[str, Any]: + group_id = group["group_id"] + rows = [row for row in inventory["manifest_rows"] if row["group_id"] == group_id] + gate_tags = sorted({tag for row in rows for tag in row.get("gate_tags", [])}) + top_level_kinds = sorted({kind for row in rows for kind in row.get("top_level_kinds", [])}) + return { + "request_id": f"k8s_argocd_owner_request:{group_id}", + "status": "draft_not_dispatched", + "group_id": group_id, + "root": group["root"], + "label": group["label"], + "control_tier": group["control_tier"], + "file_count": group["file_count"], + "yaml_manifest_file_count": group["yaml_manifest_file_count"], + "supporting_source_file_count": group["supporting_source_file_count"], + "top_level_kind_marker_count": sum(row["top_level_kind_count"] for row in rows), + "gate_tags": gate_tags, + "top_level_kinds": top_level_kinds, + "source_snapshot_ref": "docs/security/k8s-argocd-manifest-inventory.snapshot.json", + "request_fields": REQUEST_FIELDS, + "required_owner_fields": inventory["required_owner_fields"], + "evidence_gaps": inventory["evidence_gaps"], + "blocked_actions": inventory["blocked_actions"], + "owner_role_or_team": "pending_owner_role_or_team", + "decision": "pending_owner_decision", + "decision_reason": "pending_decision_reason", + "affected_scope": "pending_affected_scope", + "redacted_evidence_refs": [], + "argocd_health_readback_ref": None, + "argocd_sync_revision_ref": None, + "rollback_revision": "pending_rollback_revision", + "followup_owner": "pending_followup_owner", + "maintenance_window": "pending_maintenance_window", + "validation_plan": "pending_validation_plan", + "not_approval": True, + "request_sent": False, + "recipient_confirmed": False, + "owner_response_received": False, + "owner_response_accepted": False, + "owner_response_rejected": False, + "rendered_manifest_diff_ready": False, + "argocd_health_readback_received": 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, + "runtime_gate": False, + "action_buttons_allowed": False, + "production_write_authorized": False, + } + + +def build_report(root: Path, inventory: dict[str, Any], generated_at: str | None) -> dict[str, Any]: + report_time = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds") + requests = [request_for(group, inventory) for group in inventory["group_summaries"]] + c0_requests = [item for item in requests if item["control_tier"] == "C0"] + c1_requests = [item for item in requests if item["control_tier"] == "C1"] + + return { + "schema_version": "k8s_argocd_owner_request_draft_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"), + "status": "owner_request_draft_ready_not_dispatched", + "summary": { + "request_draft_count": len(requests), + "c0_request_draft_count": len(c0_requests), + "c1_request_draft_count": len(c1_requests), + "request_field_count": len(REQUEST_FIELDS), + "required_owner_field_count": len(inventory["required_owner_fields"]), + "evidence_gap_count": len(inventory["evidence_gaps"]), + "blocked_action_count": len(inventory["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, + "rendered_manifest_diff_ready_count": 0, + "argocd_health_readback_received_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, + "runtime_gate_count": 0, + "action_button_count": 0, + }, + "execution_boundaries": { + "request_sent": False, + "recipient_confirmed": False, + "owner_response_received": False, + "owner_response_accepted": False, + "rendered_manifest_diff_ready": False, + "argocd_api_read_authorized": 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, + "production_write_authorized": False, + "runtime_execution_authorized": False, + "action_buttons_allowed": False, + "not_authorization": True, + }, + "request_fields": REQUEST_FIELDS, + "required_owner_fields": inventory["required_owner_fields"], + "evidence_gaps": inventory["evidence_gaps"], + "blocked_actions": inventory["blocked_actions"], + "request_drafts": requests, + "next_steps": [ + "人工送件前確認 recipient role / team、snapshot 版本與 affected scope。", + "收到 owner response 後先做欄位完整性與敏感 payload 隔離,不得直接 sync 或 apply。", + "若未來要 live readback、ArgoCD sync 或 kubectl action,必須另開維護窗口、rollback revision 與 post-check gate。", + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser(description="IwoooS K8s / ArgoCD owner request draft 產生器") + 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("--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) + report = build_report(root, inventory, 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_REQUEST_DRAFT_OK " + f"drafts={summary['request_draft_count']} " + f"c0={summary['c0_request_draft_count']} " + f"fields={summary['required_owner_field_count']} " + f"sent={summary['request_sent_count']} " + f"runtime_gate={summary['runtime_gate_count']}", + file=sys.stderr, + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 258483eb..2cbaea09 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -107,6 +107,9 @@ def validate(root: Path) -> None: k8s_argocd_manifest_inventory = load_json( security_dir / "k8s-argocd-manifest-inventory.snapshot.json" ) + k8s_argocd_owner_request_draft = load_json( + security_dir / "k8s-argocd-owner-request-draft.snapshot.json" + ) public_gateway_preflight_inventory = load_json( security_dir / "public-gateway-preflight-inventory.snapshot.json" ) @@ -13937,6 +13940,133 @@ def validate(root: Path) -> None: f"k8s_argocd_manifest_inventory.manifest_rows.{row['path']}.{false_key}", row[false_key], ) + k8s_argocd_owner_request_summary = k8s_argocd_owner_request_draft["summary"] + assert_equal( + "k8s_argocd_owner_request_draft.schema", + k8s_argocd_owner_request_draft["schema_version"], + "k8s_argocd_owner_request_draft_v1", + ) + assert_equal( + "k8s_argocd_owner_request_draft.source_inventory_schema_version", + k8s_argocd_owner_request_draft["source_inventory_schema_version"], + "k8s_argocd_manifest_inventory_v1", + ) + assert_equal( + "k8s_argocd_owner_request_draft.status", + k8s_argocd_owner_request_draft["status"], + "owner_request_draft_ready_not_dispatched", + ) + expected_k8s_argocd_owner_request_summary = { + "request_draft_count": 4, + "c0_request_draft_count": 3, + "c1_request_draft_count": 1, + "request_field_count": 20, + "required_owner_field_count": 11, + "evidence_gap_count": 8, + "blocked_action_count": 13, + "request_sent_count": 0, + "recipient_confirmed_count": 0, + "owner_response_received_count": 0, + "owner_response_accepted_count": 0, + "owner_response_rejected_count": 0, + "rendered_manifest_diff_ready_count": 0, + "argocd_health_readback_received_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, + "runtime_gate_count": 0, + "action_button_count": 0, + } + for key, expected in expected_k8s_argocd_owner_request_summary.items(): + assert_equal( + f"k8s_argocd_owner_request_draft.summary.{key}", + k8s_argocd_owner_request_summary[key], + expected, + ) + for false_key in [ + "request_sent", + "recipient_confirmed", + "owner_response_received", + "owner_response_accepted", + "rendered_manifest_diff_ready", + "argocd_api_read_authorized", + "argocd_sync_authorized", + "argocd_sync_executed", + "kubectl_action_authorized", + "kubectl_action_executed", + "live_cluster_read_authorized", + "live_cluster_read_executed", + "secret_value_collection_allowed", + "production_write_authorized", + "runtime_execution_authorized", + "action_buttons_allowed", + ]: + assert_false( + f"k8s_argocd_owner_request_draft.execution_boundaries.{false_key}", + k8s_argocd_owner_request_draft["execution_boundaries"][false_key], + ) + assert_true( + "k8s_argocd_owner_request_draft.execution_boundaries.not_authorization", + k8s_argocd_owner_request_draft["execution_boundaries"]["not_authorization"], + ) + expected_k8s_argocd_request_ids = [ + "k8s_argocd_owner_request:awoooi_prod", + "k8s_argocd_owner_request:argocd", + "k8s_argocd_owner_request:velero", + "k8s_argocd_owner_request:monitoring", + ] + assert_equal( + "k8s_argocd_owner_request_draft.request_ids", + [item["request_id"] for item in k8s_argocd_owner_request_draft["request_drafts"]], + expected_k8s_argocd_request_ids, + ) + assert_equal( + "k8s_argocd_owner_request_draft.blocked_actions", + k8s_argocd_owner_request_draft["blocked_actions"], + expected_k8s_blocked_actions, + ) + for draft in k8s_argocd_owner_request_draft["request_drafts"]: + assert_equal( + f"k8s_argocd_owner_request_draft.{draft['request_id']}.request_field_count", + len(draft["request_fields"]), + 20, + ) + assert_equal( + f"k8s_argocd_owner_request_draft.{draft['request_id']}.required_owner_field_count", + len(draft["required_owner_fields"]), + 11, + ) + assert_true( + f"k8s_argocd_owner_request_draft.{draft['request_id']}.not_approval", + draft["not_approval"], + ) + for false_key in [ + "request_sent", + "recipient_confirmed", + "owner_response_received", + "owner_response_accepted", + "owner_response_rejected", + "rendered_manifest_diff_ready", + "argocd_health_readback_received", + "argocd_sync_authorized", + "argocd_sync_executed", + "kubectl_action_authorized", + "kubectl_action_executed", + "live_cluster_read_authorized", + "live_cluster_read_executed", + "secret_value_collection_allowed", + "runtime_gate", + "action_buttons_allowed", + "production_write_authorized", + ]: + assert_false( + f"k8s_argocd_owner_request_draft.{draft['request_id']}.{false_key}", + draft[false_key], + ) assert_equal( "iwooos_projection.summary.domain_tls_certbot_inventory_managed_domain_count", iwooos_projection["summary"]["domain_tls_certbot_inventory_managed_domain_count"],