跳轉到

第三方元件風險:歷次比較(Source Scan Diff)

功能群:第三方元件風險|配對鍵與資料模型先讀 功能群總覽

事實基準:2026-10-11 從 FE src/views/source-scan/SourceScanDiff.vue、src/components/source-scan/DiffFindingTable.vue、BE api/source_scan/routes/target_route.py::SourceScanTargetDiffRoute、jedi-source-scan source_scan_diff_service.py 實查掃出

變更紀錄

日期 FR 變更
2026-10-11 FR-134 新頁:同一受評系統任選兩次完成的掃描比較已修補/新增/仍存在與元件版本異動;匯出回訪報告

1. 功能描述

同一套受評系統的兩次掃描放在一起看:上次之後修好了哪些、多了哪些、哪些還在。用在顧問回訪——客戶說「上次那批都處理了」,這頁直接回答處理了幾筆、還剩幾筆、有沒有新冒出來的。預設比最近兩次。

主要使用者:顧問、稽核員。

角色速覽

角色 一句話
持 detection.source-scan.read 看比較
另持 detection.source-scan.export 匯出回訪報告

1.1 功能總覽(本頁全部功能)

# 功能 說明 位置 詳述
1 選兩次掃描 「前次」「本次」兩個下拉,選項是這套系統所有完成的掃描(時間+檔名);預設最近兩次 頁首下方 §10
2 配對規則說明 固定一行說明配對方式 下拉下方 UC-SSD-01
3 三個數字 已修補/新增/仍存在 主區上方 §5
4 分類清單 四個頁籤:已修補、新增、仍存在、元件版本異動 主區 §5
5 開兩邊結果頁 「檢視前次結果」「檢視本次結果」 主區下方 掃描結果頁
6 匯出回訪報告 以本次掃描為主體產出報表,附「與上次掃描比較」一節 頁首右 UC-SSD-02

2. Use Case

UC-SSD-01 比較兩次掃描

項目 內容
角色 持 read
前置條件 該系統至少兩次完成的掃描(不足顯示「尚無法比較」並提示由清單重新掃描)
產出 / 後置條件 無寫入;結果即時算、不落表

UC-SSD-01 比較

配對規則:以「生態系+套件名稱+弱點編號」配對,不比對版本(fingerprint)。套件升了版但仍受同一弱點影響者列為「仍存在」,不會被算成「修掉一筆、又新增一筆」。

分類 定義 版本欄
已修補 前次有、本次沒有 前次版本
新增 前次沒有、本次有 本次版本
仍存在 兩次都有 兩邊版本;版本有變動的排前面——已升版但沒升到修正版
元件版本異動 元件以 purl 去版本配對,列出升降版、新增、移除 前次/本次版本,缺的一邊顯示「無此元件」
  • 兩次掃描的先後依完成時間判定,後端一律把較早那次回成 scan_a;使用者把下拉選反了,畫面仍顯示「前次 → 本次」的正確方向。
  • 選同一次時提示「請選擇兩次不同的掃描」,不送請求。

UC-SSD-02 匯出回訪報告

項目 內容
角色 持 export
前置條件 已算出比較結果
產出 / 後置條件 下載一個檔;稽核事件 6192

與結果頁的匯出報表同一個對話框(格式、委託單位名稱),多帶 diff_with=較早那次的 uid。報表以較新那次為主體,章節同結果頁 UC-SSR-03,在「統計」之後多一節「與上次掃描比較」。

3. 權限矩陣

操作 FE 判定 BE 強制 BE 檢查位置
進頁、比較 路由守衛(source-scan-diff 子路由) require_license("plugin")+read SourceScanTargetDiffRoute.get
匯出回訪報告 v-can=export export SourceScanExportRoute.post

4. 狀態機與前置條件

條件 效果 出處
完成的掃描 < 2 顯示「尚無法比較」 SourceScanDiff.vue
兩次不屬同一系統 400 SOURCE_SCAN_400011 source_scan_app_service.py::diff_scans
任一次未完成 412 SOURCE_SCAN_412003 同上
系統不存在 404 SOURCE_SCAN_404001 同上

5. UI 設計

歷次比較版面

  • 三個數字卡:已修補(左側綠條)、新增(橘條)、仍存在(灰條),手機寬度改直排。
  • 分類頁籤欄位:套件、生態系、版本(依分類顯示前次/本次/兩邊)、弱點編號(連 NVD)、嚴重度、KEV 標記、修正版。每個頁籤頂端一行說明該分類的定義。

6. API 規格

6.1 總清單

Method + Path 說明 能力點
GET /source-scan/targets/{uid} 標題 read
GET /source-scan/targets/{uid}/scans 下拉選項(過濾出 done) read
GET /source-scan/targets/{uid}/diff?a=&b= 比較 read
POST /source-scan/scans/{uid}/export 回訪報告(帶 diff_with) export

6.2 比較回應(SourceScanDiffResponseSchema)

欄位 型別 說明
scan_a / scan_b object uid、finished_at、source_ref;a 一律是較早那次
counts object fixed、new、remaining、components_changed
fixed / new / remaining list 每筆 fingerprint、vuln_id、package、ecosystem、severity、in_kev、version_a、version_b、fixed_versions、nvd_url
components_changed list 每筆 ecosystem、name、version_a、version_b

出處:api/source_scan/serializers/source_scan.py(_DiffFindingSchema、_ComponentChangeSchema、SourceScanDiffResponseSchema)。

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/source-scan/SourceScanDiff.vue 主頁:選兩次、三數字、四頁籤、匯出
src/components/source-scan/DiffFindingTable.vue 已修補/新增/仍存在的清單
src/components/source-scan/ExportReportDialog.vue 匯出對話框(帶 diffWith)

8. 後端檔案地圖

鏈路 Route App Service 底層
比較 target_route.py::SourceScanTargetDiffRoute source_scan_app_service.py::diff_scans source_scan_diff_service.py(純函式,不碰 DB)
回訪報告 scan_route.py::SourceScanExportRoute report/report_export_service.py report_comparison.py、templates/report/_comparison.html、report_docx_comparison.py

9. DB

只讀:compliance.source_scans、source_scan_findings(用 fingerprint)、source_scan_components(用 purl 去版本)。欄位卡見掃描結果頁 §9。

每次掃描完成時,背景工作也會用同一套比較對受評系統的上一次完成掃描算一次,存進 summary.delta(清單「前次比較」與結果頁「前次比較」區塊讀它)。本頁則是任選兩次、即時算。

10. 頁面邏輯與資料對應

  • 載入:平行取受評系統與歷次掃描,過濾出 done(後端給新到舊)→ 「本次」預設最新、「前次」預設第二新。
  • 兩個下拉任一變動即重算;選同一次不送請求。
  • 匯出回訪報告用的主體掃描=result.scan_b(較新那次)。

11. 背景行為與外部依賴

類型 內容
背景 無(即時算);summary.delta 由掃描背景工作在完成時寫入
稽核事件 6192 匯出
socket 無

12. 邊界情況與已知坑

  1. 配對不含版本是刻意的:用含版本的 match_key 會把「升版但沒修好」算成一修一增,數字好看但失真。
  2. 工具組合不同的兩次掃描:例如前次只跑兩家、本次跑三家,本次可能多出只有第三家報的弱點,會落在「新增」。比較前請留意兩次的工具設定。
  3. 來源類型固定:同一系統的歷次掃描來源類型相同(精靈鎖定),否則元件辨識範圍不同,比較失真。

13. 開發與驗證

  • 導航:第三方元件風險 → 列上 🕘(完成兩次以上才出現)
  • 驗收:同一系統先掃舊版鎖定檔、再掃升過版的鎖定檔 → 「已修補」有數字、「仍存在」裡版本變動的排前面、「元件版本異動」列出升版元件;匯出回訪報告有「與上次掃描比較」一節