EverBright-IT/SBOM-Lens

GitHub: EverBright-IT/SBOM-Lens

一款纯客户端的 SPDX SBOM 查看器,支持将多级联文档解析为供应链树并提供冲突检测、版本 diff 和合规报告。

Stars: 1 | Forks: 0

![SBOM Lens:一个用于 SPDX SBOM 的快速、极简查看器](https://static.pigsec.cn/wp-content/uploads/repos/cas/9a/9a8ea1f3216bf8d5b25996320610ef7c5c4fbf27d81413a7953baf6cccd82ee6.png) # SBOM Lens 拖入一个发布级别的 SPDX 文档及其组件 SBOM,即可将整个供应链作为一棵树进行导航:release → component → sub-component → container image → package。所有操作均在你的浏览器中运行;文件永远不会离开你的机器。 **试用:** 。项目落地页位于 。VS Code 扩展位于 [Open VSX](https://open-vsx.org/extension/everbright-it/sbomlens)。 ![SBOM Lens:加载了演示级联的 Explore 视图,展示了带有跨文档徽章的树状结构、包含关系的详情面板以及文档映射图](https://static.pigsec.cn/wp-content/uploads/repos/cas/b2/b23c8f68a4c416b38e059b50255f31bc2a14ddc4d51459e1d161376ba323fcdd.png) 使用 `npm run screenshot -w @sbomlens/web`(需运行开发服务器)重新生成。 ## 为什么选择 SBOM Lens - **级联文档是一等公民。** SPDX 2.3 通过 `ExternalDocumentRef` 和跨文档关系(`DocumentRef-X:SPDXRef-Y`)链接文档。SBOM Lens 会在你加载的每个文件中解析这些引用,首先通过 checksum,然后通过 namespace 进行匹配,并跨文档边界渲染一棵连续的、支持懒加载展开的树。未解析的引用会显示为可操作的占位符:你可以通过 URL 获取、拖入文件或确认建议的匹配项。 - **在真实规模下依然快速。** 多兆字节文档(包含 6,500+ 个 package)在 Web Worker 中进行解析;树状视图和源码视图已虚拟化;搜索基于预构建的索引运行并返回排名结果。没有分页,没有卡顿。 - **设计上注重隐私。** 一个纯静态、仅限客户端的应用。SBOM 均在本地解析,绝不进行上传。URL 获取仅在你明确要求时才会发生。 - **坦诚对待脏数据。** 真实的 SBOM 存在一些怪癖:checksum 空格变体、重复的 SPDXID、没有关系的引用、未知的关系类型、隐藏在 purl 中的版本。解析器能够容忍所有这些问题,并将其发现作为每个文档的诊断信息进行报告,而不是拒绝加载。 - **解答问题,而不仅仅是展示文件。** 除了浏览之外:还提供可导出的跨级联清单、版本冲突检测、版本间的 release diff,以及针对每个文档的 NTIA 质量报告。 ## 快速开始 ``` git clone https://gitlab.com/everbrightit-group/sbom-lens.git cd sbom-lens npm ci npm run dev # → http://localhost:5173 ``` 点击 **Load example** 加载内置的四文档演示级联,或者拖入你自己的 `.spdx` / `.spdx.json` 文件(支持多选和整个文件夹)。 ## 加载文档 | 方法 | 说明 | | --- | --- | | 拖放 | 窗口内的任何位置;文件夹将进行递归遍历 | | 打开 ▸ 文件 / 文件夹 | 标准选择器 | | 打开 ▸ 从 URL 获取 | 通过 HTTP(S) 获取文档,例如从 GitLab 通用 package registry 获取 | | 占位符 ▸ 获取 | 每个未解析的引用都提供对其记录的 URL 的一键获取 | | **Fetch all**(状态栏) | **递归**下载每个被引用的文档,直到级联完成。一键获取完整的树,而不是每个占位符点一次 | **Access tokens:** 对于私有 registry,在 URL 对话框中添加针对每个主机的 token(GitLab `PRIVATE-TOKEN` 或 `Authorization: Bearer`)。Token 仅存于 `sessionStorage` 中:它们会随着标签页的关闭而消失,永远不会被持久化。 **CORS:** 浏览器只能获取那些其服务器允许跨域请求的 URL。如果不允许,SBOM Lens 会明确指出。请改为下载文件并将其拖入,或者将查看器自托管在你的 registry 相同的反向代理之后,以确保请求是同源 的。 ## 引用如何解析 对于每个已加载文档的每个 `ExternalDocumentRef`,按优先级顺序: 1. **Checksum**:引用的 SHA-1 与已加载文件的字节匹配。这是最强烈的信号,也是当引用 URI 是下载 URL 而非 namespace 时唯一有效的方法。 2. **Namespace**:引用 URI 等于已加载文档的 `documentNamespace`(规范认可 的路径)。 3. **手动**:由你自己将文件绑定到引用。 名称相似度(“看起来像 `acme-auth-service`”)永远只会作为一键 *建议* 显示,绝不自动绑定,因为 DocumentRef 名称在实际情况中通常会偏离实际的文件版本。 没有任何关系指向的引用(扫描报告、证明、发布说明)被归类为 *信息性*:它们被列在 **External documents** 下,而不会催促你去解析它们。 ## 分析视图 | 视图 | 解答的问题 | | --- | --- | | **Explore** | “这个 release 包含什么?”级联树、详情面板和原始源码。按住 Shift 并点击箭头(或按 `*`)展开整个子树,包括已解析的子 SBOM;搜索框旁边的漏斗图标会在原处对树进行过滤,保留匹配项及其祖先,并隐藏其他所有内容 | | **Map** | “这个级联是如何连接的?”文档拓扑结构显示为可折叠的从左到右的树:文档作为节点,已解析的引用作为带有方法样式的边,缺失的文档作为虚线存根。节点可以通过 `+N` 徽章折叠其子树(大型工作区默认折叠),搜索会强制显示匹配项,支持平移/缩放,单击可选择,双击可跳转至 Explore | | **Inventory** | “把部件清单作为一个文件给我。”跨越所有文档的一个可排序表格,可通过相同的搜索和分面标签(文档、类型、用途、许可证)进行过滤,并可导出为 CSV/JSON | | **Conflicts** | “哪些 package 提供了多个版本?”按整个级联中的 purl 标识进行分组,每次出现只需点击一次即可跳转到它在树中的位置 | | **Diff** | “这两个 release 之间发生了什么变化?”显示两个级联之间新增、删除和版本更改的 package(每一方是一个文档加上通过其已解析的引用可到达的所有内容),可复制为 Markdown 格式的发布说明 | 每个文档的详情面板还额外显示一份以 NTIA 最低要素为导向的 **质量报告**:作者/时间戳/namespace/关系检查,以及针对每个 package 的版本、供应商、唯一 ID、checksum 和许可证覆盖率。只有事实数据,没有虚构的评分。组织可以通过 **自定义合规性配置** 进一步深入:这是一个包含你自己最低要素(字段存在性、模式、覆盖率阈值、时效性)的小型 JSON 文件,可以通过拖放、部署目录或 VS Code 工作区中的 `.sbomlens/profile.json` 导入。报告可导出为 Markdown。参见 [docs/compliance-profiles.md](docs/compliance-profiles.md)。 ## 键盘快捷键 | 键 | 动作 | | --- | --- | | `/` | 聚焦搜索 | | `↑` `↓` | 在树/结果中移动选择 | | `→` | 展开节点,然后移至第一个子节点 | | `←` | 折叠节点,然后移至父节点 | | `*` | 展开整个子树(也可:按住 Shift 并点击箭头) | | `Enter` | 切换节点/打开搜索结果 | | `Esc` | 清除搜索,关闭面板 | | `?` | 快捷键帮助 | ## 支持的格式 - **SPDX 2.x tag-value** (`.spdx`)、**JSON** 和 **YAML**:完全支持。检测基于内容,而非文件扩展名。 - **SPDX 3.0.x JSON-LD**:可加载。Package、文件、关系、哈希、外部标识符(purl、CPE)和许可证关系会映射到与 2.x 相同的视图;来自 core/software 之外配置文件(AI、dataset、build)的元素会被计入通知中,而不是直接显示。Tag-value 没有 3.x 序列化;其他 3.x 序列化则不会被解析。 - **CycloneDX** 和 **Trivy 原生 JSON**:可被识别,并会提供指向正确转换方式的提示(`trivy --format spdx-json`,`cyclonedx convert`)。 详情视图自带规范说明:将鼠标悬停在字段旁边的“信息”图标上,即可阅读 SPDX 2.3 规范针对该字段的自有文档,该文档是在构建时从官方 JSON schema 中提取生成的(`npm run generate:spec-docs`)。点击该图标可在渲染的规范中打开该字段所在的部分。目前,SPDX 3.x 文档在渲染时没有这些工具提示:因为 2.3 的文本对于 3.0 的字段是不准确的,而精选的 3.0.1 文本将在后续推出。 ## 限制 已知的边界,在此明确说明,以免让你感到意外: - **格式范围。** 完整支持 SPDX 2.x;SPDX 3.0.x 作为 JSON-LD,映射了 core/software 配置文件(其他配置文件仅被计入,未渲染,且不会遵循外部文档映射)。CycloneDX 和 Trivy 原生 JSON 可被识别并给出转换提示,但不进行解析。检测基于内容。 - **必须使用 HTTPS 或 localhost。** 级联解析使用 `crypto.subtle` 计算文件字节的哈希,而浏览器仅在安全上下文中公开此 API。在非 localhost 主机上通过普通 HTTP 访问时,哈希处理(因此也包括基于 checksum 的引用解析)不会运行。 - **URL 加载需要 CORS。** 浏览器只能获取那些其服务器允许跨域请求的文档。如果不能,SBOM Lens 会明确提示你;请下载文件并拖入,或者在与你的 registry 相同的源后自托管(见下文)。 - **大小。** 单个 SPDX 文档没有硬性上限:包含数千个 package 的多兆字节文件在 Web Worker 中进行解析。在 **VS Code** 扩展中,工作区扫描会跳过超过 **50 MB** 的单个文件(需手动打开这些文件)。展开整个子树时会在节点数达到 **2,000** 时停止并给出通知,且树的遍历深度限制为 64。 - **合规性配置。** 配置文件的大小上限为 **64 KB**,最多包含 **200** 项检查;最多可持久化导入 **16** 个配置文件(总计 **256 KB**),超过此限制的配置文件仅保留在当前会话中。 - **保护隐私,且始终保持如此。** 没有上传途径,没有遥测。只有偏好设置和导入的配置会被持久化(在本地);加载的文档不会被持久化。因此,深层链接需要可寻址的源(目录条目或通过 URL 加载的文档),而不是被拖入的文件。 - **设计上不包含在范围内。** 不进行许可证合规性判断(展示许可证字段,但不解释),且核心模型中不包含漏洞或 VEX 覆盖层。 ## 自托管 SBOM Lens 构建为一个完全静态的站点(`apps/web/dist/`),任何 Web 服务器都可以进行托管。 包含一个最小化的 nginx 镜像(约 25 MB): ``` docker build -f deploy/Dockerfile -t sbomlens . docker run --rm -p 8080:80 sbomlens # → http://localhost:8080 ``` 默认情况下,内置的 nginx 配置附带了强化的安全标头(CSP,`nosniff`,`frame-ancestors 'none'`)。请参见 [deploy/nginx.conf](deploy/nginx.conf) 了解 CSP 允许的内容及其原因。 请通过 **HTTPS**(或 localhost)提供该应用:驱动级联解析的 SHA-1 哈希使用了 `crypto.subtle`,而浏览器仅在安全上下文中公开此 API。在通过同一源代理私有 registry 时,请将服务器端的 token 权限限制为只读,并限制可以访问该代理的用户范围(详见配置中的注释)。 构建版本使用相对资源路径,因此它适用于任何基础路径,包括 GitLab 或 GitHub Pages 的子路径。该应用是一个 PWA:一旦访问过,它就能在离线状态下继续工作(包括内置的示例)。 ### 预配置的 SBOM 目录 自托管实例可以附带一份精选的 SBOM 列表,这样用户只需打开查看器即可进行分析,而无需费力寻找文件。将 `sbomlens.catalog.json` 放置在 `index.html` 旁边: ``` { "title": "ACME releases", "sources": [ { "label": "Platform 1.0 (current release)", "description": "Release SBOM plus component SBOMs", "urls": ["sboms/1.0/platform.spdx"], "loadOnStart": false, "resolveRefs": true } ] } ``` 条目将显示在开始屏幕和 **Open** 菜单中;带有 `loadOnStart` 的源会自动加载。通过 `resolveRefs: true`,你只需列出根文档。加载后,每个被引用的 SBOM 都会被递归获取,这样只需点击一下,用户就能获得用于分析的完整树。该目录仅从此固定的同源路径中读取(绝不通过 URL 参数读取),且仅接受 http(s)/相对 URL。 **访问私有 registry(GitLab 等):** 除非服务器发送 CORS 标头,否则浏览器会阻止跨域请求,而 GitLab 的 API 不会发送。稳健的模式是使用 **同源代理**:内置的 [deploy/nginx.conf](deploy/nginx.conf) 包含一个带注释的示例,它将 `/sboms/...` 代理到 GitLab 通用 package registry,并在服务器端注入一个 **只读** token。用户不需要任何 token,没有任何跨域操作,并且目录文件中永远不会出现任何密钥。切勿将 token 放入 `sbomlens.catalog.json`。如果服务器允许 CORS,直接使用绝对 URL 也可以工作;此时,身份验证将使用 URL 对话框中针对每个主机的会话 token。 ## 开发 ``` npm run dev # dev server npm test # unit tests (Vitest) npm run lint # ESLint npm run typecheck # tsc --noEmit npm run build # typecheck + production build ``` Releases 会以锁步方式对每个工作区进行版本升级: ``` npm version 0.X.0 --workspaces --include-workspace-root --no-git-tag-version git commit -am "release: v0.X.0" && git tag -a v0.X.0 -m "SBOM Lens 0.X.0" ``` Tag pipeline 会自动将 tag 转换为 GitLab release:说明备注是该版本对应的 CHANGELOG 部分,资产包含 vsix 文件和自身的 SBOM(从 package registry 提供,因此链接不会过期)。在 [OCM Lens 产品主页](https://gitlab.com/everbrightit-group/ocm-lens) 推送相同的 tag 会在那里创建匹配的 release;请在此仓库的 tag pipeline 完成之后再进行推送,以便其 vsix 资产链接能够找到已发布的 package。 供应链卫生机制:每次推送都会运行 osv-scanner CVE 门控、SAST 和密钥检测;release 额外进行 Trivy 镜像扫描,并附带发布其自身的 SPDX SBOM(`sbomlens-.spdx.json`,可在 SBOM Lens 中打开)。依赖更新通过 Renovate MR 推送。详情:[docs/ci-security.md](docs/ci-security.md)。 该仓库是一个 npm workspace,经过了精心的分层设计: ``` packages/core/ @sbomlens/core, the framework-free domain: parsers (tag-value/JSON/YAML), workspace, reference resolution, graph indexes, tree derivation, search, analysis (inventory/conflicts/diff/quality), generated spec docs. Zero React imports, enforced by ESLint. apps/web/src/worker/ a thin Web Worker shell around core parsing (hashing + parsing off the UI thread; yaml loads only here). apps/web/src/app/ zustand store, ingest pipeline (files / folders / URLs), deployment catalog, memoized selectors. apps/web/src/ui/ React components: virtualized tree + document map, detail pane, analysis views, search, diagnostics. apps/web/src/host/ HostAdapter seam: browser host (fetch, web storage, module workers) and VS Code webview host (postMessage bridge, blob workers, editor secret storage). apps/vscode/ the VS Code extension: custom editor + workspace scan around the same webview bundle (see its README). ``` 该仓库还基于此代码库构建了一个姊妹产品:**OCM Lens**,这是一个用于查看 Open Component Model component 版本和交付物的查看器([docs/ocm.md](docs/ocm.md);产品主页 [gitlab.com/everbrightit-group/ocm-lens](https://gitlab.com/everbrightit-group/ocm-lens),实时地址位于 [ocm-lens.everbright-it.de](https://ocm-lens.everbright-it.de/))。 这是一个独立的关注点,这种拆分是结构性的,而不是表面的:描述符映射、tar 读取器和 gzip 位于 `@sbomlens/core/ocm` 之后,仅由 OCM Lens 调用它们,并且如果有任何该部分代码的字节进入了 SBOM Lens 的包中,CI 门禁就会使构建失败。SBOM Lens 是一个 SPDX 查看器:它识别 component descriptor 的程度仅足以告诉你它不是一个 SBOM。 `packages/core/fixtures/` 包含了复现解析器支持的所有真实世界怪癖的合成文档;`apps/web/scripts/generate-examples.mjs` 用于重新生成演示级联。若要在不提交私有 SBOM 集合的情况下对其进行验证:`SBOM_CORPUS_DIR=~/my-sboms npm run check-corpus`。 ## 路线图 - **SPDX 3.x,更深入**:精选的 3.0.1 字段工具提示、外部文档映射以及除 JSON-LD 之外的序列化格式。目前加载 3.0.x JSON 已可使用(参见 [支持的格式](#supported-formats))。 - **Chromium 扩展**(浏览器中用于原始 SBOM 的“Open in SBOM Lens”):基于相同代码库的轻量级外壳,类似于现在位于 [apps/vscode](apps/vscode/README.md) 的 VS Code 扩展(“Open with SBOM Lens”、工作区扫描;已发布在 [Open VSX](https://open-vsx.org/extension/everbright-it/sbomlens))。架构:[docs/extension-architecture.md](docs/extension-architecture.md)。 - 通过相同的适配器接缝实现 **CycloneDX** 读取支持 - 工作区持久化(File System Access API),可共享的深层链接(深层链接需要可寻址的源:目录或通过 URL 加载的文档) - 可选的覆盖层(漏洞),保留在核心模型之外 ## 仓库与镜像 开发在 EverBright 的 GitLab 上进行;更改会同步镜像到公开的仓库: - GitLab(规范的公开仓库): - GitHub 镜像: 欢迎在任一平台上提交 Issue 和贡献;维护者会将它们同步到主仓库中。 ## 许可证 [Apache-2.0](LICENSE) © EverBright IT GmbH。由 [EverBright IT GmbH](https://everbright-it.de) 维护。UI 中显示的字段文档衍生自 [SPDX 规范](https://spdx.dev)(CC-BY-3.0,© The Linux Foundation 和 SPDX 贡献者)。
标签:SBOM, SPDX, WebAssembly, 供应链合规, 前端, 可视化工具, 暗色界面, 硬件无关, 自动化攻击, 请求拦截