
VEX 저장소 명세
이 문서의 키워드 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", "OPTIONAL"은 RFC 2119에 설명된 대로 해석되어야 한다.
버전 비교 시:
비교 예시:
매니페스트 파일은 VEX 데이터 저장소에 대한 메타데이터를 제공한다. 이 파일에는 VEX 데이터를 검색하고 업데이트하는 데 필요한 정보가 포함되어야 한다(MUST).
https://<domain>/.well-known/vex-repository.json에 위치해야 한다(MUST).vex-repository.json은 메인 브랜치의 루트 디렉터리에 배치되어야 한다(MUST).매니페스트 파일의 JSON 스키마는 여기에 정의되어 있다.
{
"name": "Example Org VEX Repository",
"description": "VEX repository for Example Organization",
"versions": [
{
"spec_version": "0.1",
"locations": [
{
"url": "https://example.com/vex-hub/v0/vex-data-v0.tar.gz"
}
],
"update_interval": "24h",
"repository_specific": {
"location": {
"repository_type": "db",
"db_type": "bbolt",
"url": "oci://ghcr.io/example.com/vex-db:0"
}
}
},
{
"spec_version": "1.0",
"locations": [
{
"url": "https://example.com/vex-hub/v1/vex-data-v1.tar.gz//subdirectory"
},
{
"url": "https://example.com/vex-api/v1"
}
],
"update_interval": "1h"
}
]
}
| 필드 | 필수 | 설명 및 참고 사항 |
|---|---|---|
| name | ✓ | 저장소의 이름. |
| description | ✓ | 저장소에 대한 간략한 설명. |
| versions | ✓ | 사용 가능한 버전의 세부 정보를 포함하는 배열. 배열의 각 객체는 VEX 저장소 사양 버전을 구현하는 버전을 나타낸다. 버전은 오래된 순서에서 최신 순서로 오름차순 정렬되어야 한다(MUST). 하위 필드는 별도 표를 참조하라. |
| 필드 | 필수 | 설명 및 참고 사항 |
|---|---|---|
| spec_version | ✓ | 구현된 VEX 저장소 사양의 버전(예: "0.1"). 형식은 섹션 1에 정의된 대로 "X.Y"여야 한다(MUST). |
| locations | ✓ | VEX 데이터 위치를 설명하는 객체 배열. 하나 이상의 위치 객체를 포함해야 한다(MUST). 하위 필드는 별도 표를 참조하라. |
| update_interval | ✓ | 이 버전의 VEX 데이터에 대한 권장 업데이트 확인 간격. Go duration 형식을 사용한다(예: "1h", "30m", "24h"). |
| repository_specific | - | 추가적인 저장소별 정보. |
저장소는 다음 구조를 가져야 한다(MUST):
vex-repository.<archive_extension>
[optional_subdirectory/]
├── index.json
└── pkg/
├── <type>/
│ ├── <namespace>/
│ │ ├── <name>/
│ │ │ └── vex.json
│ │ └── ...
│ └── ...
└── ...
여기서 <archive_extension>은(는) 지원되는 아카이브 형식 중 하나이다.
[optional_subdirectory/]은(는) locations 필드의 URL이 // 다음에 하위 디렉터리 경로로 끝날 때 포함된다.
이는 특히 GitHub 저장소와 같은 기존 저장소 레이아웃을 사용할 때 저장소 구조에 유연성을 제공한다.
예를 들어, URL이 https://github.com/org/repo/archive/refs/heads/main.tar.gz//repo-main이면 파일 구조는 다음과 같다:
main.tar.gz
└──repo-main/
├── index.json
└── pkg/
└── ...
이 경우 repo-main/은(는) tar.gz 파일 내에서 VEX 저장소의 루트 디렉터리이다.
index.json 파일은 아카이브 파일의 내용에 대한 매니페스트 역할을 한다. 아카이브의 루트 디렉터리 또는 URL에 정의된 경우 지정된 하위 디렉터리에 배치되어야 한다(MUST). 이 파일은 다음 구조를 가져야 한다(MUST):
{
"updated_at": "2023-07-04T12:00:00Z",
"packages": [
{
"id": "pkg:deb/debian/curl",
"location": "pkg/deb/debian/curl/vex.json"
},
{
"id": "pkg:npm/lodash",
"location": "pkg/npm/lodash/vex.json",
"format": "csaf"
}
]
}
필드 설명:
| 필드 | 필수 | 설명 |
|---|---|---|
| updated_at | ✓ | 이 index.json이 마지막으로 업데이트된 시점을 나타내는 타임스탬프. |
| packages | ✓ | 저장소의 각 패키지를 나타내는 객체 배열. |
| packages[].id | ✓ | 패키지의 식별자. 현재는 Package URL(PURL)만 허용된다. 버전, 한정자 및 하위 경로는 VEX 문서에 포함되므로 생략해야 한다(MUST). OCI 유형 패키지의 경우 repository_url 한정자가 id에 포함되어야 한다(MUST). |
| packages[].location | ✓ | 아카이브 내에서 이 패키지의 VEX 파일에 대한 상대 경로. 클라이언트는 이 필드를 사용하여 특정 패키지 VEX 파일을 찾아야 한다(MUST). |
| packages[].format | - | VEX 데이터의 형식. "openvex" 또는 "csaf" 중 하나이다. 생략하면 "openvex"로 간주된다. |
인덱스 파일의 스키마는 여기에 정의되어 있다.
각 패키지의 VEX 정보는 index.json 파일에 정의된 경로 구조에 따라 별도의 JSON 파일로 저장되어야 한다(MUST). 이러한 파일의 내용은 format 필드에 지정된 VEX 형식 사양(OpenVEX 또는 CSAF VEX)을 준수해야 한다(MUST).
단일 VEX 문서에는 동일한 패키지의 서로 다른 버전, 한정자 및 하위 경로에 대한 정보가 포함될 수 있다(MAY).
OpenVEX 문서 예시는 OpenVEX 사양을 참조하라.
repository_url 한정자를 사용하여 디렉터리 구조를 만들 수 있다(MAY). 예를 들어, PURL이 "pkg:oci/debian@sha256:3e45770a143ee5afd1ebde5a6aea6e32a71d2bt5602f5dac8025db0d9cc19f10?repository_url=docker.io/library/debian"인 패키지는 "pkg/oci/docker.io/library/debian/vex.json"에 저장될 수 있다.location 필드에서 자유롭게 정의할 수 있다(MAY).VEX 저장소를 업데이트할 때:
updated_at 타임스탬프 업데이트를 포함하여 변경 사항을 반영하도록 index.json 파일을 업데이트한다.locations URL을 업데이트한다.VEX 저장소는 VEX 데이터 및 관련 메타데이터를 포함하는 아카이브 파일로 배포되어야 한다(MUST). 이 아카이브는 vex-repository.json 파일의 locations 필드에서 참조되어야 하며(MUST), VEX 정보를 배포하는 주요 수단이다.
아카이브 파일은 다음 형식 중 하나여야 한다(MUST):
tar.gz and tgztar.bz2 and tbz2tar.xz and txzzipgzbz2xzversions 배열에서 버전을 선택할 때:
spec_version 필드를 기준으로 지원하는 버전을 선택해야 한다(MUST).locations 배열에 여러 위치가 있을 때:
클라이언트는 여러 VEX 저장소를 지원하도록 설계되어야 한다(SHOULD).
클라이언트는 업데이트를 확인하기 위해 다음 프로세스를 사용해야 한다(SHOULD):
update_interval을 검색한다.update_interval을 더하여 다음 업데이트 시간을 계산한다.효율적인 운영을 위해 클라이언트는 다음 전략을 구현할 수 있다(MAY):
update_interval이 매우 짧은 경우 과도한 네트워크 요청을 피하기 위해 업데이트 확인 사이의 최소 간격(예: 1시간)을 구현한다.