
Собирайте документы VEX и обновляйте VEX Hub
vexhub-crawler — это компонент VEX Hub, который автоматически получает VEX-документы из исходных репозиториев.
Краулер определяет исходные репозитории по зарегистрированным PURL (Package URLs) и копирует VEX-документы в VEX Hub. Этот процесс гарантирует, что VEX Hub поддерживает актуальную коллекцию VEX-документов для различных программных пакетов.
На следующей диаграмме показан общий процесс работы VEX Hub Crawler на примере npm:
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 должно быть опущено.
Параметры namespace, qualifiers и subpath могут потребоваться для некоторых экосистем, например oci.
Подробную информацию о составе PURL см. в спецификации PURL.
Список PURL может быть обновлён любым желающим через Pull Requests. Если VEX-документы уже хранятся в исходном репозитории проекта с открытым исходным кодом, сторонние разработчики (не только сопровождающие проекта) могут зарегистрировать PURL в VEX Hub.
В настоящее время краулер поддерживает следующие экосистемы:
Метод определения исходных репозиториев зависит от экосистемы:
Для определения исходного репозитория используется API реестра npm. Каждый пакет имеет раздел для определения репозитория.
Например, для React это выглядит так:
$ curl -s https://registry.npmjs.org/react | jq .repository.url
"git+https://github.com/facebook/react.git"
vexhub-crawler автоматически получит VEX-файлы, хранящиеся в https://github.com/facebook/react.
Для определения репозитория по go-import выполняется HTTP-запрос.
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>
Для определения репозитория используется API PyPI.
curl -s https://pypi.org/pypi/<package-name>/json | jq .info.project_urls.Source
API crates.io будет использоваться для определения репозитория.
curl -s https://crates.io/api/v1/crates/<crate-name> | jq .crate.repository
Для Maven-пакетов определение исходного репозитория выполняется следующим образом:
repository_url в соответствии со спецификацией PURL. URL по умолчанию: https://repo.maven.apache.org/maven2.maven-metadata.xml, используя namespace и name из PURL. Например, для 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 в POM-файле.Для OCI-образов исходный репозиторий определяется путём проверки метки (label) или аннотации (annotation) org.opencontainers.image.source у тега latest.
Эти метаданные обычно задаются в процессе сборки образа и предоставляют стандартизированный способ указания репозитория исходного кода.
Процесс выглядит следующим образом:
repository_url и тег :latest.latest.org.opencontainers.image.source в следующих местах:
Labels конфигурации образаannotations манифеста образаПример получения URL исходного репозитория с помощью crane:
$ 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 создаётся на основе Package URL (PURL), без учёта версии, квалификаторов и subpath.
Краулер использует модель доверия, основанную на VEX-документах, хранящихся в исходных репозиториях. Как упоминалось в разделе «Проверка», он отфильтровывает VEX-документы, в которых указаны продукты, отличные от исходного PURL.
Например, если PURL pkg:npm/malicious зарегистрирован в VEX Hub и соответствует исходному репозиторию github.com/org/malicious, все VEX-документы, хранящиеся там, должны содержать идентификатор продукта pkg:npm/malicious.
VEX-документы с другими идентификаторами продуктов, например pkg:npm/[email protected], будут игнорироваться.
Такой подход гарантирует, что в VEX Hub попадают только релевантные и заслуживающие доверия VEX-документы.
В настоящее время VEX Hub Crawler использует API реестров для определения исходных репозиториев пакетов. Однако этот подход несёт потенциальные риски безопасности, поскольку информация о репозитории может свободно задаваться сопровождающими пакетов, что делает её уязвимой для подделки.
Для решения этой проблемы мы рассматриваем возможность использования аттестации происхождения (provenance attestation) для более надёжного определения исходного репозитория в будущем. Аттестация происхождения позволяет получить фактический URL репозитория, в котором был собран пакет, надёжным образом, обеспечивая криптографическую проверку связи между исходным кодом пакета и его опубликованными артефактами.
Примечательно, что npm уже внедрила provenance в своём реестре. Эта реализация позволяет получать информацию об исходном репозитории непосредственно из PURL, используя данные provenance. Мы считаем, что этот подход может повысить достоверность процесса определения исходного репозитория для пакетов.