# 原始碼弱點掃描與 SBOM 報表（給非技術顧問看的）

> 白話需求草稿，Phase 0。起稿 2026-10-10，起因是同日排查 SBOM 工具相容性時決策者提出。
> 下一步：開新 session 照 `big-feature-workflow` 討論，登記 FR 號（2026-10-10 時最大號 FR-133）。

## 原由

**產品現況**：我們出貨時已經會產 SBOM（軟體物料清單），走 `scripts/build/sbom.sh`：
Syft 掃 `poetry.lock`／`package-lock.json` 與五顆 image，輸出 CycloneDX 1.7 JSON；
弱點由 pip-audit（Python 套件）與 Trivy＋Grype 雙掃（image）判定，`vuln_gate.py` 對照
白名單，白名單外有 Critical 就不出包。這整套只服務**我們自己的出貨流程**，客戶看不到、
也用不上。

**觸發事件**：2026-10-10 拿國家資通安全研究院的 ex-sbom（圖形化 SBOM 檢視工具）試讀我們的
SBOM，被擋在「不認 CycloneDX 1.7」（它內建的解析套件停在 1.6）。排查過程順帶發現：
市面上解析 SBOM、呈現弱點的工具，**全部是給工程師看的**——CVE 編號、CVSS 向量、purl、
依賴拓撲圖。沒有一個是讓非技術人員能看懂「這個專案現在有多危險」的。

**真正的痛點**（決策者原話整理）：顧問在輔導客戶時，理論上專案弱點狀況該由客戶的工程師
盤點並回報，但實務上工程師最愛閃躲——「那個不嚴重」「我們環境打不到」「下個版本會修」，
顧問沒有技術背景，無從判斷是真是假，只能被敷衍帶過。**這個功能的用意，就是讓不會工程技術
的顧問，自己就能知道專案／產品的弱點在哪、多嚴重、修了沒**，拿著有工具原始輸出背書的報表
去跟工程師對話，工程師閃不掉。

**為什麼是我們做**：Guidant AI 的使用者就是顧問與稽核人員，而且我們手上已經有整條
「產 SBOM → 雙工具掃弱點 → 判定」的管線（FR-127／FR-128 建的），只差把它從出貨腳本搬進
產品、加上給人看的那一層。「給非技術人看、可交付、品牌化的弱點報表」這塊市面上是空的，
可以是產品亮點。

## 我想解決什麼問題

顧問拿到客戶的原始碼或 git repo 後，不需要工程師協助，就能：

1. 產出這個專案的 SBOM（支援多種格式、多種工具）
2. 用多種工具解析，看各工具各自報了什麼弱點
3. 在系統內瀏覽結果——**用白話呈現**，不是 CVE 清單
4. 匯出各類報表（PDF／HTML／DOCX），可以直接交給客戶或拿去跟工程師對質

## 客戶情境

- 顧問 A 輔導某客戶做 ISO 27001，客戶有一套自己開發的內部系統。顧問想知道這套系統用了哪些
  第三方套件、有沒有已知弱點，問工程師得到「都有在更新」。顧問把 repo 位置丟進 Guidant AI，
  十分鐘後拿到報表：568 個 npm 套件、12 個高風險弱點、其中 3 個有公開攻擊程式、最老的一個
  2023 年就該修。顧問拿這份報表開會，工程師無法再說「都有在更新」。
- 顧問 B 要出客戶的年度資安評估報告，其中一節是「第三方元件風險」。以前這節要請工程師提供
  資料、再自己整理成客戶看得懂的文字，來回一兩週。現在系統直接產這一節的 DOCX，附上 SBOM
  當附件。
- 顧問 C 三個月後回訪同一客戶，重掃一次，報表直接顯示「上次 12 個高風險，這次剩 4 個，新增
  2 個」——修了沒，一眼看到。

## 預期效果

- 輸入：上傳原始碼壓縮檔，或填 git repo 位置（含私有 repo 的憑證）
- 輸出 SBOM：CycloneDX 與 SPDX 兩種格式都要（應用安全圈偏 CycloneDX，法規與授權合規偏 SPDX，
  美國政府採購兩者皆可），版本可選（有些下游工具只認舊版，如 ex-sbom 只認 1.6）
- 解析：包現成工具（Syft／cdxgen 產生；Trivy／Grype／osv-scanner 查弱點），**絕對不自己造輪子**，
  成本放在把各工具輸出正規化成我們自己的資料模型
- 瀏覽：同一份 SBOM 跨工具對照——Trivy 說有、Grype 說沒有、各自的分數不同，都攤開讓顧問看到；
  再加授權風險、SBOM 品質分數（NTIA 最低要素齊不齊）
- 報表：給非技術人看的版本（這專案有多危險、哪幾個最急、修了沒），每個數字都能追到工具原始
  輸出（顧問說「Trivy 10 月 8 日就報了這個 Critical」，工程師不能說沒有）。PDF 走 WeasyPrint、
  DOCX 走 python-docx，兩者產品內都有先例
- 歷次比對：同一專案多次掃描的差異（修了幾個、新增幾個）

## 已知限制 / 風險（白話想法，待精化）

- **從原始碼產 SBOM 的準確度取決於有沒有 lock 檔**。只有 `package.json` 沒有 lock 時，工具只能
  猜版本範圍；要準就得實際跑建置工具解析（cdxgen 走這條路），代價是要在我們環境執行客戶的
  建置腳本，這是安全問題，要在設計時決定做不做、做到哪
- **跑客戶的 repo 等於執行不受信任的輸入**。clone 與掃描都要隔離。產品已有 `guidant-sandbox`
  （FR-122，純拆檔、無金鑰、不出網、唯讀 rootfs、cap_drop ALL），但掃描沙箱有兩個不同處：
  要能出網 clone git（白名單 git host）、要裝掃描工具與弱點資料庫。所以不是直接塞進現有容器，
  而是把「沙箱」從「一個容器」升級成「一種容器樣板」——共用加固形狀，各自不同 image 與網路
  政策。決策者已明示未來會越來越多類似功能，這個抽象該做。守衛測試
  `test/security/code/test_security_shape_container_hardening.py` 把 sandbox 列在自家四容器，
  形狀改動會被擋，要有意識地改
- **弱點資料庫要能離線**。落地版客戶常是封閉網路，Trivy／Grype 的資料庫（Grype 約 3GB）要能
  隨安裝包帶進去並定期更新，不然裝好弱點永遠是零。這是出貨包與升級流程的一環，不只是功能本身。
  ex-sbom 必須連網查 OSV，正是落地版不能直接用它的原因
- **多工具結果不一致是常態**。osv-scanner 對 Debian／Ubuntu 判不準（這是我們出貨管線不用它的
  原因），各工具 CVSS 來源也不同。對顧問來說「兩個工具說法不同」本身要有白話解釋，不能丟兩張表
- **掃描時間與資源**。大型 repo 加弱點比對可能要跑好幾分鐘，走背景 job（`RUN_MODE=worker` 已有
  機制）；沙箱資源上限要訂
- **私有 repo 憑證**：顧問填的 git token 是客戶的祕密，儲存、使用、銷毀都要照
  `.claude/rules/security/` 祕密與上傳解析兩支的規則

## 參考資料

- 現有出貨管線：`scripts/build/sbom.sh`、`scripts/build/vuln_gate.py`、`scripts/build/vuln-allowlist.txt`、
  `scripts/build/README.md`「sbom.sh」列與 CI 段
- 現有沙箱：`docs/features/FR-122-2609-ai-gateway-and-sandbox/design.md`、
  `docker/production/docker-compose.yml` 的 `guidant-sandbox` 服務段與 `guidant-sandbox` network 段
- 既有報表產出先例：摘要報告 PDF（WeasyPrint）、`docs/system-design/` DOCX（python-docx，見
  `docs/claude/docs-conventions.md`）
- 業界對照：
  - 產生：Syft、Trivy、cdxgen（OWASP／CycloneDX 官方，支援語言最廣）、osv-scalibr（Google）
  - 平台：OWASP Dependency-Track（開源平台事實標準，是我們最直接的對照組——但它是給工程師的）
  - 圖形化：ex-sbom（<https://github.com/nics-tw/ex-sbom>）——只認 CycloneDX 1.6、底層 osv-scanner、
    須連網
  - 品質：sbomqs（NTIA 最低要素評分）；格式工具：CycloneDX CLI（驗證、轉版本、比對）
  - 商用：Snyk、Black Duck、FOSSA、Mend——客戶可能已在用，我們的報表會被拿來跟它們比
- 2026-10-10 實測紀錄：188 的 syft 1.54.0 可用 `-o cyclonedx-json@1.6` 降版輸出，元件數與
  dependencies 與 1.7 相同；1.7 相對 1.6 新增 CBOM／citations／專利欄位，我們都沒用到

## UI 想法（粗略）

- 入口：新模組「原始碼掃描」（名稱待定），列出掃描過的專案與歷次掃描
- 新增掃描：上傳壓縮檔 或 填 repo URL＋憑證 → 選要跑哪些工具 → 送出變背景 job
- 結果頁三層：
  1. 顧問層（預設）：風險總評一句話＋紅黃綠數字＋「最急的五個」＋「跟上次比」
  2. 對照層：每個弱點一列，欄位是各工具的判定（有／無／分數），點開看白話說明
  3. 原始層：各工具原始輸出可下載，SBOM 可下載（選格式與版本）
- 匯出：選報表樣式（顧問摘要／完整技術／客戶交付）與格式（PDF／HTML／DOCX）

## 待討論的問題（給 Phase 1 brainstorm 釐清）

1. 沙箱抽象怎麼切：共用樣板的邊界在哪、network policy 怎麼參數化、守衛測試怎麼跟著改
2. 要不要支援「實際跑建置工具解析依賴」（準但要執行客戶程式碼）？第一版建議先不做，只吃 lock 檔
3. 第一版支援哪些語言生態系？建議從我們自己能驗的開始（Python／npm／Java）
4. 弱點資料庫的離線更新機制：隨安裝包帶？獨立更新包？跟 agent 升級走同一條？
5. 第一版工具組合：Syft＋Trivy＋Grype（我們已熟）就夠？cdxgen／osv-scanner 第一版要不要？
6. 顧問層的「風險總評」怎麼算？不能只拿 CVSS 最高值，要考慮數量、有無公開攻擊程式（EPSS／KEV）、
   修正版本是否存在
7. 報表「每個數字追到原始輸出」的呈現形式：附錄？超連結？
8. 這功能算哪條能力點、哪些角色能用、掃描結果屬於哪個租戶
9. 要不要跟現有專案（稽核專案）綁定，還是獨立模組？

## 不在本次範圍

- 動態掃描（DAST）、滲透測試
- 修弱點（只報告、不改客戶程式碼）
- 替代我們自己的出貨管線（`sbom.sh` 維持不動；產品功能若成熟，日後可反過來讓出貨管線吃產品的服務，但不是這次）
- 把 ex-sbom 或 Dependency-Track 整包嵌進產品
