test(iwooos): 新增供應鏈 owner policy gate [skip ci]
This commit is contained in:
@@ -193,7 +193,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公
|
||||
| P2 | AWOOOI / AwoooP / IwoooS frontend runtime config | `apps/web/next.config.js`、`apps/web/src/lib/config.ts`、i18n | web owner | NEXT_PUBLIC public-domain only、no internal transcript, desktop/mobile smoke |
|
||||
| P2 | VibeWork product boundary | VibeWork owner docs / future evidence refs | VibeWork owner | independent product boundary、repo / deploy / admin / backup scope |
|
||||
| P2 | StockPlatform / Tsenyang / Bitan / VTuber routes | Nginx templates、product runbooks | product owner | domain / admin / API / backup / owner matrix |
|
||||
| P2 | Package / supply-chain baselines | `pnpm-lock.yaml`、`package.json`、`pyproject.toml`、`requirements.txt`、Dockerfiles、docker-compose、`docs/security/PACKAGE-SUPPLY-CHAIN-BASELINE.md`、`docs/security/package-supply-chain-baseline.snapshot.json` | repo / registry owner | package manager policy、lockfile owner、Python lock policy、CVE / license / SBOM window、image digest evidence、registry owner、rollback owner |
|
||||
| P2 | Package / supply-chain baselines | `pnpm-lock.yaml`、`package.json`、`pyproject.toml`、`requirements.txt`、Dockerfiles、docker-compose、`docs/security/PACKAGE-SUPPLY-CHAIN-BASELINE.md`、`docs/security/package-supply-chain-baseline.snapshot.json`、`docs/security/PACKAGE-SUPPLY-CHAIN-OWNER-POLICY-GATE.md`、`docs/security/package-supply-chain-owner-policy-gate.snapshot.json` | repo / registry owner | package manager policy、lockfile owner、Python lock policy、requirements pinning policy、Docker digest pinning policy、compose image digest policy、CVE / license / SBOM window、registry owner、rollback owner |
|
||||
| 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。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 只讀帳本。2026-06-15 再新增 `docs/security/K8S-ARGOCD-CHANGE-EVIDENCE-ACCEPTANCE.md` 與 `docs/security/k8s-argocd-change-evidence-acceptance.snapshot.json`,固定 `candidates=4`、`c0=3`、`write_capable=4`、`required_evidence_fields=18`、`reviewer_checks=18`、`outcome_lanes=8`、`blocked_actions=28` 的 GitOps 變更證據驗收只讀帳本。這些都不是 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。
|
||||
@@ -211,6 +211,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公
|
||||
9. DNS / TLS / certbot owner response 只能收脫敏 metadata ref、coverage basis、expiry metadata、renewal owner、ACME route owner、maintenance window、rollback owner 與 validation plan;不得因 owner 回覆而自動做 DNS query、live TLS probe、certbot renew、Nginx reload、route smoke、DNS record 變更、certificate path 變更或 ACME route 變更。
|
||||
10. Public / admin / API / frontend runtime config 變更必須先通過 affected route、auth boundary、API readback、CORS diff、frontend env diff、i18n redaction、desktop / mobile smoke、sensitive string scan、rollback owner 與 post-check evidence;前台不得顯示 raw owner namespace、repo slug、內部狀態碼、內部協作內容或未脫敏截圖。
|
||||
11. 高價值配置控管必須能由 `scripts/security/iwooos-config-control-guard.py` 集中驗證;guard 通過只代表 repo snapshot 基線完整,不代表 owner response、live evidence、reload、restart、workflow / secret / runner 變更、backup / restore、scan、runtime 或 deploy 授權。
|
||||
12. Package / Docker 供應鏈修復前必須先通過 owner policy gate;Python lockfile、requirements pinning、Docker digest pinning、compose digest、CVE / license / SBOM 只能先收脫敏 owner metadata,不得因 baseline 或 gate 通過而 install、upgrade、rewrite lockfile、pull / build / push image、登入 registry、修改 workflow、部署或開 runtime gate。
|
||||
|
||||
## 5. 需要調整的既有規範
|
||||
|
||||
@@ -255,6 +256,7 @@ Nginx 是目前必須最先資安控管的配置,原因是它同時控制公
|
||||
| K8s / ArgoCD GitOps 變更證據驗收 | `100%` | 已新增 `k8s_argocd_change_evidence_acceptance_v1`,4 個 candidate、3 個 C0、4 個 write-capable、18 個 reviewer checks、8 條 outcome lanes、28 類 blocked action;成熟度 `62% -> 64%` |
|
||||
| Public / Admin / API runtime config 變更證據驗收 | `100%` | 已新增 `public_runtime_config_change_evidence_acceptance_v1`,6 個 candidate、5 個 C0、21 個 reviewer checks、8 條 outcome lanes、32 類 blocked action;成熟度 `62% -> 64%`;raw namespace / repo slug / 內部狀態碼 / 內部協作內容外洩列為拒收或隔離條件 |
|
||||
| Package / Docker supply-chain repo-only baseline | `100%` | 已新增 `package_supply_chain_baseline_v1`,盤點 `package_json=6`、`pyproject=4`、`requirements=2`、`dockerfiles=2`、`compose=6`、`gaps=5`;不 install、不掃 CVE、不改 image、不部署 |
|
||||
| Package / Docker supply-chain owner policy gate | `100%` | 已新增 `package_supply_chain_owner_policy_gate_v1`,6 個 owner policy request、2 個 C0、8 個 owner 欄位、12 個 reviewer checks、20 類 blocked action;request_sent / received / accepted / runtime / action 仍為 `0 / false` |
|
||||
| Backup / restore / escrow owner request draft | `100%` | 已將 38 個 backup / restore / escrow surface 轉成 owner request draft;request sent / received / accepted、backup run、restore run、offsite sync、remote delete、escrow marker write、retention change 仍為 0 |
|
||||
| CI blocking / workflow gate | `0%` | 本階段刻意不修改 `.gitea/workflows`,避免初期資安流程摩擦過大 |
|
||||
| owner-provided live Nginx file compare | `70%` | 工具可吃 owner 匯出的 live conf 檔比較;本階段不主動 SSH 取得 |
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
| 狀態 | `repo_only_inventory_ready_needs_owner_policy` |
|
||||
| 腳本 | `scripts/security/package-supply-chain-baseline.py` |
|
||||
| Snapshot | `docs/security/package-supply-chain-baseline.snapshot.json` |
|
||||
| Owner policy gate | `docs/security/PACKAGE-SUPPLY-CHAIN-OWNER-POLICY-GATE.md` / `docs/security/package-supply-chain-owner-policy-gate.snapshot.json` |
|
||||
| Schema | `docs/schemas/package_supply_chain_baseline_v1.schema.json` |
|
||||
| 模式 | repo snapshot only,不 install、不連外、不做 CVE scan、不改 image |
|
||||
| runtime gate | `0` |
|
||||
@@ -54,7 +55,22 @@
|
||||
7. `cve_scan_window`
|
||||
8. `rollback_owner`
|
||||
|
||||
## 5. 指令
|
||||
## 5. Owner Policy Gate
|
||||
|
||||
2026-06-15 已新增 `docs/security/PACKAGE-SUPPLY-CHAIN-OWNER-POLICY-GATE.md` 與 `docs/security/package-supply-chain-owner-policy-gate.snapshot.json`,把 baseline 缺口轉成六個 owner policy request:
|
||||
|
||||
| Request | 對應治理項 | 狀態 |
|
||||
|---------|------------|------|
|
||||
| package manager / lockfile owner | Node / pnpm lockfile owner 與更新窗口 | waiting owner policy response |
|
||||
| Python lockfile policy | Python lockfile 缺席 | waiting owner policy response |
|
||||
| requirements pinning policy | `requirements.txt` 未 pin | waiting owner policy response |
|
||||
| Docker digest pinning policy | Dockerfile base image 與 `COPY --from` image 未 digest pin | waiting owner policy response |
|
||||
| compose image digest policy | docker-compose image 未 digest pin | waiting owner policy response |
|
||||
| CVE / license / SBOM window | 掃描工具、窗口與噪音處理策略未定 | waiting owner policy response |
|
||||
|
||||
此 gate 只補「誰能決定、用什麼政策決定、何時驗證、誰負責 rollback」的收件前規範。request_sent、owner_response_received、owner_response_accepted、runtime_gate 與 action_button 仍全部是 `0 / false`。
|
||||
|
||||
## 6. 指令
|
||||
|
||||
```bash
|
||||
python3 scripts/security/package-supply-chain-baseline.py \
|
||||
@@ -77,7 +93,19 @@ python3 scripts/security/package-supply-chain-baseline.py \
|
||||
PACKAGE_SUPPLY_CHAIN_BASELINE_OK package_json=6 pyproject=4 requirements=2 dockerfiles=2 compose=6 gaps=5 runtime_gate=0
|
||||
```
|
||||
|
||||
## 6. 邊界
|
||||
Owner policy gate 驗證:
|
||||
|
||||
```bash
|
||||
python3 scripts/security/package-supply-chain-owner-policy-guard.py --root .
|
||||
```
|
||||
|
||||
預期輸出:
|
||||
|
||||
```text
|
||||
PACKAGE_SUPPLY_CHAIN_OWNER_POLICY_GUARD_OK
|
||||
```
|
||||
|
||||
## 7. 邊界
|
||||
|
||||
此 baseline 通過不代表:
|
||||
|
||||
@@ -87,13 +115,15 @@ PACKAGE_SUPPLY_CHAIN_BASELINE_OK package_json=6 pyproject=4 requirements=2 docke
|
||||
- registry login、Harbor policy、image immutability 或 scanner policy 已驗收。
|
||||
- workflow、runner、secret、production deploy 或 runtime gate 已授權。
|
||||
|
||||
## 7. 完成度
|
||||
## 8. 完成度
|
||||
|
||||
| 工作 | 完成度 | 說明 |
|
||||
|------|--------|------|
|
||||
| Package / Docker supply-chain repo-only baseline | `100%` | 已新增腳本、snapshot 與人讀文件 |
|
||||
| Node lockfile 基線 | `80%` | `pnpm-lock.yaml` 存在;仍需 owner policy 確認 lockfile owner / update window |
|
||||
| Python lock policy | `30%` | 已盤點 pyproject / requirements;尚缺 owner policy 與 lockfile 決策 |
|
||||
| Docker / compose image policy | `35%` | 已盤點 image refs;尚缺 digest pinning policy、registry owner、rollback owner |
|
||||
| CVE / license / SBOM 驗證 | `0%` | 未執行外部掃描;需 owner window 與工具策略 |
|
||||
| Package / Docker supply-chain owner policy gate | `100%` | 已新增 guard、snapshot 與人讀文件;六個 request 仍 waiting owner policy response |
|
||||
| Node lockfile 基線 | `80%` | `pnpm-lock.yaml` 存在;owner policy gate 已補,但尚未收到 lockfile owner / update window |
|
||||
| Python lock policy | `45%` | 已盤點 pyproject / requirements 並補 owner policy request;尚缺正式 owner response 與 lockfile 決策 |
|
||||
| requirements pinning policy | `35%` | 已盤點 26 條未 pin entry 並補 owner policy request;尚未批准 pinning 或相容性窗口 |
|
||||
| Docker / compose image policy | `45%` | 已盤點 image refs 並補 C0 owner policy request;尚缺 digest pinning policy、registry owner、rollback owner |
|
||||
| CVE / license / SBOM 驗證 | `15%` | 已補 owner policy request;未執行外部掃描,需 owner window 與工具策略 |
|
||||
| runtime gate | `0%` | 未開啟任何執行期閘門 |
|
||||
|
||||
99
docs/security/PACKAGE-SUPPLY-CHAIN-OWNER-POLICY-GATE.md
Normal file
99
docs/security/PACKAGE-SUPPLY-CHAIN-OWNER-POLICY-GATE.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Package / Docker 供應鏈 Owner Policy Gate
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 日期 | 2026-06-15 |
|
||||
| 狀態 | `draft_waiting_owner_policy_response` |
|
||||
| 腳本 | `scripts/security/package-supply-chain-owner-policy-guard.py` |
|
||||
| Snapshot | `docs/security/package-supply-chain-owner-policy-gate.snapshot.json` |
|
||||
| Baseline | `docs/security/package-supply-chain-baseline.snapshot.json` |
|
||||
| 模式 | repo snapshot policy gate,不 install、不 upgrade、不 pull image、不 build image、不 push image |
|
||||
| runtime gate | `0` |
|
||||
|
||||
## 1. 目的
|
||||
|
||||
此 owner policy gate 把 Package / Docker 供應鏈 baseline 的五個缺口轉成六個 owner policy request 草稿,讓後續處理 Python lockfile、requirements pinning、Docker digest pinning、compose image digest、CVE / license / SBOM 時,都必須先有 owner role / team、policy decision、maintenance window、rollback owner 與 redacted evidence refs。
|
||||
|
||||
本 gate 是只讀治理物件,不是套件安裝、升級、pinning、CVE 掃描、SBOM 產生、image pull / build / push、registry login、workflow 修改、production deploy 或 runtime gate。
|
||||
|
||||
## 2. Owner Policy Request
|
||||
|
||||
| Request ID | 分級 | 對應缺口 | 目前狀態 |
|
||||
|------------|------|----------|----------|
|
||||
| `supply_chain_owner_policy:package_manager_lockfile_owner` | C1 | Node / pnpm lockfile owner 與更新窗口 | waiting owner policy response |
|
||||
| `supply_chain_owner_policy:python_lockfile_policy` | C1 | `python_lockfile_absent` | waiting owner policy response |
|
||||
| `supply_chain_owner_policy:requirements_pin_policy` | C1 | `requirements_unpinned_entries_present` | waiting owner policy response |
|
||||
| `supply_chain_owner_policy:dockerfile_digest_pin_policy` | C0 | `docker_base_images_not_all_digest_pinned`、`docker_copy_from_images_not_all_digest_pinned` | waiting owner policy response |
|
||||
| `supply_chain_owner_policy:compose_image_digest_pin_policy` | C0 | `compose_images_not_all_digest_pinned` | waiting owner policy response |
|
||||
| `supply_chain_owner_policy:cve_license_sbom_window` | C1 | CVE / license / SBOM tool 與執行窗口未定 | waiting owner policy response |
|
||||
|
||||
## 3. Required Owner Fields
|
||||
|
||||
1. `package_manager_policy`
|
||||
2. `lockfile_owner`
|
||||
3. `python_lock_policy`
|
||||
4. `docker_base_image_policy`
|
||||
5. `compose_image_policy`
|
||||
6. `registry_owner`
|
||||
7. `cve_scan_window`
|
||||
8. `rollback_owner`
|
||||
|
||||
## 4. Reviewer Checks
|
||||
|
||||
1. owner role / team 必須可追溯,不能只填個人暱稱或未脫敏 repo namespace。
|
||||
2. policy decision 必須明確區分 observe、plan、approve change、reject change。
|
||||
3. Python lockfile 決策必須說明工具、產生位置與相容性驗證方式。
|
||||
4. requirements pinning 決策必須說明 pinning 原則、例外條件與 rollback owner。
|
||||
5. Docker digest pinning 決策必須說明 base image、`COPY --from` image、registry owner 與回復策略。
|
||||
6. compose image digest 決策必須說明 service 範圍、tag / digest 對照與維護窗口。
|
||||
7. CVE / license / SBOM 決策必須說明工具、掃描窗口、結果分級與噪音處理方式。
|
||||
8. evidence refs 只能是脫敏 metadata,不得包含 token、cookie、registry password、private key 或 secret value。
|
||||
9. change evidence 必須能回連到 baseline gap,不得只提供口頭批准。
|
||||
10. runtime gate 必須獨立批准;owner policy accepted 不能自動變成 runtime execution authorized。
|
||||
11. deploy / workflow / registry / image write 必須另有變更證據與 post-check。
|
||||
12. 前台呈現只能顯示脫敏產品 / 控管狀態,不得顯示 raw namespace、內部協作內容或工作視窗對話。
|
||||
|
||||
## 5. Blocked Actions
|
||||
|
||||
本 gate 通過前,以下動作全部維持 blocked:
|
||||
|
||||
1. install package
|
||||
2. upgrade package
|
||||
3. rewrite lockfile
|
||||
4. change requirements pin
|
||||
5. run external CVE lookup
|
||||
6. run external license lookup
|
||||
7. generate SBOM
|
||||
8. docker pull
|
||||
9. docker build
|
||||
10. docker push
|
||||
11. image tag change
|
||||
12. image digest pin change
|
||||
13. registry login
|
||||
14. workflow modification
|
||||
15. runner change
|
||||
16. secret value collection
|
||||
17. production deploy
|
||||
18. runtime execution
|
||||
19. action button enablement
|
||||
20. treat owner policy as runtime approval
|
||||
|
||||
## 6. 不可誤讀
|
||||
|
||||
- `package-supply-chain-baseline.snapshot.json` 只是 repo-only baseline。
|
||||
- `package-supply-chain-owner-policy-gate.snapshot.json` 只是 owner policy gate 草稿。
|
||||
- 所有 request_sent、owner_response_received、owner_response_accepted、runtime_execution_authorized、action_buttons_allowed 仍是 `0 / false`。
|
||||
- `owner policy gate` 通過只代表文件、snapshot 與 guard 對齊,不代表 Python lockfile、requirements pinning、Docker digest pinning、CVE / license / SBOM 已完成。
|
||||
- 本輪不 install、不 upgrade、不 pull image、不 build image、不 push image,不登入 registry、不改 workflow、不改 secret、不部署。
|
||||
|
||||
## 7. 完成度
|
||||
|
||||
| 工作 | 完成度 | 說明 |
|
||||
|------|--------|------|
|
||||
| Package / Docker supply-chain owner policy gate | `100%` | 已新增人讀文件、snapshot 與 guard,並可由總進度 guard 串接 |
|
||||
| Node lockfile owner policy | `45%` | 已有 pnpm lockfile 與 owner policy request;尚未收到 owner response |
|
||||
| Python lock policy | `45%` | 已有 Python lockfile 缺口與 owner policy request;尚未決定工具與 lockfile 策略 |
|
||||
| requirements pinning policy | `35%` | 已有 26 條未 pin entry 的 policy request;尚未批准 pinning 或相容性窗口 |
|
||||
| Docker / compose image policy | `45%` | 已有 C0 digest pinning policy request;尚未批准 digest 變更、registry owner 或 rollback |
|
||||
| CVE / license / SBOM 驗證 | `15%` | 已定義 owner policy request;尚未批准外部掃描窗口或工具 |
|
||||
| runtime gate | `0%` | 未開啟任何執行期閘門 |
|
||||
@@ -3,14 +3,14 @@
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 日期 | 2026-06-15 |
|
||||
| 狀態 | IwoooS 64% 只讀治理推進中;高價值配置集中 guard 與 Package / Docker 供應鏈 repo-only baseline 已完成;CD / Runner / Secret 注入變更證據驗收與 Public / Admin / API runtime config 變更證據驗收只讀帳本已本地完成;端口 / 防火牆變更證據驗收與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 |
|
||||
| 狀態 | IwoooS 64% 只讀治理推進中;高價值配置集中 guard、Package / Docker 供應鏈 repo-only baseline 與 Package / Docker 供應鏈 owner policy gate 已完成;CD / Runner / Secret 注入變更證據驗收與 Public / Admin / API runtime config 變更證據驗收只讀帳本已本地完成;端口 / 防火牆變更證據驗收與 K8s / ArgoCD GitOps 變更證據驗收已正式部署驗證;S4.9 owner response gate 仍是第一優先 |
|
||||
| 本階段完成 | 資安供應鏈 contract manifest + Source Control Approval Board + Draft Reconcile Plan + Ref Detail Diff + Ref Truth Classification + Source Control Ref Truth Owner Response 收件包 + GitHub Primary Readiness Gate + GitHub Primary Rollback ADR + GitHub Target Owner Decision Response 收件包 + Gitea 認證清冊匯出請求 + Gitea 認證清冊匯入驗收契約 + Gitea 清冊覆蓋 Owner Attestation + Gitea Owner Attestation Approval Lane 對齊 + Gitea Owner Attestation Response 收件包 + Workflow / Secret Name Inventory + Workflow / Secret Name Local Evidence + Workflow / Secret Name Redacted Export Request + Workflow / Secret Name Owner Response 收件包 + Source Control Owner Response Validation Rollup + Kali 112 live integration status + Security Finding contract + Kali scan scope approval package + Security Approval Queue + S3 人工批准 Gate + S3 人工決策紀錄 + S3 人工審查封包 + S3 人工決策狀態轉移 + S3 後續 runtime gate 準備契約 + 鏡像 readiness index + 鏡像接收計畫 + 鏡像事件信封 + 鏡像路由矩陣 + 鏡像驗收契約 + 鏡像隔離契約 + 鏡像 dry-run 報告契約 + 鏡像狀態彙整契約 + IwoooS 前端態勢入口 + IwoooS posture projection contract + IwoooS 既有前端資安頁面整合 + IwoooS 覆蓋與邊界矩陣 + IwoooS 只讀資安處理旅程 + IwoooS owner evidence readiness board + IwoooS host coverage view + IwoooS host action gate matrix + IwoooS host evidence readiness board + IwoooS host evidence collection order + IwoooS host evidence intake preflight + IwoooS host evidence review outcome lanes + IwoooS host evidence review handoff packets + IwoooS host evidence reviewer checklist + IwoooS host evidence reviewer outcome lanes + IwoooS host owner decision candidate packets + IwoooS host owner decision review checklist + IwoooS host owner decision review outcome lanes + IwoooS host owner decision record draft packets + IwoooS host owner decision record draft review checklist + IwoooS host owner decision record draft review outcome lanes + IwoooS host owner decision record write-up packets + IwoooS host owner decision record write-up review checklist + IwoooS host owner decision record write-up review outcome lanes + IwoooS host owner decision record formal candidate packets + IwoooS host owner decision record formal candidate review checklist + IwoooS host owner decision record formal candidate review outcome lanes + IwoooS host owner decision record formal record queue packets + IwoooS host owner decision record formal record queue review checklist + IwoooS host owner decision record formal record queue review outcome lanes + IwoooS host owner decision record human handoff readiness packets + IwoooS host owner decision record human handoff readiness review checklist + IwoooS host owner decision record human handoff readiness review outcome lanes + IwoooS host owner decision record human record owner review candidate packets + IwoooS host owner decision record human record owner review candidate checklist + IwoooS host owner decision record human record owner review candidate outcome lanes + IwoooS host owner decision record human record owner review preparation packets + IwoooS host owner decision record human record owner review preparation checklist + IwoooS progress acceleration lanes + IwoooS owner response next-action focus + IwoooS S4.9 owner response preflight + IwoooS S4.9 owner response request templates + IwoooS progress hold movement gates + IwoooS AwoooP read-only landing readiness + IwoooS AwoooP cross-session handoff packets + AwoooP 首頁 IwoooS 資安鏡像候選 + AwoooP 工作鏈路 IwoooS 資安鏡像候選 + AwoooP 審批佇列 IwoooS owner response 只讀焦點 |
|
||||
| 本階段追加 | AwoooP 合約儀表板 IwoooS 資安契約只讀候選 + AwoooP 租戶管理 IwoooS 資安租戶範圍只讀候選 + AwoooP 執行監控 IwoooS 執行狀態只讀候選 + 既有安全 / 合規頁面 IwoooS 只讀反向橋接 + 告警 / 錯誤 / 授權 / 治理頁面 IwoooS 只讀反向橋接 + 稽核 / 工程審查頁面 IwoooS 深色只讀反向橋接 + IwoooS 前端資安頁面連接狀態板 + IwoooS GitHub 主要來源就緒度只讀狀態板 + AwoooP 工作鏈路 GitHub 主要來源就緒度只讀工作項 + AwoooP 合約儀表板 GitHub 主要來源就緒度合約只讀候選 + AwoooP 審批佇列 GitHub 主要來源就緒度審批邊界 + AwoooP 首頁 GitHub 主要來源就緒度只讀摘要 + AwoooP 租戶管理 GitHub 主要來源就緒度租戶範圍 + AwoooP 執行監控 GitHub 主要來源就緒度執行邊界 + IwoooS / AwoooP 資安可視區塊繁體中文呈現防護檢查 + AwoooP 執行詳情 / 審批詳情繁體中文呈現防護檢查 + AwoooP 首頁負責人回覆驗收總覽 + AwoooP 工作鏈路負責人回覆驗收只讀工作項 + AwoooP 合約儀表板負責人回覆驗收契約只讀候選 + AwoooP 審批佇列負責人回覆驗收只讀審查邊界 + AwoooP 租戶管理負責人回覆驗收租戶範圍 + AwoooP 執行監控負責人回覆驗收執行邊界 + AwoooP 執行詳情負責人回覆驗收詳情邊界 + AwoooP 審批決策負責人回覆驗收審批邊界 + IwoooS AwoooP 資安入口覆蓋狀態板 + IwoooS 階段式資安收斂節奏圖 + IwoooS 下一步人工收件作戰板 + IwoooS 人工回覆安全驗收閘道 + IwoooS 人工回覆審查結果分流 + IwoooS 人工決策準備佇列 + IwoooS 人工決策紀錄草稿防誤用 + IwoooS 人工決策正式紀錄負責人指派確認準備包 + IwoooS 人工決策正式紀錄負責人指派確認清單 + IwoooS 人工決策正式紀錄負責人指派確認結果分流 + IwoooS 人工決策正式紀錄負責人指派決策準備包 + IwoooS 人工決策正式紀錄負責人指派決策檢查清單 + IwoooS S4.9 負責人回覆封套欄位 + IwoooS S4.9 負責人回覆封套送件前檢查 + IwoooS S4.9 負責人回覆封套送件前結果分流 + IwoooS S4.9 負責人回覆送件請求草稿 + IwoooS S4.9 負責人回覆送件鏈路摘要 + IwoooS 低摩擦分階段收斂主控 + IwoooS 低摩擦下一步行動邊界 + IwoooS 64% 進度移動訊號驗收條 + IwoooS 第一個進度解鎖路徑 + IwoooS 第一解鎖證據包 + IwoooS 第一解鎖證據包預檢分流 + IwoooS 第一解鎖證據包補件路徑 + IwoooS 第一解鎖證據包補件送審前檢查 + IwoooS 第一解鎖證據包補件送審結果分流 + IwoooS 第一解鎖證據包 reviewer 指派準備包 + IwoooS 第一解鎖證據包 reviewer 指派前檢查 + IwoooS 第一解鎖證據包 reviewer 指派前檢查結果分流 + IwoooS 正式只讀 landing 與 Kali 112 只讀證據進度重估 |
|
||||
| 本階段追加補充 | IwoooS 目前具體工作地圖 + IwoooS 目前具體交付清單 + IwoooS 目前阻塞與解除條件 + IwoooS 三軸進度與全產品套用範圍 + IwoooS 全產品分階段套用台帳 + IwoooS 全產品 rollout 波次驗收門檻 + IwoooS 全產品 rollout 驗收結果分流 + IwoooS 全產品證據接線地圖 + IwoooS 全產品證據接線預檢 + IwoooS 全產品證據接線預檢結果分流 + IwoooS 全產品預檢補件回收台帳 + IwoooS 全產品補件重試門檻 + IwoooS 全產品重試結果分流 + IwoooS 全產品人工審查候選準備 + IwoooS 全產品人工審查候選預檢 + IwoooS 全產品人工審查候選預檢結果分流 + IwoooS 全產品人工審查候選預檢補件回收台帳 + IwoooS 全產品人工審查候選預檢補件重試門檻 + IwoooS 全產品只讀套用快照 + P2-145 owner response acceptance gate 正式驗證完成 |
|
||||
| P0 追加 | IwoooS P0 配置控管優先序前台正式驗證完成;Nginx public gateway、DNS / TLS / certbot、K8s / ArgoCD / production manifests、Workflow / runner / secret metadata、Public / admin / API runtime config、agent-bounty runtime / treasury 六類先列為即時風險配置;高價值配置 Gate 已補上 `k8s/nginx/**`、`scripts/ops/**/*cert*`、`scripts/ops/**/*tls*`,sample 從 `matched=0 / C0=0` 收斂到 `matched=3 / C0=2`;Gate 預設工作樹 preflight 已可讀取 staged / unstaged / untracked,本地 smoke 對臨時 `k8s/nginx/*` 檔命中 C0;Owner Packet snapshot 已同步為 `packets=3 / c0=2`,Coverage snapshot 已同步最新 patterns;IwoooS / AwoooP 前台 Owner Packet 摘要已正式驗證 `packet=3 / c0=2`,feature commit `e999c16b`、deploy marker `16c6b983`、Gitea code-review `2973` / CD `2972` success;IwoooS posture projection snapshot / schema / guard 已同步 `packet=3 / c0=2`,不再保留舊 `1 / 0` 口徑;高價值配置 Owner Packet 收件預檢已新增 `checks=9 / lanes=5 / required_fields=27 / blocked_requests=16`;高價值配置 Owner Request 草稿包已新增 `drafts=3 / handoff_fields=11 / forbidden_payloads=12 / sent=0`;Public Gateway live conf 匯出請求包已新增 `requests=3 / c0=2 / redaction_rules=8 / received=0`;Public Gateway redacted export 收件預檢已新增 `candidates=3 / c0=2 / checks=10 / rejection_guards=12 / received=0 / accepted=0`;Public Gateway rendered diff / nginx gate 草稿已新增 `candidates=3 / c0=2 / stages=7 / blocked=14 / rendered_diff=0 / runtime=0`;Public Gateway owner response acceptance 只讀帳本已新增 `candidates=3 / c0=2 / fields=12 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;DNS / TLS / certbot Owner Confirmation Request 已新增 `requests=4 / c0=4 / fields=9 / questions=5 / guards=12 / received=0 / accepted=0`;K8s / ArgoCD manifest repo-only 清冊已新增 `files=49 / c0=36 / yaml=45 / kinds=20 / blocked=13 / runtime=0`;K8s / ArgoCD Owner Request Draft 已新增 `drafts=4 / c0=3 / fields=11 / sent=0 / runtime=0`;K8s / ArgoCD owner response acceptance 只讀帳本已新增 `candidates=4 / c0=3 / fields=11 / checks=12 / lanes=7 / blocked=18 / accepted=0 / runtime=0`;K8s / ArgoCD GitOps 變更證據驗收已新增 `candidates=4 / c0=3 / write_capable=4 / evidence_fields=18 / checks=18 / lanes=8 / blocked=28 / accepted=0 / runtime=0`;CD / Runner / Secret 注入變更證據驗收已新增 `candidates=5 / c0=4 / write_capable=5 / workflow_files=33 / secret_names=42 / runner_labels=5 / evidence_fields=19 / checks=19 / lanes=8 / blocked=32 / accepted=0 / runtime=0`;Public / Admin / API runtime config 變更證據驗收已新增 `candidates=6 / c0=5 / write_capable=6 / source_refs=20 / evidence_fields=21 / checks=21 / lanes=8 / blocked=32 / accepted=0 / runtime=0`,並把 raw namespace、repo slug、內部狀態碼與內部協作內容外洩列為拒收 / 隔離;Backup / Restore / Escrow owner response acceptance 只讀帳本已新增 `candidates=38 / write_capable=27 / fields=14 / checks=13 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;SSH / Firewall / Network Access owner response acceptance 只讀帳本已新增 `candidates=16 / write_capable=6 / fields=13 / checks=15 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;端口 / 防火牆變更證據驗收只讀帳本已新增 `candidates=14 / write_capable=6 / policy_or_exposure=5 / evidence_fields=16 / checks=16 / lanes=8 / blocked=24 / accepted=0 / runtime=0`;owner response / live evidence / runtime gate / action buttons 仍全部為 0 |
|
||||
| P0 agent-bounty 追加 | agent-bounty-protocol Owner Request Draft 已新增 `drafts=11 / control=4 / surface=7 / write_capable=8 / treasury=4 / mcp_a2a=5 / fields=22 / forbidden_inputs=25 / blocked=28 / sent=0 / runtime=0`;這是 repo / refs、deployment、data classification、MCP / A2A、cron / daemon、admin / treasury、webhook / traffic 的人工送件前草稿,不是 owner response、repo push、refs sync、workflow 修改、secret 收集、deploy、compose restart、DB migration、claim / submit、payout / withdrawal、cron / daemon、external send、host write 或 runtime gate |
|
||||
| P1 追加 | Docker / systemd / Host Service Owner Request Draft 已新增 `drafts=9 / write_capable=3 / fields=12 / blocked=14 / sent=0 / runtime=0`;SSH / Firewall / Network Access Owner Request Draft 已新增 `drafts=16 / write_capable=6 / fields=13 / blocked=16 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Request Draft 已新增 `drafts=38 / write_capable=27 / fields=14 / blocked=18 / sent=0 / runtime=0`;Backup / Restore / Escrow Owner Response Acceptance 已新增 `candidates=38 / write_capable=27 / reviewer_checks=13 / lanes=7 / blocked=22 / accepted=0 / runtime=0`;Monitoring / Alerting / Observability Owner Request Draft 已新增 `drafts=60 / write_capable=11 / fields=14 / blocked=24 / sent=0 / runtime=0`;上述全部仍是人工送件前草稿或只讀 acceptance 帳本,不是 owner response、live evidence、reload、restart、backup、restore、Telegram send、alert smoke、host write 或 runtime gate |
|
||||
| P2 供應鏈追加 | Package / Docker 供應鏈 repo-only baseline 已新增 `package_json=6 / pyproject=4 / requirements=2 / dockerfiles=2 / compose=6 / gaps=5 / runtime=0`;缺口為 Python lockfile 缺席、requirements 未 pin、Docker base image 未全數 digest pinning、Docker `COPY --from` 外部 image 未 digest pinning、compose image 未 digest pinning;目前尚未列入 36 個正式 AwoooP 消費 contract,後續若要前台消費需同步 manifest / readiness / route / rollup / dry-run / posture projection / guard count;本輪不 install、不 upgrade、不跑 CVE、不 pull / build / push image、不改 tag、不登入 registry、不部署 |
|
||||
| P2 供應鏈追加 | Package / Docker 供應鏈 repo-only baseline 已新增 `package_json=6 / pyproject=4 / requirements=2 / dockerfiles=2 / compose=6 / gaps=5 / runtime=0`;Package / Docker 供應鏈 owner policy gate 已新增 `requests=6 / c0=2 / fields=8 / checks=12 / blocked=20 / sent=0 / accepted=0 / runtime=0`;缺口為 Python lockfile 缺席、requirements 未 pin、Docker base image 未全數 digest pinning、Docker `COPY --from` 外部 image 未 digest pinning、compose image 未 digest pinning,以及 CVE / license / SBOM window 未定;目前尚未列入 36 個正式 AwoooP 消費 contract,後續若要前台消費需同步 manifest / readiness / route / rollup / dry-run / posture projection / guard count;本輪不 install、不 upgrade、不跑 CVE、不 pull / build / push image、不改 tag、不登入 registry、不部署 |
|
||||
| 原則 | 低摩擦分階段;文件、schema、read-only evidence 優先;不做 runtime enforcement、不切 primary |
|
||||
| P0 主控板 | `docs/workplans/2026-06-04-iwooos-security-governance-p0.md` |
|
||||
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
{
|
||||
"schema_version": "package_supply_chain_owner_policy_gate_v1",
|
||||
"status": "draft_waiting_owner_policy_response",
|
||||
"mode": "repo_snapshot_policy_gate_no_install_no_network_no_cve_scan",
|
||||
"generated_at": "2026-06-15T07:05:00+08:00",
|
||||
"baseline_ref": "docs/security/package-supply-chain-baseline.snapshot.json",
|
||||
"baseline_git_commit": "1ab85f51",
|
||||
"summary": {
|
||||
"baseline_gap_count": 5,
|
||||
"owner_policy_request_count": 6,
|
||||
"c0_policy_request_count": 2,
|
||||
"write_capable_policy_request_count": 6,
|
||||
"required_owner_field_count": 8,
|
||||
"reviewer_check_count": 12,
|
||||
"blocked_action_count": 20,
|
||||
"owner_policy_request_sent_count": 0,
|
||||
"owner_response_received_count": 0,
|
||||
"owner_response_accepted_count": 0,
|
||||
"owner_response_rejected_count": 0,
|
||||
"runtime_gate_count": 0,
|
||||
"action_button_count": 0
|
||||
},
|
||||
"baseline_gaps": [
|
||||
"python_lockfile_absent",
|
||||
"docker_base_images_not_all_digest_pinned",
|
||||
"docker_copy_from_images_not_all_digest_pinned",
|
||||
"compose_images_not_all_digest_pinned",
|
||||
"requirements_unpinned_entries_present"
|
||||
],
|
||||
"required_owner_fields": [
|
||||
"package_manager_policy",
|
||||
"lockfile_owner",
|
||||
"python_lock_policy",
|
||||
"docker_base_image_policy",
|
||||
"compose_image_policy",
|
||||
"registry_owner",
|
||||
"cve_scan_window",
|
||||
"rollback_owner"
|
||||
],
|
||||
"reviewer_checks": [
|
||||
"owner_role_or_team_present",
|
||||
"decision_present",
|
||||
"decision_reason_present",
|
||||
"affected_scope_present",
|
||||
"redacted_evidence_refs_present",
|
||||
"followup_owner_present",
|
||||
"rollback_owner_present",
|
||||
"package_manager_policy_consistent",
|
||||
"python_lock_policy_consistent",
|
||||
"image_digest_policy_consistent",
|
||||
"cve_license_sbom_window_metadata_only",
|
||||
"no_runtime_or_secret_request_embedded"
|
||||
],
|
||||
"blocked_actions": [
|
||||
"install_package",
|
||||
"upgrade_package",
|
||||
"downgrade_package",
|
||||
"rewrite_lockfile",
|
||||
"pin_requirements_without_owner_policy",
|
||||
"run_npm_audit",
|
||||
"run_pip_audit",
|
||||
"run_external_cve_lookup",
|
||||
"run_external_license_lookup",
|
||||
"generate_sbom",
|
||||
"docker_pull",
|
||||
"docker_build",
|
||||
"docker_push",
|
||||
"change_image_tag",
|
||||
"pin_image_digest_without_owner_policy",
|
||||
"registry_login",
|
||||
"change_workflow",
|
||||
"change_secret",
|
||||
"production_deploy",
|
||||
"open_runtime_gate"
|
||||
],
|
||||
"owner_policy_requests": [
|
||||
{
|
||||
"request_id": "supply_chain_owner_policy:package_manager_lockfile_owner",
|
||||
"label": "Node / pnpm package manager 與 lockfile owner policy",
|
||||
"control_tier": "C1",
|
||||
"status": "draft_waiting_owner_policy_response",
|
||||
"baseline_gap_refs": [
|
||||
"package_manager_policy_required"
|
||||
],
|
||||
"evidence_refs": [
|
||||
"package.json",
|
||||
"pnpm-lock.yaml",
|
||||
"docs/security/package-supply-chain-baseline.snapshot.json"
|
||||
],
|
||||
"required_owner_fields": [
|
||||
"package_manager_policy",
|
||||
"lockfile_owner",
|
||||
"python_lock_policy",
|
||||
"docker_base_image_policy",
|
||||
"compose_image_policy",
|
||||
"registry_owner",
|
||||
"cve_scan_window",
|
||||
"rollback_owner"
|
||||
],
|
||||
"blocked_until": [
|
||||
"owner confirms pnpm lockfile owner",
|
||||
"owner defines lockfile update window",
|
||||
"rollback owner is assigned"
|
||||
],
|
||||
"request_sent": false,
|
||||
"owner_response_received": false,
|
||||
"owner_response_accepted": false,
|
||||
"runtime_gate_open": false
|
||||
},
|
||||
{
|
||||
"request_id": "supply_chain_owner_policy:python_lockfile_policy",
|
||||
"label": "Python lockfile policy",
|
||||
"control_tier": "C1",
|
||||
"status": "draft_waiting_owner_policy_response",
|
||||
"baseline_gap_refs": [
|
||||
"python_lockfile_absent"
|
||||
],
|
||||
"evidence_refs": [
|
||||
"apps/api/pyproject.toml",
|
||||
"packages/lewooogo-brain/pyproject.toml",
|
||||
"packages/lewooogo-data/pyproject.toml",
|
||||
"scripts/aider_watch_client/pyproject.toml",
|
||||
"docs/security/package-supply-chain-baseline.snapshot.json"
|
||||
],
|
||||
"required_owner_fields": [
|
||||
"package_manager_policy",
|
||||
"lockfile_owner",
|
||||
"python_lock_policy",
|
||||
"docker_base_image_policy",
|
||||
"compose_image_policy",
|
||||
"registry_owner",
|
||||
"cve_scan_window",
|
||||
"rollback_owner"
|
||||
],
|
||||
"blocked_until": [
|
||||
"owner selects poetry.lock / uv.lock / Pipfile.lock policy",
|
||||
"compatibility owner confirms scope",
|
||||
"rollback owner is assigned"
|
||||
],
|
||||
"request_sent": false,
|
||||
"owner_response_received": false,
|
||||
"owner_response_accepted": false,
|
||||
"runtime_gate_open": false
|
||||
},
|
||||
{
|
||||
"request_id": "supply_chain_owner_policy:requirements_pin_policy",
|
||||
"label": "requirements pinning policy",
|
||||
"control_tier": "C1",
|
||||
"status": "draft_waiting_owner_policy_response",
|
||||
"baseline_gap_refs": [
|
||||
"requirements_unpinned_entries_present"
|
||||
],
|
||||
"evidence_refs": [
|
||||
"apps/api/requirements.txt",
|
||||
"apps/sensor/requirements.txt",
|
||||
"docs/security/package-supply-chain-baseline.snapshot.json"
|
||||
],
|
||||
"required_owner_fields": [
|
||||
"package_manager_policy",
|
||||
"lockfile_owner",
|
||||
"python_lock_policy",
|
||||
"docker_base_image_policy",
|
||||
"compose_image_policy",
|
||||
"registry_owner",
|
||||
"cve_scan_window",
|
||||
"rollback_owner"
|
||||
],
|
||||
"blocked_until": [
|
||||
"owner defines pinning approach",
|
||||
"compatibility test owner is assigned",
|
||||
"rollback owner is assigned"
|
||||
],
|
||||
"request_sent": false,
|
||||
"owner_response_received": false,
|
||||
"owner_response_accepted": false,
|
||||
"runtime_gate_open": false
|
||||
},
|
||||
{
|
||||
"request_id": "supply_chain_owner_policy:dockerfile_digest_pin_policy",
|
||||
"label": "Dockerfile base image / COPY --from digest policy",
|
||||
"control_tier": "C0",
|
||||
"status": "draft_waiting_owner_policy_response",
|
||||
"baseline_gap_refs": [
|
||||
"docker_base_images_not_all_digest_pinned",
|
||||
"docker_copy_from_images_not_all_digest_pinned"
|
||||
],
|
||||
"evidence_refs": [
|
||||
"apps/api/Dockerfile",
|
||||
"apps/web/Dockerfile",
|
||||
"docs/security/package-supply-chain-baseline.snapshot.json"
|
||||
],
|
||||
"required_owner_fields": [
|
||||
"package_manager_policy",
|
||||
"lockfile_owner",
|
||||
"python_lock_policy",
|
||||
"docker_base_image_policy",
|
||||
"compose_image_policy",
|
||||
"registry_owner",
|
||||
"cve_scan_window",
|
||||
"rollback_owner"
|
||||
],
|
||||
"blocked_until": [
|
||||
"registry owner confirms digest source",
|
||||
"image compatibility owner confirms scope",
|
||||
"rollback owner is assigned"
|
||||
],
|
||||
"request_sent": false,
|
||||
"owner_response_received": false,
|
||||
"owner_response_accepted": false,
|
||||
"runtime_gate_open": false
|
||||
},
|
||||
{
|
||||
"request_id": "supply_chain_owner_policy:compose_image_digest_pin_policy",
|
||||
"label": "docker-compose image digest policy",
|
||||
"control_tier": "C0",
|
||||
"status": "draft_waiting_owner_policy_response",
|
||||
"baseline_gap_refs": [
|
||||
"compose_images_not_all_digest_pinned"
|
||||
],
|
||||
"evidence_refs": [
|
||||
"apps/api/docker-compose.test.yml",
|
||||
"docker-compose.yml",
|
||||
"infra/langfuse/docker-compose.yml",
|
||||
"k8s/monitoring/docker-compose-110.yml",
|
||||
"ops/monitoring/docker-compose.exporters.yaml",
|
||||
"ops/sentry-self-hosted/docker-compose.yml",
|
||||
"docs/security/package-supply-chain-baseline.snapshot.json"
|
||||
],
|
||||
"required_owner_fields": [
|
||||
"package_manager_policy",
|
||||
"lockfile_owner",
|
||||
"python_lock_policy",
|
||||
"docker_base_image_policy",
|
||||
"compose_image_policy",
|
||||
"registry_owner",
|
||||
"cve_scan_window",
|
||||
"rollback_owner"
|
||||
],
|
||||
"blocked_until": [
|
||||
"registry owner confirms digest source",
|
||||
"compose service owner confirms blast radius",
|
||||
"rollback owner is assigned"
|
||||
],
|
||||
"request_sent": false,
|
||||
"owner_response_received": false,
|
||||
"owner_response_accepted": false,
|
||||
"runtime_gate_open": false
|
||||
},
|
||||
{
|
||||
"request_id": "supply_chain_owner_policy:cve_license_sbom_window",
|
||||
"label": "CVE / license / SBOM 驗證窗口 policy",
|
||||
"control_tier": "C1",
|
||||
"status": "draft_waiting_owner_policy_response",
|
||||
"baseline_gap_refs": [
|
||||
"cve_license_sbom_not_run"
|
||||
],
|
||||
"evidence_refs": [
|
||||
"docs/security/PACKAGE-SUPPLY-CHAIN-BASELINE.md",
|
||||
"docs/security/package-supply-chain-baseline.snapshot.json"
|
||||
],
|
||||
"required_owner_fields": [
|
||||
"package_manager_policy",
|
||||
"lockfile_owner",
|
||||
"python_lock_policy",
|
||||
"docker_base_image_policy",
|
||||
"compose_image_policy",
|
||||
"registry_owner",
|
||||
"cve_scan_window",
|
||||
"rollback_owner"
|
||||
],
|
||||
"blocked_until": [
|
||||
"owner selects allowed tools",
|
||||
"network / cost / runtime boundary is confirmed",
|
||||
"rollback owner is assigned"
|
||||
],
|
||||
"request_sent": false,
|
||||
"owner_response_received": false,
|
||||
"owner_response_accepted": false,
|
||||
"runtime_gate_open": false
|
||||
}
|
||||
],
|
||||
"execution_boundaries": {
|
||||
"package_installation_allowed": false,
|
||||
"package_upgrade_allowed": false,
|
||||
"lockfile_write_allowed": false,
|
||||
"requirements_pin_change_allowed": false,
|
||||
"external_cve_lookup_allowed": false,
|
||||
"external_license_lookup_allowed": false,
|
||||
"sbom_generation_allowed": false,
|
||||
"docker_pull_allowed": false,
|
||||
"docker_build_allowed": false,
|
||||
"docker_push_allowed": false,
|
||||
"image_tag_change_allowed": false,
|
||||
"image_digest_pin_change_allowed": false,
|
||||
"registry_login_allowed": false,
|
||||
"workflow_modification_authorized": false,
|
||||
"production_deploy_authorized": false,
|
||||
"runtime_execution_authorized": false,
|
||||
"action_buttons_allowed": false,
|
||||
"secret_value_collection_allowed": false,
|
||||
"runtime_gate_count": 0,
|
||||
"not_authorization": true
|
||||
},
|
||||
"operator_interpretation": [
|
||||
"此 owner policy gate 只把 package / Docker baseline 缺口轉成 owner metadata 收件草案。",
|
||||
"通過此 gate 不代表可 install、upgrade、pin requirements、寫 lockfile、pull / build / push image、跑 CVE / license / SBOM 或登入 registry。",
|
||||
"C0 Docker / compose digest policy 仍需 registry owner、rollback owner 與相容性證據,不得自動改 tag 或 digest。",
|
||||
"owner policy request sent、received、accepted、runtime gate 與 action button 全部維持 0 / false。"
|
||||
]
|
||||
}
|
||||
@@ -169,6 +169,34 @@
|
||||
"production_deploy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"step_id": "CHECK_PACKAGE_SUPPLY_CHAIN_OWNER_POLICY_GUARD",
|
||||
"expected_observation": "AwoooP dry-run 必須確認 Package / Docker 供應鏈 baseline 的五個缺口已轉成 owner policy gate,六個 request、兩個 C0、八個 owner 欄位、十二個 reviewer checks、二十個 blocked actions 齊備,且 request_sent / received / accepted / runtime / action 全部維持 0 / false。",
|
||||
"evidence_refs": [
|
||||
"docs/security/PACKAGE-SUPPLY-CHAIN-BASELINE.md",
|
||||
"docs/security/package-supply-chain-baseline.snapshot.json",
|
||||
"docs/security/PACKAGE-SUPPLY-CHAIN-OWNER-POLICY-GATE.md",
|
||||
"docs/security/package-supply-chain-owner-policy-gate.snapshot.json",
|
||||
"scripts/security/package-supply-chain-owner-policy-guard.py"
|
||||
],
|
||||
"pass_condition": "`python3 scripts/security/package-supply-chain-owner-policy-guard.py` 回傳 PACKAGE_SUPPLY_CHAIN_OWNER_POLICY_GUARD_OK,且不 install、不 upgrade、不跑外部 CVE / license lookup、不產生 SBOM、不 pull / build / push image、不登入 registry。",
|
||||
"execution_allowed": false,
|
||||
"blocked_actions": [
|
||||
"install_package",
|
||||
"upgrade_package",
|
||||
"rewrite_lockfile",
|
||||
"pin_requirements_without_owner_policy",
|
||||
"run_external_cve_lookup",
|
||||
"run_external_license_lookup",
|
||||
"generate_sbom",
|
||||
"docker_pull",
|
||||
"docker_build",
|
||||
"docker_push",
|
||||
"registry_login",
|
||||
"production_deploy",
|
||||
"open_runtime_gate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"step_id": "CHECK_LOW_NOISE_CHANNEL",
|
||||
"expected_observation": "Channel Event 初期只發低噪音摘要或人工批准必要事件。",
|
||||
@@ -208,8 +236,8 @@
|
||||
"status": "repo_snapshot_guard_pass",
|
||||
"date": "2026-06-15",
|
||||
"scope": "repo_snapshot_only",
|
||||
"command": "python3 scripts/security/security-mirror-progress-guard.py && python3 scripts/security/source-control-owner-response-guard.py && python3 scripts/security/iwooos-config-control-guard.py && python3 scripts/security/iwooos-owner-gate-guard.py",
|
||||
"result": "SECURITY_MIRROR_PROGRESS_GUARD_OK; SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK; IWOOOS_CONFIG_CONTROL_GUARD_OK; IWOOOS_OWNER_GATE_GUARD_OK",
|
||||
"command": "python3 scripts/security/security-mirror-progress-guard.py && python3 scripts/security/source-control-owner-response-guard.py && python3 scripts/security/iwooos-config-control-guard.py && python3 scripts/security/iwooos-owner-gate-guard.py && python3 scripts/security/package-supply-chain-owner-policy-guard.py",
|
||||
"result": "SECURITY_MIRROR_PROGRESS_GUARD_OK; SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK; IWOOOS_CONFIG_CONTROL_GUARD_OK; IWOOOS_OWNER_GATE_GUARD_OK; PACKAGE_SUPPLY_CHAIN_OWNER_POLICY_GUARD_OK",
|
||||
"validated_steps": [
|
||||
"LOAD_CONTRACT_INDEXES",
|
||||
"CHECK_ACCEPTANCE_AND_QUARANTINE",
|
||||
@@ -217,6 +245,7 @@
|
||||
"CHECK_OWNER_RESPONSE_GUARD",
|
||||
"CHECK_OWNER_GATE_GUARD",
|
||||
"CHECK_CONFIG_CONTROL_GUARD",
|
||||
"CHECK_PACKAGE_SUPPLY_CHAIN_OWNER_POLICY_GUARD",
|
||||
"CONFIRM_NO_RUNTIME_ACTION"
|
||||
],
|
||||
"runtime_actions_executed": false,
|
||||
|
||||
211
scripts/security/package-supply-chain-owner-policy-guard.py
Normal file
211
scripts/security/package-supply-chain-owner-policy-guard.py
Normal file
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python3
|
||||
"""驗證 Package / Docker 供應鏈 owner policy gate 維持只讀邊界。
|
||||
|
||||
本 guard 只讀取 repo 內的 package / Docker 供應鏈 baseline 與 owner
|
||||
policy gate snapshot,不安裝套件、不連外查 CVE / license、不產生 lockfile、
|
||||
不 pull / build / push image,也不修改 workflow、registry 或 production。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
EXPECTED_BASELINE_GAPS = [
|
||||
"python_lockfile_absent",
|
||||
"docker_base_images_not_all_digest_pinned",
|
||||
"docker_copy_from_images_not_all_digest_pinned",
|
||||
"compose_images_not_all_digest_pinned",
|
||||
"requirements_unpinned_entries_present",
|
||||
]
|
||||
|
||||
EXPECTED_REQUEST_IDS = [
|
||||
"supply_chain_owner_policy:package_manager_lockfile_owner",
|
||||
"supply_chain_owner_policy:python_lockfile_policy",
|
||||
"supply_chain_owner_policy:requirements_pin_policy",
|
||||
"supply_chain_owner_policy:dockerfile_digest_pin_policy",
|
||||
"supply_chain_owner_policy:compose_image_digest_pin_policy",
|
||||
"supply_chain_owner_policy:cve_license_sbom_window",
|
||||
]
|
||||
|
||||
EXPECTED_OWNER_FIELDS = [
|
||||
"package_manager_policy",
|
||||
"lockfile_owner",
|
||||
"python_lock_policy",
|
||||
"docker_base_image_policy",
|
||||
"compose_image_policy",
|
||||
"registry_owner",
|
||||
"cve_scan_window",
|
||||
"rollback_owner",
|
||||
]
|
||||
|
||||
FALSE_BOUNDARY_KEYS = [
|
||||
"package_installation_allowed",
|
||||
"package_upgrade_allowed",
|
||||
"lockfile_write_allowed",
|
||||
"requirements_pin_change_allowed",
|
||||
"external_cve_lookup_allowed",
|
||||
"external_license_lookup_allowed",
|
||||
"sbom_generation_allowed",
|
||||
"docker_pull_allowed",
|
||||
"docker_build_allowed",
|
||||
"docker_push_allowed",
|
||||
"image_tag_change_allowed",
|
||||
"image_digest_pin_change_allowed",
|
||||
"registry_login_allowed",
|
||||
"workflow_modification_authorized",
|
||||
"production_deploy_authorized",
|
||||
"runtime_execution_authorized",
|
||||
"action_buttons_allowed",
|
||||
"secret_value_collection_allowed",
|
||||
]
|
||||
|
||||
|
||||
def fail(message: str) -> None:
|
||||
raise SystemExit(f"BLOCKED {message}")
|
||||
|
||||
|
||||
def load_json(path: Path) -> dict[str, Any]:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def assert_equal(label: str, actual: Any, expected: Any) -> None:
|
||||
if actual != expected:
|
||||
fail(f"{label}: expected {expected!r}, got {actual!r}")
|
||||
|
||||
|
||||
def assert_path_exists(root: Path, relative_path: str) -> None:
|
||||
if not (root / relative_path).exists():
|
||||
fail(f"path missing: {relative_path}")
|
||||
|
||||
|
||||
def assert_text_contains(label: str, text: str, expected: str) -> None:
|
||||
if expected not in text:
|
||||
fail(f"{label}: missing {expected!r}")
|
||||
|
||||
|
||||
def assert_false_boundaries(label: str, data: dict[str, Any]) -> None:
|
||||
boundaries = data.get("execution_boundaries", {})
|
||||
for key in FALSE_BOUNDARY_KEYS:
|
||||
assert_equal(f"{label}.execution_boundaries.{key}", boundaries.get(key), False)
|
||||
assert_equal(f"{label}.execution_boundaries.runtime_gate_count", boundaries.get("runtime_gate_count"), 0)
|
||||
assert_equal(f"{label}.execution_boundaries.not_authorization", boundaries.get("not_authorization"), True)
|
||||
|
||||
|
||||
def validate_baseline(root: Path) -> dict[str, Any]:
|
||||
baseline_path = root / "docs/security/package-supply-chain-baseline.snapshot.json"
|
||||
assert_path_exists(root, "docs/security/package-supply-chain-baseline.snapshot.json")
|
||||
baseline = load_json(baseline_path)
|
||||
summary = baseline.get("summary", {})
|
||||
|
||||
assert_equal("baseline.schema_version", baseline.get("schema_version"), "package_supply_chain_baseline_v1")
|
||||
assert_equal("baseline.status", baseline.get("status"), "repo_only_inventory_ready_needs_owner_policy")
|
||||
assert_equal("baseline.mode", baseline.get("mode"), "repo_snapshot_only_no_install_no_network_no_cve_scan")
|
||||
assert_equal("baseline.summary.package_json_count", summary.get("package_json_count"), 6)
|
||||
assert_equal("baseline.summary.pyproject_count", summary.get("pyproject_count"), 4)
|
||||
assert_equal("baseline.summary.requirements_file_count", summary.get("requirements_file_count"), 2)
|
||||
assert_equal("baseline.summary.requirements_unpinned_entry_count", summary.get("requirements_unpinned_entry_count"), 26)
|
||||
assert_equal("baseline.summary.python_lockfile_count", summary.get("python_lockfile_count"), 0)
|
||||
assert_equal("baseline.summary.docker_base_digest_pinned_count", summary.get("docker_base_digest_pinned_count"), 0)
|
||||
assert_equal(
|
||||
"baseline.summary.compose_digest_pinned_image_ref_count",
|
||||
summary.get("compose_digest_pinned_image_ref_count"),
|
||||
0,
|
||||
)
|
||||
assert_equal("baseline.summary.gap_count", summary.get("gap_count"), 5)
|
||||
assert_equal("baseline.gaps", baseline.get("gaps"), EXPECTED_BASELINE_GAPS)
|
||||
assert_equal("baseline.owner_response_received_count", summary.get("owner_response_received_count"), 0)
|
||||
assert_equal("baseline.owner_response_accepted_count", summary.get("owner_response_accepted_count"), 0)
|
||||
assert_equal("baseline.runtime_gate_count", summary.get("runtime_gate_count"), 0)
|
||||
assert_equal("baseline.action_button_count", summary.get("action_button_count"), 0)
|
||||
|
||||
for relative_path in baseline.get("lockfiles", []):
|
||||
assert_path_exists(root, relative_path)
|
||||
for key in ["package_json_manifests", "pyproject_manifests", "requirements_files", "dockerfiles", "compose_files"]:
|
||||
for item in baseline.get(key, []):
|
||||
assert_path_exists(root, item["path"])
|
||||
return baseline
|
||||
|
||||
|
||||
def validate_policy_gate(root: Path, baseline: dict[str, Any]) -> None:
|
||||
gate_path = root / "docs/security/package-supply-chain-owner-policy-gate.snapshot.json"
|
||||
doc_path = root / "docs/security/PACKAGE-SUPPLY-CHAIN-OWNER-POLICY-GATE.md"
|
||||
assert_path_exists(root, "docs/security/package-supply-chain-owner-policy-gate.snapshot.json")
|
||||
assert_path_exists(root, "docs/security/PACKAGE-SUPPLY-CHAIN-OWNER-POLICY-GATE.md")
|
||||
gate = load_json(gate_path)
|
||||
summary = gate.get("summary", {})
|
||||
|
||||
assert_equal("policy_gate.schema_version", gate.get("schema_version"), "package_supply_chain_owner_policy_gate_v1")
|
||||
assert_equal("policy_gate.status", gate.get("status"), "draft_waiting_owner_policy_response")
|
||||
assert_equal("policy_gate.mode", gate.get("mode"), "repo_snapshot_policy_gate_no_install_no_network_no_cve_scan")
|
||||
assert_equal("policy_gate.baseline_ref", gate.get("baseline_ref"), "docs/security/package-supply-chain-baseline.snapshot.json")
|
||||
assert_equal("policy_gate.summary.baseline_gap_count", summary.get("baseline_gap_count"), baseline["summary"]["gap_count"])
|
||||
assert_equal("policy_gate.summary.owner_policy_request_count", summary.get("owner_policy_request_count"), 6)
|
||||
assert_equal("policy_gate.summary.c0_policy_request_count", summary.get("c0_policy_request_count"), 2)
|
||||
assert_equal("policy_gate.summary.write_capable_policy_request_count", summary.get("write_capable_policy_request_count"), 6)
|
||||
assert_equal("policy_gate.summary.required_owner_field_count", summary.get("required_owner_field_count"), 8)
|
||||
assert_equal("policy_gate.summary.reviewer_check_count", summary.get("reviewer_check_count"), 12)
|
||||
assert_equal("policy_gate.summary.blocked_action_count", summary.get("blocked_action_count"), 20)
|
||||
assert_equal("policy_gate.summary.owner_policy_request_sent_count", summary.get("owner_policy_request_sent_count"), 0)
|
||||
assert_equal("policy_gate.summary.owner_response_received_count", summary.get("owner_response_received_count"), 0)
|
||||
assert_equal("policy_gate.summary.owner_response_accepted_count", summary.get("owner_response_accepted_count"), 0)
|
||||
assert_equal("policy_gate.summary.owner_response_rejected_count", summary.get("owner_response_rejected_count"), 0)
|
||||
assert_equal("policy_gate.summary.runtime_gate_count", summary.get("runtime_gate_count"), 0)
|
||||
assert_equal("policy_gate.summary.action_button_count", summary.get("action_button_count"), 0)
|
||||
assert_equal("policy_gate.baseline_gaps", gate.get("baseline_gaps"), EXPECTED_BASELINE_GAPS)
|
||||
assert_equal("policy_gate.required_owner_fields", gate.get("required_owner_fields"), EXPECTED_OWNER_FIELDS)
|
||||
assert_equal("policy_gate.owner_policy_request_ids", [item["request_id"] for item in gate["owner_policy_requests"]], EXPECTED_REQUEST_IDS)
|
||||
|
||||
for item in gate["owner_policy_requests"]:
|
||||
assert_equal(f"{item['request_id']}.status", item.get("status"), "draft_waiting_owner_policy_response")
|
||||
assert_equal(f"{item['request_id']}.required_owner_fields", item.get("required_owner_fields"), EXPECTED_OWNER_FIELDS)
|
||||
assert_equal(f"{item['request_id']}.request_sent", item.get("request_sent"), False)
|
||||
assert_equal(f"{item['request_id']}.owner_response_received", item.get("owner_response_received"), False)
|
||||
assert_equal(f"{item['request_id']}.owner_response_accepted", item.get("owner_response_accepted"), False)
|
||||
assert_equal(f"{item['request_id']}.runtime_gate_open", item.get("runtime_gate_open"), False)
|
||||
if not item.get("baseline_gap_refs"):
|
||||
fail(f"{item['request_id']}.baseline_gap_refs: expected non-empty list")
|
||||
for ref in item.get("evidence_refs", []):
|
||||
assert_path_exists(root, ref)
|
||||
if not item.get("blocked_until"):
|
||||
fail(f"{item['request_id']}.blocked_until: expected non-empty list")
|
||||
|
||||
assert_false_boundaries("policy_gate", gate)
|
||||
|
||||
doc = doc_path.read_text(encoding="utf-8")
|
||||
for text in [
|
||||
"owner policy gate",
|
||||
"Python lockfile",
|
||||
"requirements pinning",
|
||||
"Docker digest pinning",
|
||||
"CVE / license / SBOM",
|
||||
"runtime gate",
|
||||
"0 / false",
|
||||
"不 install、不 upgrade、不 pull image、不 build image、不 push image",
|
||||
]:
|
||||
assert_text_contains("policy_gate.doc", doc, text)
|
||||
|
||||
|
||||
def validate(root: Path) -> None:
|
||||
baseline = validate_baseline(root)
|
||||
validate_policy_gate(root, baseline)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--root",
|
||||
default=Path(__file__).resolve().parents[2],
|
||||
type=Path,
|
||||
help="Repository root. Defaults to the current script's repository.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
validate(args.root.resolve())
|
||||
print("PACKAGE_SUPPLY_CHAIN_OWNER_POLICY_GUARD_OK")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -79,6 +79,10 @@ def validate(root: Path) -> None:
|
||||
config_control_guard["validate"](root)
|
||||
owner_gate_guard = runpy.run_path(str(root / "scripts" / "security" / "iwooos-owner-gate-guard.py"))
|
||||
owner_gate_guard["validate"](root)
|
||||
package_policy_guard = runpy.run_path(
|
||||
str(root / "scripts" / "security" / "package-supply-chain-owner-policy-guard.py")
|
||||
)
|
||||
package_policy_guard["validate"](root)
|
||||
|
||||
manifest = load_json(security_dir / "security-supply-chain-contract-manifest.snapshot.json")
|
||||
readiness = load_json(security_dir / "security-mirror-readiness.snapshot.json")
|
||||
@@ -24992,7 +24996,7 @@ def validate(root: Path) -> None:
|
||||
assert_equal(
|
||||
"dry_run.latest_local_validation.result",
|
||||
local_validation["result"],
|
||||
"SECURITY_MIRROR_PROGRESS_GUARD_OK; SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK; IWOOOS_CONFIG_CONTROL_GUARD_OK; IWOOOS_OWNER_GATE_GUARD_OK",
|
||||
"SECURITY_MIRROR_PROGRESS_GUARD_OK; SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK; IWOOOS_CONFIG_CONTROL_GUARD_OK; IWOOOS_OWNER_GATE_GUARD_OK; PACKAGE_SUPPLY_CHAIN_OWNER_POLICY_GUARD_OK",
|
||||
)
|
||||
assert_contains("dry_run.latest_local_validation.validated_steps", local_validation["validated_steps"], "CHECK_PROGRESS_GUARD")
|
||||
assert_contains(
|
||||
@@ -25010,6 +25014,11 @@ def validate(root: Path) -> None:
|
||||
local_validation["validated_steps"],
|
||||
"CHECK_CONFIG_CONTROL_GUARD",
|
||||
)
|
||||
assert_contains(
|
||||
"dry_run.latest_local_validation.validated_steps",
|
||||
local_validation["validated_steps"],
|
||||
"CHECK_PACKAGE_SUPPLY_CHAIN_OWNER_POLICY_GUARD",
|
||||
)
|
||||
assert_false("dry_run.latest_local_validation.runtime_actions_executed", local_validation["runtime_actions_executed"])
|
||||
assert_false("dry_run.latest_local_validation.payloads_ingested", local_validation["payloads_ingested"])
|
||||
assert_false("dry_run.latest_local_validation.production_ingestion_enabled", local_validation["production_ingestion_enabled"])
|
||||
|
||||
Reference in New Issue
Block a user