Trivy 漏洞数据库体系解析:从公告源采集到扫描消费的多仓库工作流与数据源贡献指南
本文围绕 Trivy 漏洞数据库(Trivy DB)的运作机制展开,讲清「公告采集 → 数据库构建 → 扫描消费」这条贯穿四个仓库的完整工作流,说明原始公告为何要存放在独立的 vuln-list 仓库中,并结合 Trivy 主仓库的真实源码(如 Echo OS 的检测器、数据库客户端)深入剖析各阶段的实现细节,最后给出为 Trivy 新增漏洞公告数据源的完整实操步骤。读完本文,你将理解 Trivy DB 从上游公告到 trivy scan 结果的来龙去脉,并能按文档步骤独立为一个新系统或生态系统贡献公告数据源。
一、多仓库工作流总览
Trivy 的漏洞数据库并非单仓库构建,而是通过一套多仓库协作的工作流完成,涉及三个核心仓库与 Trivy 主仓库:
graph LR
A[Advisory Sources] -->|vuln-list-update| B[vuln-list]
B --> C["trivy-db<br/>(Trivy DB)"]
C --> D["trivy<br/>(Trivy CLI)"]
E[GitHub-managed<br/>Advisories] --> C
三个工作流阶段
-
公告采集(vuln-list-update 仓库)
- 从上游公告源(API 或网页)抓取原始安全公告(advisory);
- 将公告存入 vuln-list 仓库;
- 通过定时任务(cron)周期性运行,保持公告时效性;
- 如果公告本身已托管在 Git 仓库中(例如 GitHub Security Advisories),可以跳过这一步。
-
数据库构建(trivy-db 仓库)
- 从 vuln-list 解析公告,或直接从 Git 托管的源(如 GitHub Security Advisories)读取;
- 将公告转换(transform)为 Trivy 的数据库格式;
- 同样通过 cron 周期性地发布构建好的数据库。
-
数据库消费(Trivy 主仓库)
- 扫描时下载最新的漏洞数据库;
- 利用数据库在扫描目标中检测漏洞。
这条链路的本质是「原始公告的快照库 + 格式转换器 + 消费端」三层解耦:上游公告格式再怎么变化,影响范围被隔离在采集与解析两个环节内,最终暴露给 Trivy CLI 的始终是稳定的数据库格式。
二、为什么要把公告存放在 vuln-list?
对于尚未被 Git 托管的公告源,把原始公告统一存入 vuln-list 仓库带来多重收益,这也是该仓库存在的核心原因:
- 透明性(Transparency):可以方便地追踪公告版本之间的变更与差异;
- Web UI:可以直接在仓库的 Web 界面上以友好的方式浏览公告内容;
- 稳定性(Stability):缓解上游公告服务器不稳定或不可用带来的问题——即使上游宕机,vuln-list 中仍保留最近一次抓取的完整快照;
- 可引用性(Shareability):可以为特定公告提供稳定的 URL 供引用;
- 数据质量(Data Quality):在提交进 vuln-list 之前先校验公告数据,防止格式错误或非预期的格式变更破坏 Trivy DB 的构建;
- 历史数据(Historical Data):当上游格式发生变化时,历史公告仍被完整保留。
需要注意的一个约束:vuln-list 仓库不接受手动贡献,直接对它的 Pull Request 不会被采纳,公告更新只能通过 vuln-list-update 的抓取脚本自动完成。这一约束正是「数据质量」保障的落点——所有进入数据库的公告都必须先经过抓取脚本的校验。
三、四个仓库的分工
vuln-list-update:抓取脚本仓库
包含从各种上游源抓取公告的脚本。每个数据源有自己独立的包,负责:
- 从 API 或 Web 源抓取公告;
- 校验公告格式与数据;
- 将结果保存为 vuln-list 目录结构下的 JSON 文件。
抓取脚本的一个重要约定(见下文贡献指南):尽可能原样保存上游数据,避免预处理或修改公告字段,只做诸如 YAML 转 JSON 这类格式统一。
vuln-list:原始公告数据仓库
存放由 vuln-list-update 抓取到的原始公告,特点:
- 包含 JSON 格式的原始公告数据;
- 由 vuln-list-update 脚本通过 cron 自动更新;
- 不用于手动贡献,直接 PR 不被接受;
- 作为 trivy-db 构建漏洞数据库的数据来源。
trivy-db:解析与数据库构建仓库
包含将原始公告转换为 Trivy 数据库格式的解析器。每个数据源有自己的 vulnerability source handler,负责:
- 从 vuln-list 读取公告文件,或直接读取 Git 托管的源(如 GitHub Security Advisories);
- 将公告字段映射(map)到 Trivy 的 schema;
- 将漏洞信息存入数据库。
trivy(主仓库):分析器与检测逻辑
Trivy 主仓库中承担漏洞数据库「消费端」角色,包含:
- OS 与软件包分析器:检测目标中安装了什么(
pkg/fanal/analyzer/下的分析器体系); - 漏洞检测逻辑:拿检测结果与数据库中的公告做匹配(
pkg/detector/下的检测器体系)。
四、源码级剖析:Trivy 主仓库如何消费漏洞数据库
4.1 数据库下载:OCI Artifact 拉取模型
文档中提到「扫描时下载最新漏洞数据库」。在源码中,这一过程由 pkg/db/db.go 中的 Client 实现,关键事实:
- 数据库以 OCI artifact 的形式发布,媒体类型常量定义为
application/vnd.aquasec.trivy.db.layer.v1.tar+gzip(pkg/db/db.go#L26); - 默认拉取仓库有两个:GitHub Container Registry 的
ghcr.io/aquasecurity/trivy-db:<schema-version>和 GCR 镜像mirror.gcr.io/aquasec/trivy-db:<schema-version>,标签就是数据库 schema 版本号(pkg/db/db.go#L29-L36)。这解释了为什么 trivy-db 的产物要按 schema 版本打标签发布——消费端按当前 CLI 支持的 schema 版本精确选取; - 本地数据库以 BoltDB 只读方式打开(
Init中强制ReadOnly: true,见 pkg/db/db.go#L43-L46),扫描过程绝不修改数据库文件。
NeedsUpdate 方法(pkg/db/db.go#L105-L161)实现了文档隐含的「何时重新下载」决策逻辑,值得注意的边界行为:
- 本地缺少
trivy.db或metadata.json任一文件时,判定需要下载,且此时不允许--skip-db-update(首次运行必须能拿到数据库); - 本地 DB schema 高于当前 CLI 支持的版本时,直接报错要求升级 Trivy;
- 本地 schema 与 CLI 不一致时,触发重新下载;
--skip-db-update场景下会额外校验本地 schema 是否匹配,不匹配则报错,防止离线环境用错版本数据库;- 新鲜度判断有两道门:当前时间早于
NextUpdate,或数据库在最近一小时内下载过,则跳过更新(isNewDB,pkg/db/db.go#L172-L184)。
这正是贡献指南中测试命令 trivy image --skip-db-update --cache-dir ... 能生效的底层机制:它绕过拉取,直接使用本地构建的数据库。
4.2 检测器如何读取数据库:以 Echo OS 为例
文档中「Add Vulnerability Advisory Source」一节以 Echo OS 支持为完整示例(涉及三个仓库的联动 PR)。在主仓库中,该示例的落地代码是 pkg/detector/ospkg/echo/echo.go,它是理解「trivy-db 解析结果如何被消费」的最佳入口:
Scanner持有一个echoDb.VulnSrc,它来自 trivy-db 仓库的pkg/vulnsrc/echo包(见 echo.go#L19-L27)——也就是说,trivy-db 仓库产出的不仅是数据库文件,还有按数据源划分的 Go 读取接口,Trivy 主仓库通过 import 这些vulnsrc包来读库;Detect方法对每个已安装的包调用s.vs.Get(db.GetParams{PkgName: pkg.SrcName})取出该包的所有公告,再用go-deb-version比较已安装版本与FixedVersion:只有安装版本小于修复版本时才记为漏洞(echo.go#L29-L78);- 严重级别(Severity)取自公告本身,来源标记为
vulnerability.Echo,说明严重级别由上游公告源提供而非 Trivy 重新评定(echo.go#L58-L63); - 两个针对滚动发行版的特殊设计值得注意:
IsSupportedVersion恒返回 true,因为 Echo 是滚动发行版、没有固定版本,无需版本支持性检查;FilterPackages不过滤任何包,因为 Echo 的公告 feed 不绑定基础 OS 厂商,Trivy 构建并修补了 Debian 根本没有的软件包,按仓库类别过滤包反而可能漏报(echo.go#L80-L90)。
这体现了一个通用模式:不同数据源的检测器可以有不同的包过滤策略与版本判断策略,而读取数据库的入口形态(vulnsrc + Get)保持一致。语言生态(npm、Go module 等)的检测同样走 pkg/detector/library/ 下的 driver 抽象:Detect 按包类型找到对应 driver 后逐个包查询漏洞,见 pkg/detector/library/detect.go#L14-L26。
4.3 OS 分析器:检测「这是哪个操作系统」
贡献指南要求「在 pkg/fanal/analyzer/os/ 下添加 OS 分析器来检测新 OS」。主仓库中 pkg/fanal/analyzer/os/ 下按发行版家族组织了分析器(alpine、amazonlinux、debian、redhatbase、ubuntu 等,以及基于 /etc/os-release 的通用 release 分析器)。以 Echo OS 为例,它没有单独的目录,其发行版识别落在基于 os-release 文件的 pkg/fanal/analyzer/os/release/release.go 中(该文件包含对 echo 发行版的处理)。从源码结构看,对于通过 /etc/os-release 即可识别的发行版,复用 release 分析器即可,无需新建独立分析器;而 Alpine、Debian、RedHat 这类有专有包管理元数据的发行版则需要各自的分析器解析 apk/dpkg/rpm 等来源。
五、实操指南:为 Trivy 新增一个漏洞公告数据源
以下内容继承自 Add Vulnerability Advisory Source 指南,并对照主仓库结构说明验证点。
5.1 前置条件
开始之前确认三件事:
- 已识别上游公告源及其 API/数据格式;
- 已确认该数据源尚不存在于 Trivy 中;
- 已在 Trivy 仓库中创建 discussion 或 issue 讨论新增事宜。
5.2 三仓库联动改动
步骤 1:在 vuln-list-update 添加抓取脚本
若公告源已托管在 Git 仓库(如 GitHub、GitLab)中可跳过此步。核心任务:
- 从上游 API 或源抓取公告;
- 校验公告格式与数据;
- 按 vuln-list 的目录结构将公告保存为 JSON 文件;
- 尽量原样存储上游数据:避免预处理或修改公告字段,原始数据按上游提供的样子保存(YAML 转 JSON 这类格式统一可以接受);
- 包含所有必要元数据(CVE ID、受影响版本、严重级别等)。
步骤 2:在 trivy-db 添加解析器
- 在
pkg/vulnsrc/下创建新的 vulnerability source; - 实现公告解析逻辑;
- 将公告字段映射到 Trivy 的漏洞 schema;
- 正确处
理版本范围与受影响软件包;
- 如有 CVE 映射则一并存储;
- 为解析器添加单元测试。
这个 pkg/vulnsrc/<source> 包正是 4.2 节中 Trivy 检测器所 import 的读取接口来源,两侧的接口约定由此闭合。
步骤 3:在 Trivy 主仓库添加 OS/生态支持
- 在
pkg/fanal/analyzer/os/添加 OS 分析器以检测该系统(如 4.3 节所述,能复用release分析器的发行版可不新建目录); - 在
pkg/detector/ospkg/下实现该系统的漏洞检测逻辑(参考 pkg/detector/ospkg/echo/echo.go 的结构:实现Detect、IsSupportedVersion、FilterPackages等接口); - 添加带测试数据的集成测试(主仓库
integration/testdata/下有大量以<os>.json.golden命名的 golden 文件约定可循); - 更新文档以纳入新数据源。
完整示例:Echo OS 支持的三处联动
Echo OS 支持通过三个协调的 PR 完成:
- vuln-list-update:从 Echo 的公告接口(
advisory.echohq.com/data.json)抓取公告; - trivy-db:解析 Echo 公告并存入数据库;
- Trivy:检测 Echo OS 并扫描其漏洞。
这组联动 PR 是新增任何数据源时最好的参照实现。
5.3 分仓库验证流程
验证 vuln-list-update
先抓取全部既有公告(构建数据库所必需),再单独测试新数据源:
cd vuln-list-update
go run main.go -vuln-list-dir /path/to/vuln-list
# 只抓取你的目标源
go run main.go -target your-source -vuln-list-dir /path/to/vuln-list
确认公告被正确写入 vuln-list 目录后即可进入下一步。
验证 trivy-db
cd trivy-db
make db-build CACHE_DIR=/path/to/cache
注意 CACHE_DIR 应指向 vuln-list 目录的父目录:例如 vuln-list 位于 /tmp/test/vuln-list,则设 CACHE_DIR=/tmp/test。构建无报错且包含你的公告后,可以用 BoltDB 查看工具(如 boltwiz)检查产物:
boltwiz out/trivy.db
验证 Trivy
# 构建 Trivy
mage build
# 使用本地数据库扫描
./trivy image --skip-db-update --cache-dir /path/to/cache your-test-image
确认新数据源的漏洞被正确检出。该流程之所以可行,正是因为 4.1 节描述的 --skip-db-update 校验逻辑允许在 schema 匹配的本地数据库上跳过下载。
5.4 遇到问题时
- 查阅现有数据源的参照实现(如 Echo 的三仓库代码);
- 在 Trivy 仓库发起 discussion 寻求帮助。
六、小结
Trivy 漏洞数据库体系的设计核心是「采集、存储、转换、消费」四段式解耦:vuln-list-update 负责带校验的周期性抓取,vuln-list 提供透明、稳定、可追溯的原始公告快照,trivy-db 将公告映射进按 schema 版本管理的 BoltDB 数据库并以 OCI artifact 发布,Trivy CLI 在扫描时按 schema 精确拉取、只读打开并与分析器结果做匹配。为这套体系贡献新数据源的工作,就是在这四个环节分别补齐抓取脚本、解析器(vulnsrc)与 OS 分析器/检测器,并用文中给出的分仓库验证命令逐段打通。理解 pkg/db/db.go 的更新决策逻辑与 pkg/detector/ospkg/echo/echo.go 的检测器模式,是阅读或扩展 Trivy 漏洞数据链路的两个最佳切入点。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00