Syft:从扫描源到可验证 SBOM
SBOM 文件存在,不等于软件组成已经被正确描述。扫描目录、容器镜像、归档文件和已经生成的 SBOM,会触发不同 source 解析和 cataloger;多阶段镜像删除包管理器元数据后,包数量下降也可能是输入变了,而不是依赖真的减少。Syft 的价值在于把目标字节转成结构化软件目录,同时留下足够证据解释“扫描了什么、怎样识别、哪些范围看不见”。
source 决定扫描语义
Syft 可以处理目录、镜像、文件、归档和 SBOM。看似相同的路径,在不同 source scheme 下并不等价。dir: 从宿主目录读取可见文件,docker: 通过 Docker daemon 读取镜像,registry: 直接访问 Registry,oci-archive: 与 docker-archive: 解析不同归档格式,sbom: 则消费既有清单。
实验基线采用 Syft 1.50.0。安装从官方 Release 取得指定平台资产,同时校验 checksums 与签名材料;不在受控 Runner 中执行浮动 latest 安装脚本。版本只约束实验,升级要回放固定 source。
syft version
syft cataloger list
syft config --load运行记录至少保存 Syft 版本、配置摘要、source scheme、目标引用和内容身份。镜像使用 repository@sha256:...,目录则先定义包含边界并计算输入清单摘要。仅记录 Tag 或目录名无法重建当时字节。
cataloger 决定能看见哪些软件
Cataloger 从文件、数据库、包管理器元数据、二进制特征和语言生态清单中识别 package。不同 cataloger 可能从同一文件得到互补证据,也可能产生需要去重或归因的候选。Syft 的 package 记录通常包含 name、version、type、PURL、CPE、locations、licenses 和元数据;relationship 则表达包与文件、镜像层或其他对象之间的关系。
包名相同不能证明是同一个组件。版本、生态、PURL、location、文件摘要和 cataloger 来源共同决定可追踪性。CPE 是漏洞产品标识候选,不等于 Maven GAV、npm 坐标或 PURL;下游扫描器需要自己的匹配模型。
Cataloger 配置变化会改变输出,应像扫描规则一样进入版本控制。为了让覆盖变化可见,可以建立少量关键组件断言:基础运行时、应用主包、一个直接依赖和一个 vendored 或静态链接样本。断言关注必需对象是否存在,不把总包数固定成永久阈值。
用一个目录实验观察中间状态
set -euo pipefail
LAB="$(mktemp -d)"
mkdir -p "$LAB/app" "$LAB/artifacts"
cat > "$LAB/app/package.json" <<'JSON'
{
"name": "syft-evidence-lab",
"version": "1.0.0",
"dependencies": { "lodash": "4.17.21" }
}
JSON
cat > "$LAB/app/package-lock.json" <<'JSON'
{
"name": "syft-evidence-lab",
"version": "1.0.0",
"lockfileVersion": 3,
"packages": {
"": { "name": "syft-evidence-lab", "version": "1.0.0", "dependencies": { "lodash": "4.17.21" } },
"node_modules/lodash": { "version": "4.17.21" }
}
}
JSON
find "$LAB/app" -type f -print0 | sort -z | xargs -0 sha256sum > "$LAB/artifacts/input-files.sha256"
syft scan "dir:$LAB/app" -o "syft-json=$LAB/artifacts/sbom.syft.json"
jq -e '.artifacts | length > 0' "$LAB/artifacts/sbom.syft.json"
jq -e '.artifacts[] | select(.name == "lodash" and .version == "4.17.21")' "$LAB/artifacts/sbom.syft.json"正向结果不只是命令退出 0,还包括输入清单、目标组件和 package location。若 lodash 没有出现,先看 lockfile 是否在 source 范围、对应 cataloger 是否启用、Schema 是否变化,不要手工把组件补进输出。
反向实验删除 lockfile,只留下 package.json 再生成 SBOM。输出可能仍识别声明依赖,但证据和 locations 会变化。比较两份结果可以说明 lockfile、安装目录和声明文件提供的证据强度不同;不能把“识别到名字”当成已经证明实际安装字节。
输出格式服务不同消费者
Syft JSON 保留较丰富的 cataloger 与 location 信息,适合排障和与 Grype 等 Anchore 工具协作。SPDX JSON 和 CycloneDX JSON 更适合跨组织交换,但转换后的字段、relationship、license 和自定义属性并不保证一一等价。
syft scan "dir:$LAB/app" \
-o "syft-json=$LAB/artifacts/sbom.syft.json" \
-o "spdx-json=$LAB/artifacts/sbom.spdx.json" \
-o "cyclonedx-json=$LAB/artifacts/sbom.cdx.json"
jq -e '.artifacts | length > 0' "$LAB/artifacts/sbom.syft.json"
jq -e '.packages | length > 0' "$LAB/artifacts/sbom.spdx.json"
jq -e '.components | length > 0' "$LAB/artifacts/sbom.cdx.json"
sha256sum "$LAB/artifacts"/*.json > "$LAB/artifacts/sboms.sha256"每增加一种格式,就增加一次 Schema 兼容、字段映射和存储责任。通常保留 Syft 原生 JSON 作为排障证据,再选择一种组织交换格式即可。下游只需要 SPDX 时,也要先证明关键 package、PURL、license 和 relationship 没在转换中丢失。
镜像扫描必须绑定 Digest
SUBJECT='registry.example.com/team/service@sha256:REPLACE_ME'
syft scan "$SUBJECT" -o syft-json=artifacts/image.sbom.syft.json
jq -e '.source.target.userInput != null' artifacts/image.sbom.syft.json
sha256sum artifacts/image.sbom.syft.json > artifacts/image.sbom.sha256Tag 会移动,Digest 才是输入身份。多架构镜像还要说明扫描的是 index 还是某个平台 manifest;发布 linux/amd64 与 linux/arm64 时,不能拿一个平台的 SBOM 代表全部变体。输出应和平台、manifest digest、构建提交及流水线运行绑定。
多阶段构建可能删除编译工具和元数据,这是减小攻击面的正常动作,也会降低运行镜像中可观察的信息。若需要同时回答“构建时用了什么”和“运行镜像包含什么”,应分别为构建依赖与最终制品生成清单,不能把源仓目录 SBOM 冒充运行制品 SBOM。
故障从 source、cataloger 和格式分层
包数量突然下降时,先比较 Syft 版本、配置、source scheme、目标摘要和 cataloger 集合,再看构建是否删除元数据。零包结果、命令失败和确实没有可识别包是三种状态,流水线必须分开记录。
同一组件重复时,检查不同 cataloger 的 locations、PURL 和 metadata。不要按 name/version 粗暴去重,那会把不同生态或镜像层中的对象合并。下游消费者不兼容新格式时,先用固定 SBOM 对比 Schema 与关键字段,再决定临时锁定旧版还是升级消费者;静默输出空报告最危险。
远程 Registry 扫描失败时,区分认证、manifest 解析、平台选择、layer 下载和 cataloger 错误。Runner 的 Registry Token 只授予读取目标仓库的权限,日志不输出认证头或私有包元数据。SBOM 本身会暴露基础镜像、内部包名、路径和许可证,也应按工程敏感数据管理。
升级与退出要能重放
升级 Syft 时,用固定目录和固定镜像 Digest 回放代表样本,比较 package 集合、PURL、locations、relationships、Schema 和运行资源。新增或消失的组件逐项归因到 cataloger、解析修复或真实输入差异,再批准新版本。仅比较总包数会掩盖关键包消失。
缓存可以加速镜像层读取,不能替代输入和版本真相。容量模型关注镜像大小、layer 数、文件数、包数、并发、临时磁盘和输出大小;对大型镜像限制并发并保存超时/内存失败状态,不要用空 SBOM 继续发布。
移除 Syft 前,盘点哪些发布记录、扫描任务和 Attestation 依赖其 Schema。替代工具必须用同一 Digest 生成并比较关键组件和关系,历史 SBOM 按保留策略继续可读。供应链如何把清单接入扫描、签名和部署,由供应链证据闭包统一编排;漏洞匹配由 Grype 主文承担。
