
Collect VEX documents and update VEX Hub
vexhub-crawler 是 VEX Hub 的一个组件,用于自动从源代码仓库中检索 VEX 文档。
爬虫根据已注册的 PURLs (Package URLs) 识别源代码仓库,并将 VEX 文档复制到 VEX Hub。 此过程确保 VEX Hub 为各种软件包维护最新的 VEX 文档集合。
下图以 npm 为例说明了 VEX Hub Crawler 的高级流程:
flowchart TD
Dev[Developer] -->|Register package| PL[Package List]
PL -->|Provide packages for crawling| Crawler
Crawler -->|Identify repository URL| Registry[Package Registry]
Crawler -->|Retrieve VEX documents| Src
Crawler -->|Validate and update VEX documents| Hub
subgraph crawler [VEX Hub Crawler]
Crawler
PL
end
subgraph bottom [ ]
direction LR
Registry
Src
Hub[VEX Hub]
subgraph Src[Source Repository]
direction TB
VEX[VEX documents<br>under .vex/ directory]
end
end
classDef dev fill:#b3d9ff,stroke:#2a4d69,stroke-width:1px,color:#2a4d69;
classDef vexHub fill:#ffd9e6,stroke:#4b3832,stroke-width:1px,color:#4b3832;
classDef crawler fill:#c2f0c2,stroke:#1e4d2b,stroke-width:1px,color:#1e4d2b;
classDef npmReg fill:#ffe6cc,stroke:#5e3023,stroke-width:1px,color:#5e3023;
classDef sourceRepo fill:#e6ccff,stroke:#3b2e58,stroke-width:1px,color:#3b2e58;
classDef pkgList fill:#ccf2ff,stroke:#1c4e5a,stroke-width:1px,color:#1c4e5a;
classDef invisible fill:none,stroke:none;
class Dev dev;
class Hub vexHub;
class crawler crawler;
class Registry npmReg;
class Src,VEX sourceRepo;
class PL pkgList;
class bottom invisible;
VEX Hub Crawler 维护一份 PURL 列表,用于发现 VEX 文档。 PURL 定义文件格式如下:
pkg:
npm:
- namespace: "@angular"
name: animations
golang:
- name: github.com/aquasecurity/trivy
pypi:
- name: django
maven:
- namespace: org.junit.jupiter
name: junit-jupiter-api
oci:
- name: trivy
qualifiers:
- key: repository_url
value: index.docker.io/aquasec/trivy
- name: trivy
qualifiers:
- key: repository_url
value: ghcr.io/aquasecurity/trivy
指定 PURL 时,需要以下组件:
必须省略 version。
对于某些生态系统(例如 oci),可能需要 namespace、qualifiers 和 subpath。
关于 PURL 组成的详细信息,请参阅 PURL 规范。
PURL 列表 可以通过 Pull Request 由任何人更新。 如果 VEX 文档已经存储在开源项目的源代码仓库中,欢迎项目维护者以外的个人在 VEX Hub 中注册该 PURL。
目前,爬虫支持以下生态系统:
识别源代码仓库的方法因生态系统而异:
将使用 npm registry API 来解析源代码仓库。 每个包都有一个部分来定义仓库。
以 React 为例,如下所示:
$ curl -s https://registry.npmjs.org/react | jq .repository.url
"git+https://github.com/facebook/react.git"
vexhub-crawler 将自动检索存储在 https://github.com/facebook/react 中的 VEX 文件。
将通过 HTTP 访问从 go-import 中识别仓库。
curl -s "https://k8s.io/client-go?go-get=1"
<html><head>
<meta name="go-import"
content="k8s.io/client-go
git https://github.com/kubernetes/client-go">
<meta name="go-source"
content="k8s.io/client-go
https://github.com/kubernetes/client-go
https://github.com/kubernetes/client-go/tree/master{/dir}
https://github.com/kubernetes/client-go/blob/master{/dir}/{file}#L{line}">
</head></html>
将使用 PyPI API 来解析仓库。
curl -s https://pypi.org/pypi/<package-name>/json | jq .info.project_urls.Source
将使用 crates.io API 来解析仓库。
curl -s https://crates.io/api/v1/crates/<crate-name> | jq .crate.repository
对于 Maven 包,通过以下步骤识别源代码仓库:
repository_url。默认 URL 是 https://repo.maven.apache.org/maven2。maven-metadata.xml 文件的 URL。例如,对于 com.fasterxml.jackson.core:jackson-databind,URL 为:https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-core/maven-metadata.xml。maven-metadata.xml 中提取最新版本,scm.url 或 url 字段来识别源代码仓库。对于 OCI 镜像,通过检查 latest 标签的 org.opencontainers.image.source 标签或注解来识别源代码仓库。
该元数据通常在镜像构建过程中设置,并提供了一种标准化的方式来引用源代码仓库。
过程如下:
repository_url 和 :latest 标签来构造完整的镜像引用。latest 标签的镜像 manifest 和配置。org.opencontainers.image.source 键:
Labels 字段annotations 字段使用 crane 检索源 URL 的示例:
$ crane config ghcr.io/aquasecurity/trivy:latest | jq -r '.config.Labels["org.opencontainers.image.source"]'
https://github.com/aquasecurity/trivy
一旦识别出源代码仓库(目前仅支持 git 仓库),vexhub-crawler 会在仓库根目录的 .vex/ 目录中搜索 VEX 文档。
爬虫将匹配以下模式的文件视为 VEX 文档:
爬虫执行以下验证:
爬虫将发现的文件以原始文件名复制到 VEX Hub。 VEX Hub 中的目录结构基于包 URL(PURL)创建,不包括 version、qualifiers 和 subpath。
爬虫采用基于源代码仓库中存储的 VEX 文档的信任模型。 如验证部分所述,它会过滤掉声明产品与原始 PURL 不同的 VEX 文档。
例如,如果 VEX Hub 中注册了 PURL pkg:npm/malicious,并且该 PURL 解析到源代码仓库 github.com/org/malicious,则存储在那里的任何 VEX 文档都必须具有产品 ID pkg:npm/malicious。
具有不同产品 ID(如 pkg:npm/[email protected])的 VEX 文档将被忽略。
这种方法确保了只有相关且可信的 VEX 文档才会被包含在 VEX Hub 中。
目前,VEX Hub Crawler 使用 registry API 来识别包的源代码仓库。 然而,这种方法存在潜在的安全风险,因为仓库信息可以由包维护者自由设置,因此容易受到篡改。
为了解决这一挑战,我们正在考虑在未来使用 provenance attestation 来实现更可靠的源代码仓库解析。 Provenance attestation 允许以可信的方式获取包构建时实际使用的仓库 URL,从而能够对包的源代码与其发布产物之间的关系进行密码学验证。
值得注意的是,npm 已经在其 registry 中实现了 provenance。 这一实现使得可以直接使用 provenance 数据从 PURL 检索源代码仓库信息。 我们相信这种方法可以增强包源代码仓库解析过程的可信度。