首页
/ Crawl4AI SBOM 深度解析:CycloneDX 依赖清单的结构、内容与再生成流程

Crawl4AI SBOM 深度解析:CycloneDX 依赖清单的结构、内容与再生成流程

2026-09-06 17:23:40作者:凤尚柏Louis

Crawl4AI 仓库在 sbom/ 目录下维护了一份 CycloneDX 格式的软件物料清单(Software Bill of Materials, SBOM),用于完整披露项目运行时依赖的组件、许可证与版本。本文以 sbom/README.mdsbom/sbom.cdx.json 为主体,结合生成脚本 scripts/gen-sbom.sh 的源码,讲解这份 SBOM 的规范版本、组件构成、依赖图谱结构,以及如何在本地验证与再生成它。

一、SBOM 在 Crawl4AI 中的定位与官方声明

sbom/ 目录是 Crawl4AI 仓库中存放合规与供应链透明度资产的位置,目录内仅包含两个文件:

sbom/README.md 中的声明是理解这份文件边界的关键:

  1. 用途声明:该目录包含项目的 CycloneDX SBOM;
  2. 免责条款(Disclaimer):该 SBOM 是基于项目元数据“尽力而为”(best-effort)生成的,反映的是生成时刻的依赖状态,不构成完整性或准确性的保证
  3. 再生成方式:通过运行 ./scripts/gen-sbom.sh 重新生成。

这一免责声明很重要:Crawl4AI 是一个依赖面很广的 Web 爬虫框架(Playwright、aiohttp、Pydantic 等),其实际环境还包含 uv.lock 锁定的开发依赖、.venv 中已安装的包以及 Docker 部署镜像的依赖。SBOM 捕获的是“某一次构建/扫描时点”的快照,因此使用者在将其用于安全审计或合规申报时,应当以仓库最新一次再生成的结果为准,而不是直接引用历史快照。

二、SBOM 的规范版本与元数据

sbom/sbom.cdx.json 的顶层字段可以确认其格式与生成工具信息:

字段 含义
bomFormat CycloneDX 采用 CycloneDX 标准
specVersion 1.6 CycloneDX 规范 1.6 版本
serialNumber urn:uuid:03585831-4a90-4206-8589-7c4d89f6d58c SBOM 文档的唯一序列号(URN UUID),便于下游工具去重与引用
version 1 文档版本号
metadata.timestamp 2026-01-27T01:43:08Z 生成时间戳
metadata.tools.components syft v1.40.1(author: anchore) 实际执行扫描的引擎
metadata.component type: file, name: "." 被扫描的根组件即仓库根目录本身

其中 metadata.tools 字段明确记录了本次清单由 anchore 出品的 syft 1.40.1 生成——这与下文生成脚本中调用的工具一致。metadata.component 声明根组件为 .(项目根目录),说明 syft 是对整个仓库目录树(而非单一构建产物)做的文件级与包级联合扫描。

三、组件构成:679 个组件如何分类

顶层 components 数组共包含 679 个组件,按 type 字段可分为三类:

组件类型 数量 说明
library 278 软件库,绝大多数为 PyPI 包(purl 形如 pkg:pypi/aiohttp@3.13.3),也包含 GitHub Actions(如 pkg:github/actions/checkout@v4
file 385 仓库内的文本文件(如工作流、脚本、文档),每个条目携带 SHA-1 与 SHA-256 双哈希
application 16 被识别为“应用/二进制”的组件,例如 Python 虚拟环境中随包分发的 PE 可执行文件(pip 的 distlib 启动器、setuptools 的 cli 二进制等)

几个值得注意的实际样本(均可在 sbom/sbom.cdx.json 中检索到):

1. 项目自身作为一个组件被收录。 清单中存在 purl: pkg:pypi/crawl4ai@0.7.8 的 library 组件,带有作者 Unclecode、许可证 Apache-2.0 以及推导出的 CPE(cpe:2.3:a:unclecode_...:python-crawl4ai:0.7.8:...)。这说明扫描器从已安装的 crawl4ai 包元数据中识别出了项目本体。需要留意的是:该组件版本(0.7.8)对应生成时点的环境,而当前仓库 crawl4ai/version.py__version__ 已演进为 0.9.0,这也印证了 README 中“快照仅反映生成时刻依赖”的免责声明。

2. 许可证信息并非全量。 679 个组件中只有 126 个携带 licenses 字段。syft 依赖包元数据(dist-info/METADATA)与 lock 文件中的许可证声明,未声明的组件不会虚构许可证值——使用时应按“缺省即未知”处理。

3. 同一包可能出现多个版本。 例如 aiohttp 同时存在 3.12.13(来自 /uv.lock)与 3.13.3(来自 .venv 的 dist-info),click 存在 8.1.88.3.1certifi 存在 2025.7.92026.1.4。这不是数据错误,而是扫描范围覆盖了“锁定声明”与“实际安装”两个层面(见下一节)。

四、依赖图谱与来源溯源(properties 属性)

CycloneDX 1.6 的 dependencies 数组在 sbom/sbom.cdx.json 中共有 140 个条目,每个条目以组件 bom-ref 为键、dependsOn 为值,构成依赖关系图。例如:

{
  "ref": "pkg:pypi/aiohttp@3.13.3?package-id=0eeb93580cf1583c",
  "dependsOn": ["pkg:pypi/aiosignal@1.4.0?..."]
}

从结构看,这些关系主要由 uv.lock 中的锁定元数据推导而来,可以直接用于下游 SBOM 工具做依赖链分析(如“某个漏洞组件被哪条链引入”)。

每个组件还携带 properties 数组,其中 syft 的溯源属性是审计的关键:

  • syft:package:foundBy:发现该组件的 cataloger(扫描器),如 github-actions-usage-catalogerpe-binary-package-cataloger 等;
  • syft:package:type:包的分类,取值包括 python(PyPI 包)、github-action(GitHub Actions)、binary(二进制)等;
  • syft:location:0:path 等:组件在仓库中的物理位置,这是最实用的溯源字段。

按位置前缀统计所有组件的出处,可以清楚看出 syft 实际扫描了哪些来源:

来源路径 组件命中次数 对应仓库文件
/uv.lock 127 uv.lock(项目锁文件,声明层依赖)
/.venv/... 378 生成时点的 Python 虚拟环境(安装层依赖,含 dist-info 元数据)
/.github/workflows/... 8 CI 工作流(如 .github/workflows/main.yml 中引用的 Ilshidur/action-discord.github/workflows/release.yml 中的 actions/checkout@v4actions/setup-python@v5
/deploy/docker/requirements.txt 6 deploy/docker/requirements.txt(Docker 服务端部署的 Python 依赖)
其他(根目录 requirements.txt 等) 2 requirements.txt

也就是说,这份 SBOM 实际上把 Crawl4AI 的四条依赖面都纳入了视野:开发/锁定的主依赖(uv.lock + pyproject.toml)、实际运行环境(.venv)、Docker 部署镜像(deploy/docker/ 的 requirements 与服务代码 deploy/docker/server.py)、以及 CI 供应链(GitHub Actions)。对于评估一个爬虫框架的攻击面——第三方 Action、HTTP 客户端、证书库(如 certificryptography)——这份清单提供了逐条可查的证据。

五、再生成 SBOM:gen-sbom.sh 脚本剖析

sbom/README.md 给出的再生成命令背后,是 scripts/gen-sbom.sh 这个 15 行的小脚本,其完整逻辑如下:

#!/usr/bin/env bash
set -euo pipefail

# Generate CycloneDX JSON SBOM using Syft
# Output: sbom.cdx.json in project root

cd "$(dirname "$0")/.."

if ! command -v syft &> /dev/null; then
    echo "Error: syft is not installed. Install from https://github.com/anchore/syft" >&2
    exit 1
fi

syft . -o cyclonedx-json=sbom/sbom.cdx.json

echo "SBOM generated: sbom/sbom.cdx.json"

逐行理解几个关键设计:

  1. set -euo pipefail:严格错误模式,任一命令失败即终止,避免生成出残缺的清单;
  2. cd "$(dirname "$0")/..":无论调用方位于哪个目录,都先切换到脚本上一级(即仓库根目录),保证 syft . 的扫描根是项目根;
  3. 前置检查 command -v syft:syft 未安装时直接报错退出(脚本注释中指明了 syft 的安装来源,为 anchore 官方项目),而不是让 syft 命令静默失败;
  4. 核心扫描命令 syft . -o cyclonedx-json=sbom/sbom.cdx.json:对当前目录树执行全量 catalog,输出 CycloneDX JSON 并直接写入 sbom/sbom.cdx.json

因此复现流程为:

# 1. 安装 syft(anchore 官方工具),例如通过包管理器或官方安装脚本
# 2. 在仓库根目录执行:
./scripts/gen-sbom.sh
# 输出:SBOM generated: sbom/sbom.cdx.json

需要注意两个适用前提:其一,扫描结果与执行环境强相关——若在干净的 checkout 中运行(无 .venv),生成的清单将不含安装层组件,主要反映 uv.lockrequirements.txt 与 CI 工作流的声明依赖;其二,生成产物直接覆盖仓库内文件,应通过版本控制 diff 审阅变更,而不是盲目信任单次输出。这与 sbom/README.md 的 best-effort 免责声明一脉相承。

六、如何阅读与利用这份 SBOM(实用建议)

面向供应链安全、合规审计或依赖治理场景,结合本仓库的实际结构,给出几条可操作的用法:

  1. 验证文件完整性file 类组件携带 SHA-256 哈希,可用于比对 CI 工作流等关键文件是否在传输中被篡改;
  2. 版本漂移检查:对比 metadata.componentcrawl4ai 的版本与 crawl4ai/version.pypyproject.toml(通过 attr = "crawl4ai.__version__.__version__" 动态取版本)中的当前版本,可判断清单是否过期;本仓库快照中的 0.7.8 与当前 0.9.0 的差异即为典型案例;
  3. 双源交叉核对uv.lock 来源(声明层)与 .venv 来源(安装层)的版本差异(如前文 aiohttp、click 的例子)提示环境存在漂移,可据此检查 requirements.txtdeploy/docker/requirements.txt 与 lock 文件的一致性;
  4. 许可证缺口识别:对缺失 licenses 字段的 500 余个组件,应回到源包元数据单独确认许可证,而不是默认宽松;
  5. CI 供应链审计:通过 syft:location 定位到 .github/workflows/main.yml.github/workflows/release.yml.github/workflows/docker-release.yml 的 Action 引用,逐一核对第三方 Action 的版本与可信度。

七、小结

Crawl4AI 的 sbom/ 目录提供了一份规范版本为 CycloneDX 1.6、由 syft 1.40.1 生成的全仓库 SBOM:它把 679 个组件(278 个库、385 个文件、16 个应用/二进制)、140 条依赖关系,以及从 uv.lock.venv、Docker requirements 到 GitHub Actions 的四条依赖面,统一收录进 sbom/sbom.cdx.json,并可通过 scripts/gen-sbom.sh 一键再生成。理解其 best-effort 快照属性、组件溯源属性(syft:locationsyft:package:foundBy)与许可证覆盖缺口,是在这个仓库上做好供应链透明度评估的基本功。

登录后查看全文
热门项目推荐
相关项目推荐