diff --git a/.gitattributes b/.gitattributes
index a2363ebf92..279878b8e4 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,3 @@
cmd/build.go export-subst
*.go diff=golang
+Documentation/reference/api.md linguist-generated
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index f031ede90a..736ccb2be3 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -38,11 +38,6 @@ jobs:
printf '::error file=%s,title=Bad Filename::Disallowed character in file name\n' "$file"
done
exit $(git ls-files -- ':/:*[<>:"|?*]*' | wc -l)
- - name: Check API Reference
- if: ${{ !cancelled() && steps.checkout.conclusion == 'success' }}
- run: |
- npx widdershins --search false --language_tabs 'python:Python' 'go:Golang' 'javascript:Javascript' --summary ./openapi.yaml -o ./Documentation/reference/api.md
- git diff --exit-code
- name: Check Container Versions
if: ${{ !cancelled() && steps.checkout.conclusion == 'success' }}
run: |
diff --git a/Documentation/reference/api.md b/Documentation/reference/api.md
index ebc74ab43e..224226725e 100644
--- a/Documentation/reference/api.md
+++ b/Documentation/reference/api.md
@@ -1,5 +1,5 @@
---
-title: ClairV4 v1.1
+title: Clair Container Analyzer v1.2.0
language_tabs:
- python: Python
- go: Golang
@@ -8,7 +8,8 @@ language_clients:
- python: ""
- go: ""
- javascript: ""
-toc_footers: []
+toc_footers:
+ - External documentation
includes: []
search: false
highlight_theme: darkula
@@ -18,265 +19,22 @@ headingLevel: 2
-
ClairV4 v1.1
+Clair Container Analyzer v1.2.0
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
-ClairV4 is a set of cooperating microservices which scan, index, and match your container's content with known vulnerabilities.
+Clair is a set of cooperating microservices which can index and match a container image's content with known vulnerabilities.
+
+**Note:** Any endpoints tagged "internal" are documented for completeness but are considered exempt from versioning.
Email: Clair Team Web: Clair Team
License: Apache License 2.0
-Notifier
-
-## DeleteNotification
-
-
-
-> Code samples
-
-```python
-import requests
-headers = {
- 'Accept': 'application/json'
-}
-
-r = requests.delete('/notifier/api/v1/notification/{notification_id}', headers = headers)
-
-print(r.json())
-
-```
-
-```go
-package main
-
-import (
- "bytes"
- "net/http"
-)
-
-func main() {
-
- headers := map[string][]string{
- "Accept": []string{"application/json"},
- }
-
- data := bytes.NewBuffer([]byte{jsonReq})
- req, err := http.NewRequest("DELETE", "/notifier/api/v1/notification/{notification_id}", data)
- req.Header = headers
-
- client := &http.Client{}
- resp, err := client.Do(req)
- // ...
-}
-
-```
-
-```javascript
-
-const headers = {
- 'Accept':'application/json'
-};
-
-fetch('/notifier/api/v1/notification/{notification_id}',
-{
- method: 'DELETE',
-
- headers: headers
-})
-.then(function(res) {
- return res.json();
-}).then(function(body) {
- console.log(body);
-});
-
-```
-
-`DELETE /notifier/api/v1/notification/{notification_id}`
-
-Issues a delete of the provided notification id and all associated notifications. After this delete clients will no longer be able to retrieve notifications.
-
-Parameters
-
-|Name|In|Type|Required|Description|
-|---|---|---|---|---|
-|notification_id|path|string|false|A notification ID returned by a callback|
-
-> Example responses
-
-> 400 Response
-
-```json
-{
- "code": "string",
- "message": "string"
-}
-```
-
-Responses
-
-|Status|Meaning|Description|Schema|
-|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|OK|None|
-|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[Error](#schemaerror)|
-|405|[Method Not Allowed](https://tools.ietf.org/html/rfc7231#section-6.5.5)|Method Not Allowed|[Error](#schemaerror)|
-|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal Server Error|[Error](#schemaerror)|
-
-
-This operation does not require authentication
-
-
-## Retrieve a paginated result of notifications for the provided id.
-
-
-
-> Code samples
-
-```python
-import requests
-headers = {
- 'Accept': 'application/json'
-}
-
-r = requests.get('/notifier/api/v1/notification/{notification_id}', headers = headers)
-
-print(r.json())
-
-```
-
-```go
-package main
-
-import (
- "bytes"
- "net/http"
-)
-
-func main() {
-
- headers := map[string][]string{
- "Accept": []string{"application/json"},
- }
-
- data := bytes.NewBuffer([]byte{jsonReq})
- req, err := http.NewRequest("GET", "/notifier/api/v1/notification/{notification_id}", data)
- req.Header = headers
-
- client := &http.Client{}
- resp, err := client.Do(req)
- // ...
-}
-
-```
-
-```javascript
-
-const headers = {
- 'Accept':'application/json'
-};
-
-fetch('/notifier/api/v1/notification/{notification_id}',
-{
- method: 'GET',
-
- headers: headers
-})
-.then(function(res) {
- return res.json();
-}).then(function(body) {
- console.log(body);
-});
-
-```
-
-`GET /notifier/api/v1/notification/{notification_id}`
-
-By performing a GET with a notification_id as a path parameter, the client will retrieve a paginated response of notification objects.
-
-Parameters
-
-|Name|In|Type|Required|Description|
-|---|---|---|---|---|
-|notification_id|path|string|false|A notification ID returned by a callback|
-|page_size|query|int|false|The maximum number of notifications to deliver in a single page.|
-|next|query|string|false|The next page to fetch via id. Typically this number is provided on initial response in the page.next field. The first GET request may omit this field.|
-
-> Example responses
-
-> 200 Response
-
-```json
-{
- "page": {
- "size": 100,
- "next": "1b4d0db2-e757-4150-bbbb-543658144205"
- },
- "notifications": [
- {
- "id": "5e4b387e-88d3-4364-86fd-063447a6fad2",
- "manifest": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
- "reason": "added",
- "vulnerability": {
- "name": "CVE-2009-5155",
- "fixed_in_version": "v0.0.1",
- "links": "http://link-to-advisory",
- "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
- "normalized_severity": "Unknown",
- "package": {
- "id": "10",
- "name": "libapt-pkg5.0",
- "version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
- "arch": "x86",
- "module": "",
- "cpe": "",
- "source": {
- "id": "9",
- "name": "apt",
- "version": "1.6.11",
- "kind": "source",
- "source": null
- }
- },
- "distribution": {
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS"
- },
- "repository": {
- "id": "string",
- "name": "string",
- "key": "string",
- "uri": "string",
- "cpe": "string"
- }
- }
- }
- ]
-}
-```
-
-Responses
-
-|Status|Meaning|Description|Schema|
-|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|A paginated list of notifications|[PagedNotifications](#schemapagednotifications)|
-|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[Error](#schemaerror)|
-|405|[Method Not Allowed](https://tools.ietf.org/html/rfc7231#section-6.5.5)|Method Not Allowed|[Error](#schemaerror)|
-|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal Server Error|[Error](#schemaerror)|
+# Authentication
-
-This operation does not require authentication
-
+- HTTP Authentication, scheme: bearer Clair's authentication scheme.
-Indexer
+indexer
## Index the contents of a Manifest
@@ -287,8 +45,8 @@ This operation does not require authentication
```python
import requests
headers = {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'
+ 'Content-Type': 'application/vnd.clair.manifest.v1+json',
+ 'Accept': 'application/vnd.clair.index_report.v1+json'
}
r = requests.post('/indexer/api/v1/index_report', headers = headers)
@@ -308,8 +66,8 @@ import (
func main() {
headers := map[string][]string{
- "Content-Type": []string{"application/json"},
- "Accept": []string{"application/json"},
+ "Content-Type": []string{"application/vnd.clair.manifest.v1+json"},
+ "Accept": []string{"application/vnd.clair.index_report.v1+json"},
}
data := bytes.NewBuffer([]byte{jsonReq})
@@ -328,22 +86,19 @@ const inputBody = '{
"hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
"layers": [
{
- "hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
+ "hash": "sha256:2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
"uri": "https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
"headers": {
- "property1": [
- "string"
- ],
- "property2": [
- "string"
+ "Authoriztion": [
+ "Bearer hunter2"
]
}
}
]
}';
const headers = {
- 'Content-Type':'application/json',
- 'Accept':'application/json'
+ 'Content-Type':'application/vnd.clair.manifest.v1+json',
+ 'Accept':'application/vnd.clair.index_report.v1+json'
};
fetch('/indexer/api/v1/index_report',
@@ -371,14 +126,11 @@ By submitting a Manifest object to this endpoint Clair will fetch the layers, sc
"hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
"layers": [
{
- "hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
+ "hash": "sha256:2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
"uri": "https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
"headers": {
- "property1": [
- "string"
- ],
- "property2": [
- "string"
+ "Authoriztion": [
+ "Bearer hunter2"
]
}
}
@@ -390,7 +142,7 @@ By submitting a Manifest object to this endpoint Clair will fetch the layers, sc
|Name|In|Type|Required|Description|
|---|---|---|---|---|
-|body|body|[Manifest](#schemamanifest)|true|none|
+|body|body|[manifest](#schemamanifest)|true|Manifest to index.|
> Example responses
@@ -398,51 +150,17 @@ By submitting a Manifest object to this endpoint Clair will fetch the layers, sc
```json
{
- "manifest_hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "state": "IndexFinished",
- "packages": {
- "10": {
- "id": "10",
- "name": "libapt-pkg5.0",
- "version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
- "arch": "x86",
- "module": "",
- "cpe": "",
- "source": {
- "id": "9",
- "name": "apt",
- "version": "1.6.11",
- "kind": "source",
- "source": null
- }
- }
- },
- "distributions": {
- "1": {
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS"
- }
- },
- "environments": {
- "10": [
- {
- "package_db": "var/lib/dpkg/status",
- "introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
- "distribution_id": "1"
- }
- ]
- },
+ "manifest_hash": null,
+ "state": "string",
+ "err": "string",
"success": true,
- "err": ""
+ "packages": {},
+ "distributions": {},
+ "repository": {},
+ "environments": {
+ "property1": [],
+ "property2": []
+ }
}
```
@@ -450,16 +168,26 @@ By submitting a Manifest object to this endpoint Clair will fetch the layers, sc
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|IndexReport Created|[IndexReport](#schemaindexreport)|
-|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[Error](#schemaerror)|
-|405|[Method Not Allowed](https://tools.ietf.org/html/rfc7231#section-6.5.5)|Method Not Allowed|[Error](#schemaerror)|
-|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal Server Error|[Error](#schemaerror)|
+|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|IndexReport created.
+
+Clients may want to avoid reading the body if simply submitting the manifest for later vulnerability reporting.|[index_report](#schemaindex_report)|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|412|[Precondition Failed](https://tools.ietf.org/html/rfc7232#section-4.2)|Precondition Failed|None|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
+
+### Response Headers
+
+|Status|Header|Type|Format|Description|
+|---|---|---|---|---|
+|201|Location|string||HTTP [Location header](https://httpwg.org/specs/rfc9110.html#field.location)|
+|201|Link|string||Web Linking [Link header](https://httpwg.org/specs/rfc8288.html#header)|
This operation does not require authentication
-## Delete the IndexReport and associated information for the given Manifest hashes, if they exist.
+## Delete the referenced manifests.
@@ -468,8 +196,8 @@ This operation does not require authentication
```python
import requests
headers = {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'
+ 'Content-Type': 'application/vnd.clair.bulk_delete.v1+json',
+ 'Accept': 'application/vnd.clair.bulk_delete.v1+json'
}
r = requests.delete('/indexer/api/v1/index_report', headers = headers)
@@ -489,8 +217,8 @@ import (
func main() {
headers := map[string][]string{
- "Content-Type": []string{"application/json"},
- "Accept": []string{"application/json"},
+ "Content-Type": []string{"application/vnd.clair.bulk_delete.v1+json"},
+ "Accept": []string{"application/vnd.clair.bulk_delete.v1+json"},
}
data := bytes.NewBuffer([]byte{jsonReq})
@@ -509,8 +237,8 @@ const inputBody = '[
"sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3"
]';
const headers = {
- 'Content-Type':'application/json',
- 'Accept':'application/json'
+ 'Content-Type':'application/vnd.clair.bulk_delete.v1+json',
+ 'Accept':'application/vnd.clair.bulk_delete.v1+json'
};
fetch('/indexer/api/v1/index_report',
@@ -539,11 +267,11 @@ Given a Manifest's content addressable hash, any data related to it will be remo
]
```
-
+Parameters
|Name|In|Type|Required|Description|
|---|---|---|---|---|
-|body|body|[BulkDelete](#schemabulkdelete)|true|none|
+|body|body|[bulk_delete](#schemabulk_delete)|true|Array of manifest digests to delete.|
> Example responses
@@ -555,19 +283,26 @@ Given a Manifest's content addressable hash, any data related to it will be remo
]
```
-
+Responses
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|OK|[BulkDelete](#schemabulkdelete)|
-|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[Error](#schemaerror)|
-|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal Server Error|[Error](#schemaerror)|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Successfully deleted manifests.|[bulk_delete](#schemabulk_delete)|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
+
+### Response Headers
+
+|Status|Header|Type|Format|Description|
+|---|---|---|---|---|
+|200|Clair-Error|string||This is a trailer containing any errors encountered while writing the response.|
This operation does not require authentication
-## Delete the IndexReport and associated information for the given Manifest hash, if exists.
+## Delete the referenced manifest.
@@ -576,10 +311,10 @@ This operation does not require authentication
```python
import requests
headers = {
- 'Accept': 'application/json'
+ 'Accept': 'application/vnd.clair.error.v1+json'
}
-r = requests.delete('/indexer/api/v1/index_report/{manifest_hash}', headers = headers)
+r = requests.delete('/indexer/api/v1/index_report/{digest}', headers = headers)
print(r.json())
@@ -596,11 +331,11 @@ import (
func main() {
headers := map[string][]string{
- "Accept": []string{"application/json"},
+ "Accept": []string{"application/vnd.clair.error.v1+json"},
}
data := bytes.NewBuffer([]byte{jsonReq})
- req, err := http.NewRequest("DELETE", "/indexer/api/v1/index_report/{manifest_hash}", data)
+ req, err := http.NewRequest("DELETE", "/indexer/api/v1/index_report/{digest}", data)
req.Header = headers
client := &http.Client{}
@@ -613,10 +348,10 @@ func main() {
```javascript
const headers = {
- 'Accept':'application/json'
+ 'Accept':'application/vnd.clair.error.v1+json'
};
-fetch('/indexer/api/v1/index_report/{manifest_hash}',
+fetch('/indexer/api/v1/index_report/{digest}',
{
method: 'DELETE',
@@ -630,15 +365,15 @@ fetch('/indexer/api/v1/index_report/{manifest_hash}',
```
-`DELETE /indexer/api/v1/index_report/{manifest_hash}`
+`DELETE /indexer/api/v1/index_report/{digest}`
Given a Manifest's content addressable hash, any data related to it will be removed it it exists.
-
+Parameters
|Name|In|Type|Required|Description|
|---|---|---|---|---|
-|manifest_hash|path|[Digest](#schemadigest)|true|A digest of a manifest that has been indexed previous to this request.|
+|digest|path|[digest](#schemadigest)|true|OCI-compatible digest of a referred object.|
> Example responses
@@ -651,19 +386,20 @@ Given a Manifest's content addressable hash, any data related to it will be remo
}
```
-
+Responses
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|204|[No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5)|OK|None|
-|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[Error](#schemaerror)|
-|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal Server Error|[Error](#schemaerror)|
+|204|[No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5)|Success|None|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
This operation does not require authentication
-## Retrieve an IndexReport for the given Manifest hash if exists.
+## Retrieve the IndexReport for the referenced manifest.
@@ -672,10 +408,10 @@ This operation does not require authentication
```python
import requests
headers = {
- 'Accept': 'application/json'
+ 'Accept': 'application/vnd.clair.index_report.v1+json'
}
-r = requests.get('/indexer/api/v1/index_report/{manifest_hash}', headers = headers)
+r = requests.get('/indexer/api/v1/index_report/{digest}', headers = headers)
print(r.json())
@@ -692,11 +428,11 @@ import (
func main() {
headers := map[string][]string{
- "Accept": []string{"application/json"},
+ "Accept": []string{"application/vnd.clair.index_report.v1+json"},
}
data := bytes.NewBuffer([]byte{jsonReq})
- req, err := http.NewRequest("GET", "/indexer/api/v1/index_report/{manifest_hash}", data)
+ req, err := http.NewRequest("GET", "/indexer/api/v1/index_report/{digest}", data)
req.Header = headers
client := &http.Client{}
@@ -709,10 +445,10 @@ func main() {
```javascript
const headers = {
- 'Accept':'application/json'
+ 'Accept':'application/vnd.clair.index_report.v1+json'
};
-fetch('/indexer/api/v1/index_report/{manifest_hash}',
+fetch('/indexer/api/v1/index_report/{digest}',
{
method: 'GET',
@@ -726,15 +462,15 @@ fetch('/indexer/api/v1/index_report/{manifest_hash}',
```
-`GET /indexer/api/v1/index_report/{manifest_hash}`
+`GET /indexer/api/v1/index_report/{digest}`
-Given a Manifest's content addressable hash an IndexReport will be retrieved if exists.
+Given a Manifest's content addressable hash, an IndexReport will be retrieved if it exists.
-Parameters
+Parameters
|Name|In|Type|Required|Description|
|---|---|---|---|---|
-|manifest_hash|path|[Digest](#schemadigest)|true|A digest of a manifest that has been indexed previous to this request.|
+|digest|path|[digest](#schemadigest)|true|OCI-compatible digest of a referred object.|
> Example responses
@@ -742,63 +478,35 @@ Given a Manifest's content addressable hash an IndexReport will be retrieved if
```json
{
- "manifest_hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "state": "IndexFinished",
- "packages": {
- "10": {
- "id": "10",
- "name": "libapt-pkg5.0",
- "version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
- "arch": "x86",
- "module": "",
- "cpe": "",
- "source": {
- "id": "9",
- "name": "apt",
- "version": "1.6.11",
- "kind": "source",
- "source": null
- }
- }
- },
- "distributions": {
- "1": {
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS"
- }
- },
- "environments": {
- "10": [
- {
- "package_db": "var/lib/dpkg/status",
- "introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
- "distribution_id": "1"
- }
- ]
- },
+ "manifest_hash": null,
+ "state": "string",
+ "err": "string",
"success": true,
- "err": ""
+ "packages": {},
+ "distributions": {},
+ "repository": {},
+ "environments": {
+ "property1": [],
+ "property2": []
+ }
}
```
-Responses
+Responses
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|IndexReport retrieved|[IndexReport](#schemaindexreport)|
-|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[Error](#schemaerror)|
-|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|Not Found|[Error](#schemaerror)|
-|405|[Method Not Allowed](https://tools.ietf.org/html/rfc7231#section-6.5.5)|Method Not Allowed|[Error](#schemaerror)|
-|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal Server Error|[Error](#schemaerror)|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|IndexReport retrieved|[index_report](#schemaindex_report)|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|Not Found|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
+
+### Response Headers
+
+|Status|Header|Type|Format|Description|
+|---|---|---|---|---|
+|200|Clair-Error|string||This is a trailer containing any errors encountered while writing the response.|
This operation does not require authentication
@@ -813,7 +521,7 @@ This operation does not require authentication
```python
import requests
headers = {
- 'Accept': 'application/json'
+ 'Accept': 'application/vnd.clair.index_state.v1+json'
}
r = requests.get('/indexer/api/v1/index_state', headers = headers)
@@ -833,7 +541,7 @@ import (
func main() {
headers := map[string][]string{
- "Accept": []string{"application/json"},
+ "Accept": []string{"application/vnd.clair.index_state.v1+json"},
}
data := bytes.NewBuffer([]byte{jsonReq})
@@ -850,7 +558,7 @@ func main() {
```javascript
const headers = {
- 'Accept':'application/json'
+ 'Accept':'application/vnd.clair.index_state.v1+json'
};
fetch('/indexer/api/v1/index_state',
@@ -878,7 +586,7 @@ A client may be interested in this as a signal that manifests may need to be re-
```json
{
- "state": "aae368a064d7c5a433d0bf2c4f5554cc"
+ "state": "string"
}
```
@@ -886,22 +594,22 @@ A client may be interested in this as a signal that manifests may need to be re-
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Indexer State|[State](#schemastate)|
-|304|[Not Modified](https://tools.ietf.org/html/rfc7232#section-4.1)|Indexer State Unchanged|None|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Indexer State|[index_state](#schemaindex_state)|
+|304|[Not Modified](https://tools.ietf.org/html/rfc7232#section-4.1)|Not Modified|None|
### Response Headers
|Status|Header|Type|Format|Description|
|---|---|---|---|---|
-|200|Etag|string||Entity Tag|
+|200|Etag|string||HTTP [ETag header](https://httpwg.org/specs/rfc9110.html#field.etag)|
This operation does not require authentication
-Matcher
+matcher
-## Retrieve a VulnerabilityReport for a given manifest's content addressable hash.
+## Retrieve a VulnerabilityReport for the referenced manifest.
@@ -910,10 +618,10 @@ This operation does not require authentication
```python
import requests
headers = {
- 'Accept': 'application/json'
+ 'Accept': 'application/vnd.clair.vulnerability_report.v1+json'
}
-r = requests.get('/matcher/api/v1/vulnerability_report/{manifest_hash}', headers = headers)
+r = requests.get('/matcher/api/v1/vulnerability_report/{digest}', headers = headers)
print(r.json())
@@ -930,11 +638,11 @@ import (
func main() {
headers := map[string][]string{
- "Accept": []string{"application/json"},
+ "Accept": []string{"application/vnd.clair.vulnerability_report.v1+json"},
}
data := bytes.NewBuffer([]byte{jsonReq})
- req, err := http.NewRequest("GET", "/matcher/api/v1/vulnerability_report/{manifest_hash}", data)
+ req, err := http.NewRequest("GET", "/matcher/api/v1/vulnerability_report/{digest}", data)
req.Header = headers
client := &http.Client{}
@@ -947,10 +655,10 @@ func main() {
```javascript
const headers = {
- 'Accept':'application/json'
+ 'Accept':'application/vnd.clair.vulnerability_report.v1+json'
};
-fetch('/matcher/api/v1/vulnerability_report/{manifest_hash}',
+fetch('/matcher/api/v1/vulnerability_report/{digest}',
{
method: 'GET',
@@ -964,15 +672,15 @@ fetch('/matcher/api/v1/vulnerability_report/{manifest_hash}',
```
-`GET /matcher/api/v1/vulnerability_report/{manifest_hash}`
+`GET /matcher/api/v1/vulnerability_report/{digest}`
Given a Manifest's content addressable hash a VulnerabilityReport will be created. The Manifest **must** have been Indexed first via the Index endpoint.
-Parameters
+Parameters
|Name|In|Type|Required|Description|
|---|---|---|---|---|
-|manifest_hash|path|[Digest](#schemadigest)|true|A digest of a manifest that has been indexed previous to this request.|
+|digest|path|[digest](#schemadigest)|true|OCI-compatible digest of a referred object.|
> Example responses
@@ -980,141 +688,229 @@ Given a Manifest's content addressable hash a VulnerabilityReport will be create
```json
{
- "manifest_hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "packages": {
- "10": {
- "id": "10",
- "name": "libapt-pkg5.0",
- "version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
- "arch": "x86",
- "module": "",
- "cpe": "",
- "source": {
- "id": "9",
- "name": "apt",
- "version": "1.6.11",
- "kind": "source",
- "source": null
- }
- }
- },
- "distributions": {
- "1": {
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS"
- }
- },
+ "manifest_hash": null,
+ "packages": {},
+ "distributions": {},
+ "repository": {},
"environments": {
- "10": [
- {
- "package_db": "var/lib/dpkg/status",
- "introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
- "distribution_id": "1"
- }
- ]
- },
- "vulnerabilities": {
- "356835": {
- "id": "356835",
- "updater": "",
- "name": "CVE-2009-5155",
- "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
- "links": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-5155 http://people.canonical.com/~ubuntu-security/cve/2009/CVE-2009-5155.html https://sourceware.org/bugzilla/show_bug.cgi?id=11053 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22793 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32806 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34238 https://sourceware.org/bugzilla/show_bug.cgi?id=18986\"",
- "severity": "Low",
- "normalized_severity": "Low",
- "package": {
- "id": "0",
- "name": "glibc",
- "version": "",
- "kind": "",
- "source": null,
- "package_db": "",
- "repository_hint": ""
- },
- "dist": {
- "id": "0",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": ""
- },
- "repo": {
- "id": "0",
- "name": "Ubuntu 18.04.3 LTS",
- "key": "",
- "uri": ""
- },
- "issued": "2019-10-12T07:20:50.52Z",
- "fixed_in_version": "2.28-0ubuntu1"
- }
+ "property1": [],
+ "property2": []
},
+ "vulnerabilities": {},
"package_vulnerabilities": {
- "10": [
- "356835"
+ "property1": [
+ "string"
+ ],
+ "property2": [
+ "string"
]
+ },
+ "enrichments": {
+ "property1": [],
+ "property2": []
}
}
```
-Responses
+Responses
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|VulnerabilityReport Created|[VulnerabilityReport](#schemavulnerabilityreport)|
-|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[Error](#schemaerror)|
-|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|Not Found|[Error](#schemaerror)|
-|405|[Method Not Allowed](https://tools.ietf.org/html/rfc7231#section-6.5.5)|Method Not Allowed|[Error](#schemaerror)|
-|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Internal Server Error|[Error](#schemaerror)|
+|201|[Created](https://tools.ietf.org/html/rfc7231#section-6.3.2)|Vulnerability Report Created|[vulnerability_report](#schemavulnerability_report)|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|404|[Not Found](https://tools.ietf.org/html/rfc7231#section-6.5.4)|Not Found|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
This operation does not require authentication
-# Schemas
+notifier
-Page
-
-
-
-
-
+## Delete the referenced notification set.
-```json
-{
- "size": 1,
- "next": "1b4d0db2-e757-4150-bbbb-543658144205"
+
+
+> Code samples
+
+```python
+import requests
+headers = {
+ 'Accept': 'application/vnd.clair.error.v1+json'
}
+r = requests.delete('/notifier/api/v1/notification/{id}', headers = headers)
+
+print(r.json())
+
```
-Page
+```go
+package main
-### Properties
+import (
+ "bytes"
+ "net/http"
+)
-|Name|Type|Required|Restrictions|Description|
+func main() {
+
+ headers := map[string][]string{
+ "Accept": []string{"application/vnd.clair.error.v1+json"},
+ }
+
+ data := bytes.NewBuffer([]byte{jsonReq})
+ req, err := http.NewRequest("DELETE", "/notifier/api/v1/notification/{id}", data)
+ req.Header = headers
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ // ...
+}
+
+```
+
+```javascript
+
+const headers = {
+ 'Accept':'application/vnd.clair.error.v1+json'
+};
+
+fetch('/notifier/api/v1/notification/{id}',
+{
+ method: 'DELETE',
+
+ headers: headers
+})
+.then(function(res) {
+ return res.json();
+}).then(function(body) {
+ console.log(body);
+});
+
+```
+
+`DELETE /notifier/api/v1/notification/{id}`
+
+Issues a delete of the provided notification id and all associated notifications.
+After this delete clients will no longer be able to retrieve notifications.
+
+Parameters
+
+|Name|In|Type|Required|Description|
|---|---|---|---|---|
-|size|int|false|none|The maximum number of elements in a page|
-|next|string|false|none|The next id to submit to the api to continue paging|
+|id|path|[token](#schematoken)|true|A notification ID returned by a callback|
-PagedNotifications
-
-
-
-
-
+> Example responses
+
+> 400 Response
+
+```json
+{
+ "code": "string",
+ "message": "string"
+}
+```
+
+Responses
+
+|Status|Meaning|Description|Schema|
+|---|---|---|---|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Success|None|
+|204|[No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5)|TODO|None|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
+
+### Response Headers
+
+|Status|Header|Type|Format|Description|
+|---|---|---|---|---|
+|200|Clair-Error|string||This is a trailer containing any errors encountered while writing the response.|
+
+
+This operation does not require authentication
+
+
+## Retrieve pages of the referenced notification set.
+
+
+
+> Code samples
+
+```python
+import requests
+headers = {
+ 'Accept': 'application/vnd.clair.notification_page.v1+json'
+}
+
+r = requests.get('/notifier/api/v1/notification/{id}', headers = headers)
+
+print(r.json())
+
+```
+
+```go
+package main
+
+import (
+ "bytes"
+ "net/http"
+)
+
+func main() {
+
+ headers := map[string][]string{
+ "Accept": []string{"application/vnd.clair.notification_page.v1+json"},
+ }
+
+ data := bytes.NewBuffer([]byte{jsonReq})
+ req, err := http.NewRequest("GET", "/notifier/api/v1/notification/{id}", data)
+ req.Header = headers
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ // ...
+}
+
+```
+
+```javascript
+
+const headers = {
+ 'Accept':'application/vnd.clair.notification_page.v1+json'
+};
+
+fetch('/notifier/api/v1/notification/{id}',
+{
+ method: 'GET',
+
+ headers: headers
+})
+.then(function(res) {
+ return res.json();
+}).then(function(body) {
+ console.log(body);
+});
+
+```
+
+`GET /notifier/api/v1/notification/{id}`
+
+By performing a GET with an id as a path parameter, the client will retrieve a paginated response of notification objects.
+
+Parameters
+
+|Name|In|Type|Required|Description|
+|---|---|---|---|---|
+|page_size|query|integer|false|The maximum number of notifications to deliver in a single page.|
+|next|query|string|false|The next page to fetch via id. Typically this number is provided on initial response in the "page.next" field. The first request should omit this field.|
+|id|path|[token](#schematoken)|true|A notification ID returned by a callback|
+
+> Example responses
+
+> 200 Response
```json
{
@@ -1130,23 +926,20 @@ Page
"vulnerability": {
"name": "CVE-2009-5155",
"fixed_in_version": "v0.0.1",
- "links": "http://link-to-advisory",
+ "links": "http://example.com/CVE-2009-5155",
"description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
"normalized_severity": "Unknown",
"package": {
"id": "10",
"name": "libapt-pkg5.0",
"version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
+ "kind": "BINARY",
"arch": "x86",
- "module": "",
- "cpe": "",
"source": {
"id": "9",
"name": "apt",
"version": "1.6.11",
- "kind": "source",
+ "kind": "SOURCE",
"source": null
}
},
@@ -1157,546 +950,855 @@ Page
"version": "18.04.3 LTS (Bionic Beaver)",
"version_code_name": "bionic",
"version_id": "18.04",
- "arch": "",
- "cpe": "",
"pretty_name": "Ubuntu 18.04.3 LTS"
- },
- "repository": {
- "id": "string",
- "name": "string",
- "key": "string",
- "uri": "string",
- "cpe": "string"
}
}
}
]
}
+```
+
+Responses
+
+|Status|Meaning|Description|Schema|
+|---|---|---|---|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|A paginated list of notifications|[notification_page](#schemanotification_page)|
+|304|[Not Modified](https://tools.ietf.org/html/rfc7232#section-4.1)|Not modified|None|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
+
+### Response Headers
+
+|Status|Header|Type|Format|Description|
+|---|---|---|---|---|
+|200|Clair-Error|string||This is a trailer containing any errors encountered while writing the response.|
+
+
+This operation does not require authentication
+
+
+internal
+
+## Retrieve the set of manifests affected by the provided vulnerabilities.
+
+
+
+> Code samples
+
+```python
+import requests
+headers = {
+ 'Accept': 'application/vnd.clair.affected_manifests.v1+json'
+}
+
+r = requests.post('/indexer/api/v1/internal/affected_manifest', headers = headers)
+
+print(r.json())
```
-PagedNotifications
+```go
+package main
-### Properties
+import (
+ "bytes"
+ "net/http"
+)
-|Name|Type|Required|Restrictions|Description|
+func main() {
+
+ headers := map[string][]string{
+ "Accept": []string{"application/vnd.clair.affected_manifests.v1+json"},
+ }
+
+ data := bytes.NewBuffer([]byte{jsonReq})
+ req, err := http.NewRequest("POST", "/indexer/api/v1/internal/affected_manifest", data)
+ req.Header = headers
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ // ...
+}
+
+```
+
+```javascript
+
+const headers = {
+ 'Accept':'application/vnd.clair.affected_manifests.v1+json'
+};
+
+fetch('/indexer/api/v1/internal/affected_manifest',
+{
+ method: 'POST',
+
+ headers: headers
+})
+.then(function(res) {
+ return res.json();
+}).then(function(body) {
+ console.log(body);
+});
+
+```
+
+`POST /indexer/api/v1/internal/affected_manifest`
+
+> Example responses
+
+> 200 Response
+
+```json
+{
+ "vulnerabilities": {},
+ "vulnerable_manifests": {
+ "property1": [
+ "string"
+ ],
+ "property2": [
+ "string"
+ ]
+ }
+}
+```
+
+Responses
+
+|Status|Meaning|Description|Schema|
+|---|---|---|---|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|TODO|[affected_manifests](#schemaaffected_manifests)|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
+
+### Response Headers
+
+|Status|Header|Type|Format|Description|
|---|---|---|---|---|
-|page|object|false|none|A page object informing the client the next page to retrieve. If page.next becomes "-1" the client should stop paging.|
-|notifications|[[Notification](#schemanotification)]|false|none|A list of notifications within this page|
+|200|Clair-Error|string||This is a trailer containing any errors encountered while writing the response.|
+
+
+This operation does not require authentication
+
+
+## GetUpdateDiff
+
+
+
+> Code samples
+
+```python
+import requests
+headers = {
+ 'Accept': 'application/vnd.clair.update_diff.v1+json'
+}
+
+r = requests.get('/matcher/api/v1/internal/update_diff', headers = headers)
+
+print(r.json())
+
+```
-Callback
+```go
+package main
+
+import (
+ "bytes"
+ "net/http"
+)
+
+func main() {
+
+ headers := map[string][]string{
+ "Accept": []string{"application/vnd.clair.update_diff.v1+json"},
+ }
+
+ data := bytes.NewBuffer([]byte{jsonReq})
+ req, err := http.NewRequest("GET", "/matcher/api/v1/internal/update_diff", data)
+ req.Header = headers
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ // ...
+}
+
+```
+
+```javascript
+
+const headers = {
+ 'Accept':'application/vnd.clair.update_diff.v1+json'
+};
+
+fetch('/matcher/api/v1/internal/update_diff',
+{
+ method: 'GET',
+
+ headers: headers
+})
+.then(function(res) {
+ return res.json();
+}).then(function(body) {
+ console.log(body);
+});
+
+```
+
+`GET /matcher/api/v1/internal/update_diff`
+
+Parameters
+
+|Name|In|Type|Required|Description|
+|---|---|---|---|---|
+|cur|query|[token](#schematoken)|false|TKTK|
+|prev|query|[token](#schematoken)|false|TKTK|
+
+> Example responses
+
+> 200 Response
+
+```json
+{}
+```
+
+Responses
+
+|Status|Meaning|Description|Schema|
+|---|---|---|---|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|TODO|[update_diff](#schemaupdate_diff)|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
+
+### Response Headers
+
+|Status|Header|Type|Format|Description|
+|---|---|---|---|---|
+|200|Clair-Error|string||This is a trailer containing any errors encountered while writing the response.|
+
+
+This operation does not require authentication
+
+
+## UpdateOperation
+
+
+
+> Code samples
+
+```python
+import requests
+headers = {
+ 'Accept': 'application/vnd.clair.affected_manifests.v1+json'
+}
+
+r = requests.post('/matcher/api/v1/internal/update_operation', headers = headers)
+
+print(r.json())
+
+```
+
+```go
+package main
+
+import (
+ "bytes"
+ "net/http"
+)
+
+func main() {
+
+ headers := map[string][]string{
+ "Accept": []string{"application/vnd.clair.affected_manifests.v1+json"},
+ }
+
+ data := bytes.NewBuffer([]byte{jsonReq})
+ req, err := http.NewRequest("POST", "/matcher/api/v1/internal/update_operation", data)
+ req.Header = headers
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ // ...
+}
+
+```
+
+```javascript
+
+const headers = {
+ 'Accept':'application/vnd.clair.affected_manifests.v1+json'
+};
+
+fetch('/matcher/api/v1/internal/update_operation',
+{
+ method: 'POST',
+
+ headers: headers
+})
+.then(function(res) {
+ return res.json();
+}).then(function(body) {
+ console.log(body);
+});
+
+```
+
+`POST /matcher/api/v1/internal/update_operation`
+
+> Example responses
+
+> 200 Response
+
+```json
+{
+ "vulnerabilities": {},
+ "vulnerable_manifests": {
+ "property1": [
+ "string"
+ ],
+ "property2": [
+ "string"
+ ]
+ }
+}
+```
+
+Responses
+
+|Status|Meaning|Description|Schema|
+|---|---|---|---|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|TODO|[affected_manifests](#schemaaffected_manifests)|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Bad Request|[error](#schemaerror)|
+|415|[Unsupported Media Type](https://tools.ietf.org/html/rfc7231#section-6.5.13)|Unsupported Media Type|[error](#schemaerror)|
+|default|Default|Internal Server Error|[error](#schemaerror)|
+
+### Response Headers
+
+|Status|Header|Type|Format|Description|
+|---|---|---|---|---|
+|200|Clair-Error|string||This is a trailer containing any errors encountered while writing the response.|
+
+
+This operation does not require authentication
+
+
+# Schemas
+
+token
+
+
+
+
+
+
+```json
+"string"
+
+```
+
+An opaque token previously obtained from the service.
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|*anonymous*|string|false|none|An opaque token previously obtained from the service.|
+
+affected_manifests
+
+
+
+
+
+
+```json
+{
+ "vulnerabilities": {},
+ "vulnerable_manifests": {
+ "property1": [
+ "string"
+ ],
+ "property2": [
+ "string"
+ ]
+ }
+}
+
+```
+
+Affected Manifests
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|vulnerabilities|object|false|none|Vulnerability objects.|
+|» **additionalProperties**|[vulnerability.schema.json](#schemavulnerability.schema.json)|false|none|none|
+|vulnerable_manifests|object|true|none|Mapping of manifest digests to vulnerability identifiers.|
+|» **additionalProperties**|[string]|false|none|none|
+
+bulk_delete
+
+
+
+
+
+
+```json
+[
+ "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3"
+]
+
+```
+
+Bulk Delete
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|Bulk Delete|[[digest.schema.json](#schemadigest.schema.json)]|false|none|Array of manifest digests to delete from the system.|
+
+cpe
+
+
+
+
+
+
+```json
+"cpe:/a:microsoft:internet_explorer:8.0.6001:beta"
+
+```
+
+Common Platform Enumeration Name
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|Common Platform Enumeration Name|any|false|none|This is a CPE Name in either v2.2 "URI" form or v2.3 "Formatted String" form.|
+
+oneOf
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|*anonymous*|string|false|none|This is the CPE 2.2 regexp: https://cpe.mitre.org/specification/2.2/cpe-language_2.2.xsd|
+
+xor
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|*anonymous*|string|false|none|This is the CPE 2.3 regexp: https://csrc.nist.gov/schema/cpe/2.3/cpe-naming_2.3.xsd|
+
+digest
+
+
+
+
+
+
+```json
+"string"
+
+```
+
+Digest
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|Digest|any|false|none|A digest acts as a content identifier, enabling content addressability.|
+
+oneOf
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|*anonymous*|string|false|none|SHA256|
+
+xor
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|*anonymous*|string|false|none|SHA512|
+
+xor
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|*anonymous*|string|false|none|BLAKE3 **Currently not implemented.**|
+
+distribution
+
+
+
+
+
+
+```json
+{
+ "id": "1",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04",
+ "pretty_name": "Ubuntu 18.04.3 LTS"
+}
+
+```
+
+Distribution
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|id|string|true|none|Unique ID for this Distribution. May be unique to the response document, not the whole system.|
+|did|string|false|none|A lower-case string (no spaces or other characters outside of 0–9, a–z, ".", "_", and "-") identifying the operating system, excluding any version information and suitable for processing by scripts or usage in generated filenames.|
+|name|string|false|none|A string identifying the operating system.|
+|version|string|false|none|A string identifying the operating system version, excluding any OS name information, possibly including a release code name, and suitable for presentation to the user.|
+|version_code_name|string|false|none|A lower-case string (no spaces or other characters outside of 0–9, a–z, ".", "_", and "-") identifying the operating system release code name, excluding any OS name information or release version, and suitable for processing by scripts or usage in generated filenames.|
+|version_id|string|false|none|A lower-case string (mostly numeric, no spaces or other characters outside of 0–9, a–z, ".", "_", and "-") identifying the operating system version, excluding any OS name information or release code name.|
+|arch|string|false|none|A string identifying the OS architecture.|
+|cpe|[cpe.schema.json](#schemacpe.schema.json)|false|none|Common Platform Enumeration name.|
+|pretty_name|string|false|none|A pretty operating system name in a format suitable for presentation to the user.|
+
+environment
+
+
+
+
+
+
+```json
+{
+ "value": {
+ "package_db": "var/lib/dpkg/status",
+ "introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
+ "distribution_id": "1"
+ }
+}
+
+```
+
+Environment
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|package_db|string|false|none|The database the associated Package was discovered in.|
+|distribution_id|string|false|none|The ID of the Distribution of the associated Package.|
+|introduced_in|[digest.schema.json](#schemadigest.schema.json)|false|none|The Layer the associated Package was introduced in.|
+|repository_ids|[string]|false|none|The IDs of the Repositories of the associated Package.|
+
+error
+
+
+
+
+
+
+```json
+{
+ "code": "string",
+ "message": "string"
+}
+
+```
+
+Error
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|code|string|false|none|a code for this particular error|
+|message|string|true|none|a message with further detail|
+
+index_report
+
+
+
+
+
+
+```json
+{
+ "manifest_hash": null,
+ "state": "string",
+ "err": "string",
+ "success": true,
+ "packages": {},
+ "distributions": {},
+ "repository": {},
+ "environments": {
+ "property1": [],
+ "property2": []
+ }
+}
+
+```
+
+Index Report
+
+### Properties
+
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|manifest_hash|[digest.schema.json](#schemadigest.schema.json)|true|none|The Manifest's digest.|
+|state|string|true|none|The current state of the index operation|
+|err|string|false|none|An error message on event of unsuccessful index|
+|success|boolean|true|none|A bool indicating succcessful index|
+|packages|object|false|none|A map of Package objects indexed by a document-local identifier.|
+|» **additionalProperties**|[package.schema.json](#schemapackage.schema.json)|false|none|none|
+|distributions|object|false|none|A map of Distribution objects indexed by a document-local identifier.|
+|» **additionalProperties**|[distribution.schema.json](#schemadistribution.schema.json)|false|none|none|
+|repository|object|false|none|A map of Repository objects indexed by a document-local identifier.|
+|» **additionalProperties**|[repository.schema.json](#schemarepository.schema.json)|false|none|none|
+|environments|object|false|none|A map of Environment arrays indexed by a Package's identifier.|
+|» **additionalProperties**|[[environment.schema.json](#schemaenvironment.schema.json)]|false|none|none|
+
+index_state
-
-
-
-
+
+
+
+
```json
{
- "notification_id": "269886f3-0146-4f08-9bf7-cb1138d48643",
- "callback": "http://clair-notifier/notifier/api/v1/notification/269886f3-0146-4f08-9bf7-cb1138d48643"
+ "state": "string"
}
```
-Callback
+Index State
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|notification_id|string|false|none|the unique identifier for this set of notifications|
-|callback|string|false|none|the url where notifications can be retrieved|
+|state|string|true|none|an opaque token|
-VulnSummary
+layer
-
-
-
-
+
+
+
+
```json
{
- "name": "CVE-2009-5155",
- "fixed_in_version": "v0.0.1",
- "links": "http://link-to-advisory",
- "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
- "normalized_severity": "Unknown",
- "package": {
- "id": "10",
- "name": "libapt-pkg5.0",
- "version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
- "arch": "x86",
- "module": "",
- "cpe": "",
- "source": {
- "id": "9",
- "name": "apt",
- "version": "1.6.11",
- "kind": "source",
- "source": null
- }
- },
- "distribution": {
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS"
- },
- "repository": {
- "id": "string",
- "name": "string",
- "key": "string",
- "uri": "string",
- "cpe": "string"
- }
+ "hash": null,
+ "uri": "string",
+ "headers": {},
+ "media_type": "string"
}
```
-VulnSummary
+Layer
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|name|string|false|none|the vulnerability name|
-|fixed_in_version|string|false|none|The version which the vulnerability is fixed in. Empty if not fixed.|
-|links|string|false|none|links to external information about vulnerability|
-|description|string|false|none|the vulnerability name|
-|normalized_severity|string|false|none|A well defined set of severity strings guaranteed to be present.|
-|package|[Package](#schemapackage)|false|none|A package discovered by indexing a Manifest|
-|distribution|[Distribution](#schemadistribution)|false|none|An indexed distribution discovered in a layer. See https://www.freedesktop.org/software/systemd/man/os-release.html for explanations and example of fields.|
-|repository|[Repository](#schemarepository)|false|none|A package repository|
+|hash|[digest.schema.json](#schemadigest.schema.json)|true|none|Digest of the layer blob.|
+|uri|string|true|none|A URI indicating where the layer blob can be downloaded from.|
+|headers|object|false|none|Any additional HTTP-style headers needed for requesting layers.|
+|» ^[a-zA-Z0-9\-_]+$|[string]|false|none|none|
+|media_type|string|false|none|The OCI Layer media type for this layer.|
-#### Enumerated Values
-
-|Property|Value|
-|---|---|
-|normalized_severity|Unknown|
-|normalized_severity|Negligible|
-|normalized_severity|Low|
-|normalized_severity|Medium|
-|normalized_severity|High|
-|normalized_severity|Critical|
-
-Notification
+manifest
-
-
-
-
+
+
+
+
```json
{
- "id": "5e4b387e-88d3-4364-86fd-063447a6fad2",
- "manifest": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
- "reason": "added",
- "vulnerability": {
- "name": "CVE-2009-5155",
- "fixed_in_version": "v0.0.1",
- "links": "http://link-to-advisory",
- "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
- "normalized_severity": "Unknown",
- "package": {
- "id": "10",
- "name": "libapt-pkg5.0",
- "version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
- "arch": "x86",
- "module": "",
- "cpe": "",
- "source": {
- "id": "9",
- "name": "apt",
- "version": "1.6.11",
- "kind": "source",
- "source": null
+ "hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
+ "layers": [
+ {
+ "hash": "sha256:2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
+ "uri": "https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
+ "headers": {
+ "Authoriztion": [
+ "Bearer hunter2"
+ ]
}
- },
- "distribution": {
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS"
- },
- "repository": {
- "id": "string",
- "name": "string",
- "key": "string",
- "uri": "string",
- "cpe": "string"
}
- }
+ ]
}
```
-Notification
+Manifest
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|id|string|false|none|a unique identifier for this notification|
-|manifest|string|false|none|The hash of the manifest affected by the provided vulnerability.|
-|reason|string|false|none|the reason for the notifcation, [added | removed]|
-|vulnerability|[VulnSummary](#schemavulnsummary)|false|none|A summary of a vulnerability|
+|hash|[digest.schema.json](#schemadigest.schema.json)|true|none|The OCI Image Manifest's digest. This is used as an identifier throughout the system. This **SHOULD** be the same as the OCI Image Manifest's digest, but this is not enforced.|
+|layers|[[layer.schema.json](#schemalayer.schema.json)]|false|none|The OCI Layers making up the Image, in order.|
-Environment
+normalized_severity
-
-
-
-
+
+
+
+
```json
-{
- "package_db": "var/lib/dpkg/status",
- "introduced_in": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "distribution_id": "1"
-}
+"Unknown"
```
-Environment
+Normalized Severity
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|package_db|string|true|none|The filesystem path or unique identifier of a package database.|
-|introduced_in|[Digest](#schemadigest)|true|none|A digest string with prefixed algorithm. The format is described here: https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests Digests are used throughout the API to identify Layers and Manifests.|
-|distribution_id|string|true|none|The distribution ID found in an associated IndexReport or VulnerabilityReport.|
+|Normalized Severity|any|false|none|Standardized severity values.|
+
+#### Enumerated Values
-IndexReport
+|Property|Value|
+|---|---|
+|Normalized Severity|Unknown|
+|Normalized Severity|Negligible|
+|Normalized Severity|Low|
+|Normalized Severity|Medium|
+|Normalized Severity|High|
+|Normalized Severity|Critical|
+
+notification_page
-
-
-
-
+
+
+
+
```json
{
- "manifest_hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "state": "IndexFinished",
- "packages": {
- "10": {
- "id": "10",
- "name": "libapt-pkg5.0",
- "version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
- "arch": "x86",
- "module": "",
- "cpe": "",
- "source": {
- "id": "9",
- "name": "apt",
- "version": "1.6.11",
- "kind": "source",
- "source": null
- }
- }
- },
- "distributions": {
- "1": {
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS"
- }
+ "page": {
+ "size": 100,
+ "next": "1b4d0db2-e757-4150-bbbb-543658144205"
},
- "environments": {
- "10": [
- {
- "package_db": "var/lib/dpkg/status",
- "introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
- "distribution_id": "1"
+ "notifications": [
+ {
+ "id": "5e4b387e-88d3-4364-86fd-063447a6fad2",
+ "manifest": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
+ "reason": "added",
+ "vulnerability": {
+ "name": "CVE-2009-5155",
+ "fixed_in_version": "v0.0.1",
+ "links": "http://example.com/CVE-2009-5155",
+ "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
+ "normalized_severity": "Unknown",
+ "package": {
+ "id": "10",
+ "name": "libapt-pkg5.0",
+ "version": "1.6.11",
+ "kind": "BINARY",
+ "arch": "x86",
+ "source": {
+ "id": "9",
+ "name": "apt",
+ "version": "1.6.11",
+ "kind": "SOURCE",
+ "source": null
+ }
+ },
+ "distribution": {
+ "id": "1",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04",
+ "pretty_name": "Ubuntu 18.04.3 LTS"
+ }
}
- ]
- },
- "success": true,
- "err": ""
+ }
+ ]
}
```
-IndexReport
+Notification Page
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|manifest_hash|[Digest](#schemadigest)|true|none|A digest string with prefixed algorithm. The format is described here: https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests Digests are used throughout the API to identify Layers and Manifests.|
-|state|string|true|none|The current state of the index operation|
-|packages|object|true|none|A map of Package objects indexed by Package.id|
-|» **additionalProperties**|[Package](#schemapackage)|false|none|A package discovered by indexing a Manifest|
-|distributions|object|true|none|A map of Distribution objects keyed by their Distribution.id discovered in the manifest.|
-|» **additionalProperties**|[Distribution](#schemadistribution)|false|none|An indexed distribution discovered in a layer. See https://www.freedesktop.org/software/systemd/man/os-release.html for explanations and example of fields.|
-|environments|object|true|none|A map of lists containing Environment objects keyed by the associated Package.id.|
-|» **additionalProperties**|[[Environment](#schemaenvironment)]|false|none|[The environment a particular package was discovered in.]|
-|success|boolean|true|none|A bool indicating succcessful index|
-|err|string|true|none|An error message on event of unsuccessful index|
+|page|object|true|none|An object informing the client the next page to retrieve.|
+|» size|integer|true|none|none|
+|» next|any|false|none|none|
-VulnerabilityReport
-
-
-
-
-
+oneOf
-```json
-{
- "manifest_hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "packages": {
- "10": {
- "id": "10",
- "name": "libapt-pkg5.0",
- "version": "1.6.11",
- "kind": "binary",
- "normalized_version": "",
- "arch": "x86",
- "module": "",
- "cpe": "",
- "source": {
- "id": "9",
- "name": "apt",
- "version": "1.6.11",
- "kind": "source",
- "source": null
- }
- }
- },
- "distributions": {
- "1": {
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS"
- }
- },
- "environments": {
- "10": [
- {
- "package_db": "var/lib/dpkg/status",
- "introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
- "distribution_id": "1"
- }
- ]
- },
- "vulnerabilities": {
- "356835": {
- "id": "356835",
- "updater": "",
- "name": "CVE-2009-5155",
- "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
- "links": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-5155 http://people.canonical.com/~ubuntu-security/cve/2009/CVE-2009-5155.html https://sourceware.org/bugzilla/show_bug.cgi?id=11053 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22793 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32806 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34238 https://sourceware.org/bugzilla/show_bug.cgi?id=18986\"",
- "severity": "Low",
- "normalized_severity": "Low",
- "package": {
- "id": "0",
- "name": "glibc",
- "version": "",
- "kind": "",
- "source": null,
- "package_db": "",
- "repository_hint": ""
- },
- "dist": {
- "id": "0",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": ""
- },
- "repo": {
- "id": "0",
- "name": "Ubuntu 18.04.3 LTS",
- "key": "",
- "uri": ""
- },
- "issued": "2019-10-12T07:20:50.52Z",
- "fixed_in_version": "2.28-0ubuntu1"
- }
- },
- "package_vulnerabilities": {
- "10": [
- "356835"
- ]
- }
-}
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|»» *anonymous*|string|false|none|none|
-```
+xor
-VulnerabilityReport
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|»» *anonymous*|any|false|none|none|
-### Properties
+continued
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|manifest_hash|[Digest](#schemadigest)|true|none|A digest string with prefixed algorithm. The format is described here: https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests Digests are used throughout the API to identify Layers and Manifests.|
-|packages|object|true|none|A map of Package objects indexed by Package.id|
-|» **additionalProperties**|[Package](#schemapackage)|false|none|A package discovered by indexing a Manifest|
-|distributions|object|true|none|A map of Distribution objects indexed by Distribution.id.|
-|» **additionalProperties**|[Distribution](#schemadistribution)|false|none|An indexed distribution discovered in a layer. See https://www.freedesktop.org/software/systemd/man/os-release.html for explanations and example of fields.|
-|environments|object|true|none|A mapping of Environment lists indexed by Package.id|
-|» **additionalProperties**|[[Environment](#schemaenvironment)]|false|none|[The environment a particular package was discovered in.]|
-|vulnerabilities|object|true|none|A map of Vulnerabilities indexed by Vulnerability.id|
-|» **additionalProperties**|[Vulnerability](#schemavulnerability)|false|none|A unique vulnerability indexed by Clair|
-|package_vulnerabilities|object|true|none|A mapping of Vulnerability.id lists indexed by Package.id.|
-|» **additionalProperties**|[string]|false|none|none|
+|notifications|[[notification.schema.json](#schemanotification.schema.json)]|true|none|Notifications within this page.|
-Vulnerability
+notification
-
-
-
-
+
+
+
+
```json
{
- "id": "356835",
- "updater": "",
- "name": "CVE-2009-5155",
- "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
- "links": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-5155 http://people.canonical.com/~ubuntu-security/cve/2009/CVE-2009-5155.html https://sourceware.org/bugzilla/show_bug.cgi?id=11053 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22793 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32806 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34238 https://sourceware.org/bugzilla/show_bug.cgi?id=18986\"",
- "severity": "Low",
- "normalized_severity": "Low",
- "package": {
- "id": "0",
- "name": "glibc",
- "version": "",
- "kind": "",
- "source": null,
- "package_db": "",
- "repository_hint": ""
- },
- "dist": {
- "id": "0",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": ""
- },
- "repo": {
- "id": "0",
- "name": "Ubuntu 18.04.3 LTS",
- "key": "",
- "uri": ""
- },
- "issued": "2019-10-12T07:20:50.52Z",
- "fixed_in_version": "2.28-0ubuntu1",
- "x-widdershins-oldRef": "#/components/examples/Vulnerability/value"
+ "id": "string",
+ "manifest": null,
+ "reason": "added",
+ "vulnerability": null
}
```
-Vulnerability
+Notification
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|id|string|true|none|A unique ID representing this vulnerability.|
-|updater|string|true|none|A unique ID representing this vulnerability.|
-|name|string|true|none|Name of this specific vulnerability.|
-|description|string|true|none|A description of this specific vulnerability.|
-|links|string|true|none|A space separate list of links to any external information.|
-|severity|string|true|none|A severity keyword taken verbatim from the vulnerability source.|
-|normalized_severity|string|true|none|A well defined set of severity strings guaranteed to be present.|
-|package|[Package](#schemapackage)|false|none|A package discovered by indexing a Manifest|
-|distribution|[Distribution](#schemadistribution)|false|none|An indexed distribution discovered in a layer. See https://www.freedesktop.org/software/systemd/man/os-release.html for explanations and example of fields.|
-|repository|[Repository](#schemarepository)|false|none|A package repository|
-|issued|string|false|none|The timestamp in which the vulnerability was issued|
-|range|string|false|none|The range of package versions affected by this vulnerability.|
-|fixed_in_version|string|true|none|A unique ID representing this vulnerability.|
+|id|string|true|none|Unique identifier for this notification.|
+|manifest|[digest.schema.json](#schemadigest.schema.json)|true|none|The digest of the manifest affected by the provided vulnerability.|
+|reason|any|true|none|The reason for the notifcation.|
+|vulnerability|[vulnerability_summary.schema.json](#schemavulnerability_summary.schema.json)|true|none|none|
#### Enumerated Values
|Property|Value|
|---|---|
-|normalized_severity|Unknown|
-|normalized_severity|Negligible|
-|normalized_severity|Low|
-|normalized_severity|Medium|
-|normalized_severity|High|
-|normalized_severity|Critical|
-
-Distribution
-
-
-
-
-
-
-```json
-{
- "id": "1",
- "did": "ubuntu",
- "name": "Ubuntu",
- "version": "18.04.3 LTS (Bionic Beaver)",
- "version_code_name": "bionic",
- "version_id": "18.04",
- "arch": "",
- "cpe": "",
- "pretty_name": "Ubuntu 18.04.3 LTS",
- "x-widdershins-oldRef": "#/components/examples/Distribution/value"
-}
-
-```
+|reason|added|
+|reason|removed|
-Distribution
-
-### Properties
-
-|Name|Type|Required|Restrictions|Description|
-|---|---|---|---|---|
-|id|string|true|none|A unique ID representing this distribution|
-|did|string|true|none|none|
-|name|string|true|none|none|
-|version|string|true|none|none|
-|version_code_name|string|true|none|none|
-|version_id|string|true|none|none|
-|arch|string|true|none|none|
-|cpe|string|true|none|none|
-|pretty_name|string|true|none|none|
-
-Package
+package
-
+
@@ -1716,8 +1818,7 @@ Distribution
"version": "1.6.11",
"kind": "source",
"source": null
- },
- "x-widdershins-oldRef": "#/components/examples/Package/value"
+ }
}
```
@@ -1728,222 +1829,248 @@ Package
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|id|string|true|none|A unique ID representing this package|
-|name|string|true|none|Name of the Package|
-|version|string|true|none|Version of the Package|
-|kind|string|false|none|Kind of package. Source | Binary|
-|source|[Package](#schemapackage)|false|none|A package discovered by indexing a Manifest|
-|normalized_version|[Version](#schemaversion)|false|none|Version is a normalized claircore version, composed of a "kind" and an array of integers such that two versions of the same kind have the correct ordering when the integers are compared pair-wise.|
-|arch|string|false|none|The package's target system architecture|
-|module|string|false|none|A module further defining a namespace for a package|
-|cpe|string|false|none|A CPE identifying the package|
-
-Repository
+|id|string|false|none|Unique ID for this Package. May be unique to the response document, not the whole system.|
+|name|string|true|none|Identifier of this Package. The uniqueness and scoping of this name depends on the packaging system.|
+|version|string|true|none|Version of this Package, as reported by the packaging system.|
+|kind|any|false|none|The "kind" of this Package.|
+|source|[#](#schema#)|false|none|Source Package that produced the current binary Package, if known.|
+|normalized_version|string|false|none|Normalized representation of the discoverd version. The format is not specific, but is guarenteed to be forward compatible.|
+|module|string|false|none|An identifier for intra-Repository grouping of packages. Likely only relevant on rpm-based systems.|
+|arch|string|false|none|Native architecture for the Package.|
+|cpe|[cpe.schema.json](#schemacpe.schema.json)|false|none|CPE Name for the Package.|
+
+#### Enumerated Values
+
+|Property|Value|
+|---|---|
+|kind|BINARY|
+|kind|SOURCE|
+
+range
-
-
-
-
+
+
+
+
```json
{
- "id": "string",
- "name": "string",
- "key": "string",
- "uri": "string",
- "cpe": "string"
+ "[": "string",
+ ")": "string"
}
```
-Repository
+Range
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|id|string|false|none|none|
-|name|string|false|none|none|
-|key|string|false|none|none|
-|uri|string|false|none|none|
-|cpe|string|false|none|none|
+|[|string|false|none|Lower bound, inclusive.|
+|)|string|false|none|Upper bound, exclusive.|
-Version
+repository
-
-
-
-
+
+
+
+
```json
-"pep440:0.0.0.0.0.0.0.0.0"
+{
+ "id": "string",
+ "name": "string",
+ "key": "string",
+ "uri": "http://example.com",
+ "cpe": null
+}
```
-Version
+Repository
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|Version|string|false|none|Version is a normalized claircore version, composed of a "kind" and an array of integers such that two versions of the same kind have the correct ordering when the integers are compared pair-wise.|
+|id|string|true|none|Unique ID for this Repository. May be unique to the response document, not the whole system.|
+|name|string|false|none|Human-relevant name for the Repository.|
+|key|string|false|none|Machine-relevant name for the Repository.|
+|uri|string(uri)|false|none|URI describing the Repository.|
+|cpe|[cpe.schema.json](#schemacpe.schema.json)|false|none|CPE name for the Repository.|
-Manifest
+update_diff
-
-
-
-
+
+
+
+
```json
-{
- "hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "layers": [
- {
- "hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "uri": "https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
- "headers": {
- "property1": [
- "string"
- ],
- "property2": [
- "string"
- ]
- }
- }
- ]
-}
+{}
```
-Manifest
+Update Difference
### Properties
-|Name|Type|Required|Restrictions|Description|
-|---|---|---|---|---|
-|hash|[Digest](#schemadigest)|true|none|A digest string with prefixed algorithm. The format is described here: https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests Digests are used throughout the API to identify Layers and Manifests.|
-|layers|[[Layer](#schemalayer)]|true|none|[A Layer within a Manifest and where Clair may retrieve it.]|
+*None*
-Layer
+vulnerability_core
-
-
-
-
+
+
+
+
```json
{
- "hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
- "uri": "https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
- "headers": {
- "property1": [
- "string"
- ],
- "property2": [
- "string"
- ]
- }
+ "name": "string",
+ "fixed_in_version": "string",
+ "severity": "string",
+ "normalized_severity": null,
+ "range": null,
+ "arch_op": "equals",
+ "package": null,
+ "distribution": null,
+ "repository": null
}
```
-Layer
+Vulnerability Core
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|hash|[Digest](#schemadigest)|true|none|A digest string with prefixed algorithm. The format is described here: https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests Digests are used throughout the API to identify Layers and Manifests.|
-|uri|string|true|none|A URI describing where the layer may be found. Implementations MUST support http(s) schemes and MAY support additional schemes.|
-|headers|object|true|none|map of arrays of header values keyed by header value. e.g. map[string][]string|
-|» **additionalProperties**|[string]|false|none|none|
-
-BulkDelete
-
-
-
-
-
+|name|string|true|none|Human-readable name, as presented in the vendor data.|
+|fixed_in_version|string|false|none|Version string, as presented in the vendor data.|
+|severity|string|false|none|Severity, as presented in the vendor data.|
+|normalized_severity|[normalized_severity.schema.json](#schemanormalized_severity.schema.json)|true|none|A well defined set of severity strings guaranteed to be present.|
+|range|[range.schema.json](#schemarange.schema.json)|false|none|Range of versions the vulnerability applies to.|
+|arch_op|any|false|none|Flag indicating how the referenced package's "arch" member should be interpreted.|
+|package|[package.schema.json](#schemapackage.schema.json)|false|none|A package description|
+|distribution|[distribution.schema.json](#schemadistribution.schema.json)|false|none|A distribution description|
+|repository|[repository.schema.json](#schemarepository.schema.json)|false|none|A repository description|
+
+anyOf
-```json
-[
- "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3"
-]
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|*anonymous*|object|false|none|none|
-```
+or
-BulkDelete
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|*anonymous*|object|false|none|none|
-### Properties
+or
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|BulkDelete|[[Digest](#schemadigest)]|false|none|An array of Digests to be deleted.|
+|*anonymous*|object|false|none|none|
+
+#### Enumerated Values
-Error
+|Property|Value|
+|---|---|
+|arch_op|equals|
+|arch_op|not equals|
+|arch_op|pattern match|
+
+vulnerability_report
-
-
-
-
+
+
+
+
```json
{
- "code": "string",
- "message": "string"
+ "manifest_hash": null,
+ "packages": {},
+ "distributions": {},
+ "repository": {},
+ "environments": {
+ "property1": [],
+ "property2": []
+ },
+ "vulnerabilities": {},
+ "package_vulnerabilities": {
+ "property1": [
+ "string"
+ ],
+ "property2": [
+ "string"
+ ]
+ },
+ "enrichments": {
+ "property1": [],
+ "property2": []
+ }
}
```
-Error
+Vulnerability Report
### Properties
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|code|string|false|none|a code for this particular error|
-|message|string|false|none|a message with further detail|
+|manifest_hash|[digest.schema.json](#schemadigest.schema.json)|true|none|The Manifest's digest.|
+|packages|object|true|none|A map of Package objects indexed by a document-local identifier.|
+|» **additionalProperties**|[package.schema.json](#schemapackage.schema.json)|false|none|none|
+|distributions|object|true|none|A map of Distribution objects indexed by a document-local identifier.|
+|» **additionalProperties**|[distribution.schema.json](#schemadistribution.schema.json)|false|none|none|
+|repository|object|false|none|A map of Repository objects indexed by a document-local identifier.|
+|» **additionalProperties**|[repository.schema.json](#schemarepository.schema.json)|false|none|none|
+|environments|object|true|none|A map of Environment arrays indexed by a Package's identifier.|
+|» **additionalProperties**|[[environment.schema.json](#schemaenvironment.schema.json)]|false|none|none|
+|vulnerabilities|object|true|none|A map of Vulnerabilities indexed by a document-local identifier.|
+|» **additionalProperties**|[vulnerability.schema.json](#schemavulnerability.schema.json)|false|none|none|
+|package_vulnerabilities|object|true|none|A mapping of Vulnerability identifier lists indexed by Package identifier.|
+|» **additionalProperties**|[string]|false|none|none|
+|enrichments|object|false|none|A mapping of extra "enrichment" data by type|
+|» **additionalProperties**|array|false|none|none|
-State
+vulnerability
-
-
-
-
+
+
+
+
```json
-{
- "state": "aae368a064d7c5a433d0bf2c4f5554cc"
-}
+false
```
-State
+Vulnerability
### Properties
-|Name|Type|Required|Restrictions|Description|
-|---|---|---|---|---|
-|state|string|true|none|an opaque identifier|
+*None*
-Digest
+vulnerability_summary
-
-
-
-
+
+
+
+
```json
-"sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3"
+false
```
-Digest
+Vulnerability Summary
### Properties
-|Name|Type|Required|Restrictions|Description|
-|---|---|---|---|---|
-|Digest|string|false|none|A digest string with prefixed algorithm. The format is described here: https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests Digests are used throughout the API to identify Layers and Manifests.|
+*None*
diff --git a/Makefile b/Makefile
index dbe85570cc..19b0ed53b6 100644
--- a/Makefile
+++ b/Makefile
@@ -29,16 +29,6 @@ rm_pat =
all:
$(go) build ./cmd/...
-# Use https://github.com/Mermade/widdershins to convert openapi.yaml to
-# markdown. You'll need to have npx to run this.
-Documentation/reference/api.md: openapi.yaml
- npx widdershins\
- --search false \
- --language_tabs 'python:Python' 'go:Golang' 'javascript:Javascript' \
- --summary $< \
- -o $@
-# Intended to be checked-in, so not cleaned.
-
contrib/openshift/grafana/dashboards/dashboard-clair.configmap.yaml: \
local-dev/grafana/provisioning/dashboards/clair.json \
contrib/openshift/grafana/dashboard-clair.configmap.yaml.tpl
diff --git a/httptransport/api/.gitattributes b/httptransport/api/.gitattributes
new file mode 100644
index 0000000000..a971df5c30
--- /dev/null
+++ b/httptransport/api/.gitattributes
@@ -0,0 +1,3 @@
+v*/openapi.json linguist-generated
+v*/openapi.yaml linguist-generated
+v*/openapi.etag linguist-generated
diff --git a/httptransport/api/lib/oapi.jq b/httptransport/api/lib/oapi.jq
new file mode 100644
index 0000000000..ba9b10f108
--- /dev/null
+++ b/httptransport/api/lib/oapi.jq
@@ -0,0 +1,64 @@
+# vim: set expandtab ts=2 sw=2:
+module {
+ name: "openapi",
+};
+
+# Some helper functions:
+
+def ref($ref): # Construct a JSON Schema reference object.
+ { "$ref": "\($ref)" }
+;
+
+def lref($kind; $id): # Construct a ref object to an OpenAPI component.
+ ref("#/components/\($kind)/\($id)")
+;
+
+def param_ref($id): # Construct a ref object to an OpenAPI parameter component.
+ lref("parameters"; $id)
+;
+
+def response_ref($id): # Construct a ref object to an OpenAPI response component.
+ lref("responses"; $id)
+;
+
+def header_ref($id): # Construct a ref object to an OpenAPI header component.
+ lref("headers"; $id)
+;
+
+def schema_ref($id): # Construct a ref object to an OpenAPI schema component.
+ lref("schemas"; $id)
+;
+
+def mediatype($t; $v): # Return the local vendor mediatype for $t, version $v.
+ "application/vnd.clair.\($t).\($v)+json"
+;
+
+def mediatype($t): # As mediatype/2, but with the default of "v1".
+ mediatype($t; "v1")
+;
+
+def contenttype($t; $v): # Construct an OpenAPI content type object for $t, version $v.
+ { (mediatype($t; $v)): { "schema": schema_ref($t) } }
+;
+
+def contenttype($t): # As contenttype/2, but with the default version.
+ { (mediatype($t)): { "schema": schema_ref($t) } }
+;
+
+def cli_hints: # Add some hints that CLI tools can pick up on to ignore our internal paths.
+ (.paths[][] | select(objects and (.tags|contains(["internal"]))) ) |= . + {"x-cli-ignore": true}
+;
+
+def sort_paths: # Sort the paths object.
+ .paths |= (. | to_entries | sort_by(.key) | from_entries)
+;
+
+def content_defaults: # All responses that don't have a "default" type, pick the first one.
+ "application/json" as $t |
+ [["example"], ["examples"]] as $rm |
+ ( .paths[][] | select(objects) | .responses[].content | select(objects and (has($t)|not)) ) |= (. + { $t: (to_entries[0].value | delpaths($rm)) })
+ |
+ ( .paths[][] | select(objects) | .requestBody.content | select(objects and (has($t)|not)) ) |= (. + { $t: (to_entries[0].value | delpaths($rm)) })
+ |
+ ( .components.responses[].content | select(has($t)|not) ) |= (. + { $t: (to_entries[0].value | delpaths($rm)) })
+;
diff --git a/httptransport/api/openapi.zsh b/httptransport/api/openapi.zsh
new file mode 100755
index 0000000000..6b6c5cc63e
--- /dev/null
+++ b/httptransport/api/openapi.zsh
@@ -0,0 +1,96 @@
+#!/usr/bin/zsh
+set -euo pipefail
+
+# This script builds the OpenAPI documents, rendering them into YAML and JSON.
+#
+# The main inputs for this are the "openapi.jq" files in the "v?" directories.
+# These are jq(1) scripts that are executed with no input in the relevant
+# directory; they're expected to output a valid OpenAPI document. All the JSON
+# Schema documents in the matching "httptransport/types/v?" directory are
+# copied into the working directory. Matching files in the "examples"
+# subdirectory will be slipstreamed to the expected field.
+#
+# The result is then "bundled" into one document, then linted, rendered out to
+# both YAML and JSON, and strings to be used as HTTP Etags are written out.
+
+for cmd in sha256sum git jq yq npx; do
+ if ! command -v "$cmd" &>/dev/null; then
+ print missing needed command: "$cmd" >&2
+ exit 1
+ fi
+done
+local root=$(git rev-parse --show-toplevel)
+
+function jq() {
+ command jq --exit-status "$@"
+}
+
+function yq() {
+ command yq --exit-status "$@"
+}
+
+function schemalint() {
+ local tmp=$(mktemp --tmpdir schemalint.out.XXX)
+ trap "
+ [[ \"\$?\" -eq 0 ]] || cat \"$tmp\"
+ [[ -f \"$tmp\" ]] && rm \"$tmp\"
+ " EXIT
+ npx --yes @sourcemeta/jsonschema metaschema --resolve "$1" "$1" &>>"$tmp"
+ npx --yes @sourcemeta/jsonschema lint --resolve "$1" "$1" &>>"$tmp"
+}
+
+function widdershins() {
+ local tmp=$(mktemp --tmpdir widdershins.out.XXX)
+ trap "
+ [[ \"\$?\" -eq 0 ]] || cat \"$tmp\"
+ [[ -f \"$tmp\" ]] && rm \"$tmp\"
+ " EXIT
+ npx --yes widdershins \
+ -o "${root}/Documentation/reference/api.md" \
+ --search false \
+ --language_tabs python:Python go:Golang javascript:Javascript \
+ --summary \
+ "${1?missing OpenAPI document}" &>"$tmp"
+}
+
+function render() {
+ trap '
+ rm openapi.*.{json,yaml}(N) *.schema.json(N)
+ popd -q
+ ' EXIT
+ pushd -q "${1?missing directory argument}"
+ local v=${1:A:t}
+ local t=${1:A:h:h}/types/v1
+
+ schemalint "$t"
+ for f in ${t}/*.schema.json; do
+ local ex=examples/${${f:t}%.schema.json}.json
+ if [[ -f "$ex" ]]; then
+ jq --slurpfile ex "${ex}" 'setpath(["examples"]; $ex)' "$f" > "${f:t}"
+ else
+ cp "$f" .
+ fi
+ done
+
+ jq --null-input \
+ 'reduce (inputs|(.["$id"]|split("/")|.[-1]|rtrimstr(".schema.json")) as $k|{components:{schemas:{$k:.}}}) as $it({};. * $it)'\
+ *.schema.json >openapi.types.json
+
+
+ jq --null-input -L "${1:A:h}/lib" --from-file openapi.jq >openapi.frag.json
+ jq --null-input 'reduce inputs as $it({};. * $it)' openapi.{frag,types}.json >openapi.json
+
+ yq -pj eval . openapi.yaml
+ # Need some validator that actually works >:(
+
+ sha256sum openapi.json |
+ awk '{printf "\"%s\"", $1 >"openapi.etag" }'
+}
+
+# Process all the openapi generation scripts.
+for d in ${root}/httptransport/api/v*/openapi.jq(om); do
+ render "${d:h}"
+done
+
+# Generate documentation for the highest version.
+widdershins "${root}"/httptransport/api/v*/openapi.yaml(NnOn[1])
diff --git a/httptransport/api/v1/examples/bulk_delete.json b/httptransport/api/v1/examples/bulk_delete.json
new file mode 100644
index 0000000000..d8a817d301
--- /dev/null
+++ b/httptransport/api/v1/examples/bulk_delete.json
@@ -0,0 +1,3 @@
+[
+ "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3"
+]
diff --git a/httptransport/api/v1/examples/cpe.json b/httptransport/api/v1/examples/cpe.json
new file mode 100644
index 0000000000..c05fb5ab1d
--- /dev/null
+++ b/httptransport/api/v1/examples/cpe.json
@@ -0,0 +1,2 @@
+"cpe:/a:microsoft:internet_explorer:8.0.6001:beta"
+"cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"
diff --git a/httptransport/api/v1/examples/distribution.json b/httptransport/api/v1/examples/distribution.json
new file mode 100644
index 0000000000..19b1fd83a0
--- /dev/null
+++ b/httptransport/api/v1/examples/distribution.json
@@ -0,0 +1,9 @@
+{
+ "id": "1",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04",
+ "pretty_name": "Ubuntu 18.04.3 LTS"
+}
diff --git a/httptransport/api/v1/examples/environment.json b/httptransport/api/v1/examples/environment.json
new file mode 100644
index 0000000000..d55cdb1c9b
--- /dev/null
+++ b/httptransport/api/v1/examples/environment.json
@@ -0,0 +1,7 @@
+{
+ "value": {
+ "package_db": "var/lib/dpkg/status",
+ "introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
+ "distribution_id": "1"
+ }
+}
diff --git a/httptransport/api/v1/examples/manifest.json b/httptransport/api/v1/examples/manifest.json
new file mode 100644
index 0000000000..f2ed8f8f2a
--- /dev/null
+++ b/httptransport/api/v1/examples/manifest.json
@@ -0,0 +1,14 @@
+{
+ "hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
+ "layers": [
+ {
+ "hash": "sha256:2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
+ "uri": "https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
+ "headers": {
+ "Authoriztion": [
+ "Bearer hunter2"
+ ]
+ }
+ }
+ ]
+}
diff --git a/httptransport/api/v1/examples/notification_page.json b/httptransport/api/v1/examples/notification_page.json
new file mode 100644
index 0000000000..c90ebab9f0
--- /dev/null
+++ b/httptransport/api/v1/examples/notification_page.json
@@ -0,0 +1,43 @@
+{
+ "page": {
+ "size": 100,
+ "next": "1b4d0db2-e757-4150-bbbb-543658144205"
+ },
+ "notifications": [
+ {
+ "id": "5e4b387e-88d3-4364-86fd-063447a6fad2",
+ "manifest": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
+ "reason": "added",
+ "vulnerability": {
+ "name": "CVE-2009-5155",
+ "fixed_in_version": "v0.0.1",
+ "links": "http://example.com/CVE-2009-5155",
+ "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
+ "normalized_severity": "Unknown",
+ "package": {
+ "id": "10",
+ "name": "libapt-pkg5.0",
+ "version": "1.6.11",
+ "kind": "BINARY",
+ "arch": "x86",
+ "source": {
+ "id": "9",
+ "name": "apt",
+ "version": "1.6.11",
+ "kind": "SOURCE",
+ "source": null
+ }
+ },
+ "distribution": {
+ "id": "1",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04",
+ "pretty_name": "Ubuntu 18.04.3 LTS"
+ }
+ }
+ }
+ ]
+}
diff --git a/httptransport/api/v1/examples/package.json b/httptransport/api/v1/examples/package.json
new file mode 100644
index 0000000000..d86c65698b
--- /dev/null
+++ b/httptransport/api/v1/examples/package.json
@@ -0,0 +1,17 @@
+{
+ "id": "10",
+ "name": "libapt-pkg5.0",
+ "version": "1.6.11",
+ "kind": "binary",
+ "normalized_version": "",
+ "arch": "x86",
+ "module": "",
+ "cpe": "",
+ "source": {
+ "id": "9",
+ "name": "apt",
+ "version": "1.6.11",
+ "kind": "source",
+ "source": null
+ }
+}
diff --git a/httptransport/api/v1/examples/vulnerability.json b/httptransport/api/v1/examples/vulnerability.json
new file mode 100644
index 0000000000..92a0944aca
--- /dev/null
+++ b/httptransport/api/v1/examples/vulnerability.json
@@ -0,0 +1,31 @@
+{
+ "id": "356835",
+ "updater": "ubuntu",
+ "name": "CVE-2009-5155",
+ "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.",
+ "links": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-5155 http://people.canonical.com/~ubuntu-security/cve/2009/CVE-2009-5155.html https://sourceware.org/bugzilla/show_bug.cgi?id=11053 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22793 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32806 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34238 https://sourceware.org/bugzilla/show_bug.cgi?id=18986",
+ "severity": "Low",
+ "normalized_severity": "Low",
+ "package": {
+ "id": "0",
+ "name": "glibc",
+ "version": "2.27-0ubuntu1",
+ "kind": "binary",
+ "source": null
+ },
+ "dist": {
+ "id": "0",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04",
+ "arch": "amd64"
+ },
+ "repo": {
+ "id": "0",
+ "name": "Ubuntu 18.04.3 LTS"
+ },
+ "issued": "2019-10-12T07:20:50.52Z",
+ "fixed_in_version": "2.28-0ubuntu1"
+}
diff --git a/httptransport/api/v1/examples/vulnerability_summary.json b/httptransport/api/v1/examples/vulnerability_summary.json
new file mode 100644
index 0000000000..2f90e97b9b
--- /dev/null
+++ b/httptransport/api/v1/examples/vulnerability_summary.json
@@ -0,0 +1,24 @@
+{
+ "name": "CVE-2009-5155",
+ "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.",
+ "normalized_severity": "Low",
+ "fixed_in_version": "v0.0.1",
+ "links": "http://link-to-advisory",
+ "package": {
+ "id": "0",
+ "name": "glibc",
+ "version": "v0.0.1-rc1"
+ },
+ "dist": {
+ "id": "0",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04"
+ },
+ "repo": {
+ "id": "0",
+ "name": "Ubuntu 18.04.3 LTS"
+ }
+}
diff --git a/httptransport/api/v1/openapi.etag b/httptransport/api/v1/openapi.etag
new file mode 100644
index 0000000000..9a40d57fd9
--- /dev/null
+++ b/httptransport/api/v1/openapi.etag
@@ -0,0 +1 @@
+"a5d92768f73d630910e284bcbb0ba0a6ae37a2e9eaa3b93e23bf60d9f364991d"
\ No newline at end of file
diff --git a/httptransport/api/v1/openapi.jq b/httptransport/api/v1/openapi.jq
new file mode 100644
index 0000000000..e17f534b64
--- /dev/null
+++ b/httptransport/api/v1/openapi.jq
@@ -0,0 +1,437 @@
+# vim: set expandtab ts=2 sw=2:
+include "oapi";
+
+# Some helper functions:
+def example_ref($id): ref("examples/\($id).json"); # Files are local at build time.
+def responses($r):
+{
+ "200": {
+ description: "Success",
+ headers: {
+ "Clair-Error": header_ref("Clair-Error"),
+ },
+ },
+ "400": response_ref("bad_request"),
+ "415": response_ref("unsupported_media_type"),
+ default: response_ref("oops"),
+} * $r
+;
+
+# Some variables:
+"/notifier/api/v1" as $path_notif |
+"/matcher/api/v1" as $path_match |
+"/indexer/api/v1" as $path_index |
+
+# The OpenAPI object:
+{
+ openapi: "3.1.0",
+ info: {
+ title: "Clair Container Analyzer",
+ description: ([
+ "Clair is a set of cooperating microservices which can index and match a container image's content with known vulnerabilities.",
+ "",
+ "**Note:** Any endpoints tagged \"internal\" are documented for completeness but are considered exempt from versioning.",
+ ""] | join("\n") | sub("[[:space:]]*$"; "")),
+ version: "1.2.0",
+ contact: {
+ name: "Clair Team",
+ url: "http://github.com/quay/clair",
+ email: "quay-devel@redhat.com",
+ },
+ license: {
+ name: "Apache License 2.0",
+ url: "http://www.apache.org/licenses/",
+ }
+ },
+ externalDocs: {url: "https://quay.github.io/clair/"},
+ tags: [
+ { name: "indexer" },
+ { name: "matcher" },
+ { name: "notifier" },
+ { name: "internal" }
+ ],
+ paths: {
+ "\($path_notif)/notification/{id}": {
+ parameters: [ {
+ in: "path",
+ name: "id",
+ required: true,
+ schema: schema_ref("token"),
+ description: "A notification ID returned by a callback"
+ } ],
+ delete: {
+ operationId: "DeleteNotification",
+ responses: responses({"204": {description: "TODO"}}),
+ },
+ get: {
+ operationId: "GetNotification",
+ parameters: [
+ {
+ in: "query",
+ name: "page_size",
+ schema: {"type": "integer"},
+ description: "The maximum number of notifications to deliver in a single page."
+ },
+ {
+ in: "query",
+ name: "next",
+ schema: {"type": "string"},
+ description: "The next page to fetch via id. Typically this number is provided on initial response in the \"page.next\" field. The first request should omit this field."
+ }
+ ],
+ responses: responses({
+ "200": {
+ description: "A paginated list of notifications",
+ content: contenttype("notification_page"),
+ },
+ "304": {
+ description: "Not modified",
+ },
+ })
+ }
+ },
+ "\($path_index)/index_report": {
+ post: {
+ operationId: "Index",
+ requestBody: {
+ description: "Manifest to index.",
+ required: true,
+ content: contenttype("manifest"),
+ },
+ responses: (responses({
+ "201": {
+ description: "IndexReport created.\n\nClients may want to avoid reading the body if simply submitting the manifest for later vulnerability reporting.",
+ content: contenttype("index_report"),
+ headers: {
+ Location: header_ref("Location"),
+ Link: header_ref("Link"),
+ },
+ links: {
+ retrieve: {
+ operationId: "GetIndexReport",
+ parameters: {
+ digest: "$request.body#/hash"
+ },
+ },
+ delete: {
+ operationId: "DeleteManifest",
+ parameters: {
+ digest: "$request.body#/hash"
+ },
+ },
+ report: {
+ operationId: "GetVulnerabilityReport",
+ parameters: {
+ digest: "$request.body#/hash"
+ },
+ },
+ },
+ },
+ "412": {
+ description: "Precondition Failed",
+ },
+ }) | del(.["200"])),
+ },
+ delete: {
+ operationId: "DeleteManifests",
+ requestBody: {
+ description: "Array of manifest digests to delete.",
+ required: true,
+ content: contenttype("bulk_delete"),
+ },
+ responses: responses({
+ "200": {
+ description: "Successfully deleted manifests.",
+ content: contenttype("bulk_delete"),
+ },
+ }),
+ }
+ },
+ "\($path_index)/index_report/{digest}": {
+ delete: {
+ operationId: "DeleteManifest",
+ responses: (responses({"204": {
+ description: "Success",
+ }}) |
+ del(.["200"])),
+ },
+ get: {
+ operationId: "GetIndexReport",
+ responses: responses({
+ "200": {
+ description: "IndexReport retrieved",
+ content: contenttype("index_report"),
+ },
+ "404": response_ref("not_found"),
+ }),
+ },
+ parameters: [ param_ref("digest") ],
+ },
+ "\($path_index)/internal/affected_manifest": {
+ post: {
+ tags: ["internal"],
+ operationId: "AffectedManifests",
+ responses: responses({
+ "200": {
+ description: "TODO",
+ content: contenttype("affected_manifests"),
+ },
+ }),
+ },
+ },
+ "\($path_index)/index_state": {
+ get: {
+ operationId: "IndexState",
+ responses: {
+ "200": {
+ description: "Indexer State",
+ headers: {
+ Etag: header_ref("Etag"),
+ },
+ content: contenttype("index_state"),
+ },
+ "304": {
+ description: "Not Modified",
+ },
+ }
+ }
+ },
+ "\($path_match)/vulnerability_report/{digest}": {
+ get: {
+ operationId: "GetVulnerabilityReport",
+ responses: (responses({
+ "201": {
+ description: "Vulnerability Report Created",
+ content: contenttype("vulnerability_report"),
+ }
+ ,
+ "404": response_ref("not_found"),
+ }) | del(.["200"])),
+ },
+ parameters: [ param_ref("digest") ],
+ },
+ "\($path_match)/internal/update_operation": {
+ post: {
+ tags: ["internal"],
+ operationId: "UpdateOperation",
+ responses: responses({
+ "200": {
+ description: "TODO",
+ content: contenttype("affected_manifests"),
+ },
+ }),
+ },
+ },
+ "\($path_match)/internal/update_diff": {
+ get: {
+ tags: ["internal"],
+ operationId: "GetUpdateDiff",
+ responses: responses({
+ "200": {
+ description: "TODO",
+ content: contenttype("update_diff"),
+ },
+ }),
+ parameters: [
+ {
+ in: "query",
+ name: "cur",
+ schema: schema_ref("token"),
+ description: "TKTK"
+ },
+ {
+ in: "query",
+ name: "prev",
+ schema: schema_ref("token"),
+ description: "TKTK"
+ }
+ ],
+ },
+ },
+ },
+ security: [
+ #{},
+ #{"psk": []},
+ ],
+ webhooks: {
+ notification: {
+ post: {
+ tags: ["notifier"],
+ requestBody: {
+ content: contenttype("notification"),
+ },
+ responses: {
+ "200": {
+ description: "TODO",
+ },
+ },
+ },
+ },
+ },
+ components: {
+ schemas: {
+ # Anything here will get overwritten by standalone JSON Schema objects
+ # if the keys are duplicated.
+ #
+ # Generally, anything that goes in a response/request body should have a
+ # schema over in the types directory.
+ token: {
+ "type": "string",
+ description: "An opaque token previously obtained from the service.",
+ },
+ },
+ responses: {
+ bad_request: {
+ description: "Bad Request",
+ content: contenttype("error"),
+ },
+ oops: {
+ description: "Internal Server Error",
+ content: contenttype("error"),
+ },
+ not_found: {
+ description: "Not Found",
+ content: contenttype("error"),
+ },
+ # Not expressible in OpenAPI:
+ #method_not_allowed: {
+ # description: "Method Not Allowed",
+ # headers: {
+ # Allow: header_ref("Allow"),
+ # },
+ # content: contenttype("error"),
+ #},
+ unsupported_media_type: {
+ description: "Unsupported Media Type",
+ content: contenttype("error"),
+ },
+ },
+ parameters: {
+ digest: {
+ description: "OCI-compatible digest of a referred object.",
+ name: "digest",
+ in: "path",
+ schema: schema_ref("digest"),
+ required: true,
+ }
+ },
+ headers: {
+ # Only used for 415 Method Not Allowed responses, which aren't expressible in OpenAPI.
+ #Allow: {
+ # description: "TKTK",
+ # style: "simple",
+ # schema: { "type": "string" },
+ # required: true,
+ #},
+ "Clair-Error": {
+ description: "This is a trailer containing any errors encountered while writing the response.",
+ style: "simple",
+ schema: { "type": "string" },
+ },
+ Etag: {
+ description: "HTTP [ETag header](https://httpwg.org/specs/rfc9110.html#field.etag)",
+ style: "simple",
+ schema: {"type": "string"}
+ },
+ Link: {
+ description: "Web Linking [Link header](https://httpwg.org/specs/rfc8288.html#header)",
+ style: "simple",
+ schema: { "type": "string" },
+ },
+ Location: {
+ description: "HTTP [Location header](https://httpwg.org/specs/rfc9110.html#field.location)",
+ style: "simple",
+ required: true,
+ schema: { "type": "string" },
+ },
+ },
+ securitySchemes: {
+ psk: {
+ "type": "http",
+ scheme: "bearer",
+ bearerFormat: "JWT with preshared key and allow-listed issuers",
+ description: "Clair's authentication scheme.",
+ },
+ },
+ },
+}
+|
+# And now, a bunch of fixups:
+def add_tags: # Match the path prefixes and add default tags.
+ .paths |= with_entries(
+ (
+ if (.key|startswith($path_index)) then
+ "indexer"
+ elif (.key|startswith($path_match)) then
+ "matcher"
+ elif (.key|startswith($path_notif)) then
+ "notifier"
+ else
+ ""
+ end
+ ) as $k |
+ if ($k=="") then
+ .
+ else
+ (.value[]|select(objects)) |= . + {
+ tags: ((.tags//[]) + [$k]),
+ }
+ end
+ )
+;
+def operation_metadata: # Slipstream some metadata into response objects.
+ {
+ AffectedManifests: {
+ summary: "Retrieve the set of manifests affected by the provided vulnerabilities.",
+ description: "",
+ },
+ DeleteManifest: {
+ summary: "Delete the referenced manifest.",
+ description: "Given a Manifest's content addressable hash, any data related to it will be removed it it exists.",
+ },
+ DeleteManifests: {
+ summary: "Delete the referenced manifests.",
+ description: "Given a Manifest's content addressable hash, any data related to it will be removed if it exists.",
+ },
+ DeleteNotification: {
+ summary: "Delete the referenced notification set.",
+ description: "Issues a delete of the provided notification id and all associated notifications.\nAfter this delete clients will no longer be able to retrieve notifications.",
+ },
+ GetIndexReport: {
+ summary: "Retrieve the IndexReport for the referenced manifest.",
+ description: "Given a Manifest's content addressable hash, an IndexReport will be retrieved if it exists.",
+ },
+ GetNotification: {
+ summary: "Retrieve pages of the referenced notification set.",
+ description: "By performing a GET with an id as a path parameter, the client will retrieve a paginated response of notification objects.",
+ },
+ GetVulnerabilityReport: {
+ summary: "Retrieve a VulnerabilityReport for the referenced manifest.",
+ description: "Given a Manifest's content addressable hash a VulnerabilityReport will be created. The Manifest **must** have been Indexed first via the Index endpoint.",
+ },
+ Index: {
+ summary: "Index the contents of a Manifest",
+ description: "By submitting a Manifest object to this endpoint Clair will fetch the layers, scan each layer's contents, and provide an index of discovered packages, repository and distribution information.",
+ },
+ IndexState: {
+ summary: "Report the indexer's internal configuration and state.",
+ description: "The index state endpoint returns a json structure indicating the indexer's internal configuration state.\nA client may be interested in this as a signal that manifests may need to be re-indexed.",
+ },
+ } as $m |
+ ( .paths[][] | select(objects) ) |= (
+ .operationId as $id |
+ ($m[$id]?) as $m |
+ if ($m) then
+ . + $m
+ else
+ .
+ end
+ )
+;
+
+sort_paths |
+content_defaults |
+add_tags |
+operation_metadata |
+cli_hints |
+.
diff --git a/httptransport/api/v1/openapi.json b/httptransport/api/v1/openapi.json
new file mode 100644
index 0000000000..aaff862b89
--- /dev/null
+++ b/httptransport/api/v1/openapi.json
@@ -0,0 +1,1613 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "Clair Container Analyzer",
+ "description": "Clair is a set of cooperating microservices which can index and match a container image's content with known vulnerabilities.\n\n**Note:** Any endpoints tagged \"internal\" are documented for completeness but are considered exempt from versioning.",
+ "version": "1.2.0",
+ "contact": {
+ "name": "Clair Team",
+ "url": "http://github.com/quay/clair",
+ "email": "quay-devel@redhat.com"
+ },
+ "license": {
+ "name": "Apache License 2.0",
+ "url": "http://www.apache.org/licenses/"
+ }
+ },
+ "externalDocs": {
+ "url": "https://quay.github.io/clair/"
+ },
+ "tags": [
+ {
+ "name": "indexer"
+ },
+ {
+ "name": "matcher"
+ },
+ {
+ "name": "notifier"
+ },
+ {
+ "name": "internal"
+ }
+ ],
+ "paths": {
+ "/indexer/api/v1/index_report": {
+ "post": {
+ "operationId": "Index",
+ "requestBody": {
+ "description": "Manifest to index.",
+ "required": true,
+ "content": {
+ "application/vnd.clair.manifest.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/manifest"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/manifest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ },
+ "201": {
+ "description": "IndexReport created.\n\nClients may want to avoid reading the body if simply submitting the manifest for later vulnerability reporting.",
+ "content": {
+ "application/vnd.clair.index_report.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/index_report"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/index_report"
+ }
+ }
+ },
+ "headers": {
+ "Location": {
+ "$ref": "#/components/headers/Location"
+ },
+ "Link": {
+ "$ref": "#/components/headers/Link"
+ }
+ },
+ "links": {
+ "retrieve": {
+ "operationId": "GetIndexReport",
+ "parameters": {
+ "digest": "$request.body#/hash"
+ }
+ },
+ "delete": {
+ "operationId": "DeleteManifest",
+ "parameters": {
+ "digest": "$request.body#/hash"
+ }
+ },
+ "report": {
+ "operationId": "GetVulnerabilityReport",
+ "parameters": {
+ "digest": "$request.body#/hash"
+ }
+ }
+ }
+ },
+ "412": {
+ "description": "Precondition Failed"
+ }
+ },
+ "tags": [
+ "indexer"
+ ],
+ "summary": "Index the contents of a Manifest",
+ "description": "By submitting a Manifest object to this endpoint Clair will fetch the layers, scan each layer's contents, and provide an index of discovered packages, repository and distribution information."
+ },
+ "delete": {
+ "operationId": "DeleteManifests",
+ "requestBody": {
+ "description": "Array of manifest digests to delete.",
+ "required": true,
+ "content": {
+ "application/vnd.clair.bulk_delete.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/bulk_delete"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bulk_delete"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successfully deleted manifests.",
+ "headers": {
+ "Clair-Error": {
+ "$ref": "#/components/headers/Clair-Error"
+ }
+ },
+ "content": {
+ "application/vnd.clair.bulk_delete.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/bulk_delete"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/bulk_delete"
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ }
+ },
+ "tags": [
+ "indexer"
+ ],
+ "summary": "Delete the referenced manifests.",
+ "description": "Given a Manifest's content addressable hash, any data related to it will be removed if it exists."
+ }
+ },
+ "/indexer/api/v1/index_report/{digest}": {
+ "delete": {
+ "operationId": "DeleteManifest",
+ "responses": {
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ },
+ "204": {
+ "description": "Success"
+ }
+ },
+ "tags": [
+ "indexer"
+ ],
+ "summary": "Delete the referenced manifest.",
+ "description": "Given a Manifest's content addressable hash, any data related to it will be removed it it exists."
+ },
+ "get": {
+ "operationId": "GetIndexReport",
+ "responses": {
+ "200": {
+ "description": "IndexReport retrieved",
+ "headers": {
+ "Clair-Error": {
+ "$ref": "#/components/headers/Clair-Error"
+ }
+ },
+ "content": {
+ "application/vnd.clair.index_report.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/index_report"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/index_report"
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ },
+ "404": {
+ "$ref": "#/components/responses/not_found"
+ }
+ },
+ "tags": [
+ "indexer"
+ ],
+ "summary": "Retrieve the IndexReport for the referenced manifest.",
+ "description": "Given a Manifest's content addressable hash, an IndexReport will be retrieved if it exists."
+ },
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/digest"
+ }
+ ]
+ },
+ "/indexer/api/v1/index_state": {
+ "get": {
+ "operationId": "IndexState",
+ "responses": {
+ "200": {
+ "description": "Indexer State",
+ "headers": {
+ "Etag": {
+ "$ref": "#/components/headers/Etag"
+ }
+ },
+ "content": {
+ "application/vnd.clair.index_state.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/index_state"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/index_state"
+ }
+ }
+ }
+ },
+ "304": {
+ "description": "Not Modified"
+ }
+ },
+ "tags": [
+ "indexer"
+ ],
+ "summary": "Report the indexer's internal configuration and state.",
+ "description": "The index state endpoint returns a json structure indicating the indexer's internal configuration state.\nA client may be interested in this as a signal that manifests may need to be re-indexed."
+ }
+ },
+ "/indexer/api/v1/internal/affected_manifest": {
+ "post": {
+ "tags": [
+ "internal",
+ "indexer"
+ ],
+ "operationId": "AffectedManifests",
+ "responses": {
+ "200": {
+ "description": "TODO",
+ "headers": {
+ "Clair-Error": {
+ "$ref": "#/components/headers/Clair-Error"
+ }
+ },
+ "content": {
+ "application/vnd.clair.affected_manifests.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/affected_manifests"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/affected_manifests"
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ }
+ },
+ "summary": "Retrieve the set of manifests affected by the provided vulnerabilities.",
+ "description": "",
+ "x-cli-ignore": true
+ }
+ },
+ "/matcher/api/v1/internal/update_diff": {
+ "get": {
+ "tags": [
+ "internal",
+ "matcher"
+ ],
+ "operationId": "GetUpdateDiff",
+ "responses": {
+ "200": {
+ "description": "TODO",
+ "headers": {
+ "Clair-Error": {
+ "$ref": "#/components/headers/Clair-Error"
+ }
+ },
+ "content": {
+ "application/vnd.clair.update_diff.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/update_diff"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/update_diff"
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ }
+ },
+ "parameters": [
+ {
+ "in": "query",
+ "name": "cur",
+ "schema": {
+ "$ref": "#/components/schemas/token"
+ },
+ "description": "TKTK"
+ },
+ {
+ "in": "query",
+ "name": "prev",
+ "schema": {
+ "$ref": "#/components/schemas/token"
+ },
+ "description": "TKTK"
+ }
+ ],
+ "x-cli-ignore": true
+ }
+ },
+ "/matcher/api/v1/internal/update_operation": {
+ "post": {
+ "tags": [
+ "internal",
+ "matcher"
+ ],
+ "operationId": "UpdateOperation",
+ "responses": {
+ "200": {
+ "description": "TODO",
+ "headers": {
+ "Clair-Error": {
+ "$ref": "#/components/headers/Clair-Error"
+ }
+ },
+ "content": {
+ "application/vnd.clair.affected_manifests.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/affected_manifests"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/affected_manifests"
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ }
+ },
+ "x-cli-ignore": true
+ }
+ },
+ "/matcher/api/v1/vulnerability_report/{digest}": {
+ "get": {
+ "operationId": "GetVulnerabilityReport",
+ "responses": {
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ },
+ "201": {
+ "description": "Vulnerability Report Created",
+ "content": {
+ "application/vnd.clair.vulnerability_report.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/vulnerability_report"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/vulnerability_report"
+ }
+ }
+ }
+ },
+ "404": {
+ "$ref": "#/components/responses/not_found"
+ }
+ },
+ "tags": [
+ "matcher"
+ ],
+ "summary": "Retrieve a VulnerabilityReport for the referenced manifest.",
+ "description": "Given a Manifest's content addressable hash a VulnerabilityReport will be created. The Manifest **must** have been Indexed first via the Index endpoint."
+ },
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/digest"
+ }
+ ]
+ },
+ "/notifier/api/v1/notification/{id}": {
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/token"
+ },
+ "description": "A notification ID returned by a callback"
+ }
+ ],
+ "delete": {
+ "operationId": "DeleteNotification",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "headers": {
+ "Clair-Error": {
+ "$ref": "#/components/headers/Clair-Error"
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ },
+ "204": {
+ "description": "TODO"
+ }
+ },
+ "tags": [
+ "notifier"
+ ],
+ "summary": "Delete the referenced notification set.",
+ "description": "Issues a delete of the provided notification id and all associated notifications.\nAfter this delete clients will no longer be able to retrieve notifications."
+ },
+ "get": {
+ "operationId": "GetNotification",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "page_size",
+ "schema": {
+ "type": "integer"
+ },
+ "description": "The maximum number of notifications to deliver in a single page."
+ },
+ {
+ "in": "query",
+ "name": "next",
+ "schema": {
+ "type": "string"
+ },
+ "description": "The next page to fetch via id. Typically this number is provided on initial response in the \"page.next\" field. The first request should omit this field."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "A paginated list of notifications",
+ "headers": {
+ "Clair-Error": {
+ "$ref": "#/components/headers/Clair-Error"
+ }
+ },
+ "content": {
+ "application/vnd.clair.notification_page.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/notification_page"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/notification_page"
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/bad_request"
+ },
+ "415": {
+ "$ref": "#/components/responses/unsupported_media_type"
+ },
+ "default": {
+ "$ref": "#/components/responses/oops"
+ },
+ "304": {
+ "description": "Not modified"
+ }
+ },
+ "tags": [
+ "notifier"
+ ],
+ "summary": "Retrieve pages of the referenced notification set.",
+ "description": "By performing a GET with an id as a path parameter, the client will retrieve a paginated response of notification objects."
+ }
+ }
+ },
+ "security": [],
+ "webhooks": {
+ "notification": {
+ "post": {
+ "tags": [
+ "notifier"
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.clair.notification.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/notification"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "TODO"
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "token": {
+ "type": "string",
+ "description": "An opaque token previously obtained from the service."
+ },
+ "affected_manifests": {
+ "$id": "https://clairproject.org/api/http/v1/affected_manifests.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Affected Manifests",
+ "type": "object",
+ "description": "**This is an internal type, documented for completeness.**\n\nManifests affected by the specified vulnerability objects.",
+ "properties": {
+ "vulnerabilities": {
+ "type": "object",
+ "description": "Vulnerability objects.",
+ "additionalProperties": {
+ "$ref": "vulnerability.schema.json"
+ }
+ },
+ "vulnerable_manifests": {
+ "type": "object",
+ "description": "Mapping of manifest digests to vulnerability identifiers.",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "description": "An identifier to be used in the \"#/vulnerabilities\" object."
+ }
+ }
+ }
+ },
+ "required": [
+ "vulnerable_manifests"
+ ]
+ },
+ "bulk_delete": {
+ "$id": "https://clairproject.org/api/http/v1/bulk_delete.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Bulk Delete",
+ "type": "array",
+ "description": "Array of manifest digests to delete from the system.",
+ "items": {
+ "$ref": "digest.schema.json",
+ "description": "Manifest digest to delete from the system."
+ },
+ "examples": [
+ [
+ "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3"
+ ]
+ ]
+ },
+ "cpe": {
+ "$id": "https://clairproject.org/api/http/v1/cpe.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Common Platform Enumeration Name",
+ "description": "This is a CPE Name in either v2.2 \"URI\" form or v2.3 \"Formatted String\" form.",
+ "$comment": "Clair only produces v2.3 CPE Names. Any v2.2 Names will be normalized into v2.3 form.",
+ "oneOf": [
+ {
+ "description": "This is the CPE 2.2 regexp: https://cpe.mitre.org/specification/2.2/cpe-language_2.2.xsd",
+ "type": "string",
+ "pattern": "^[c][pP][eE]:/[AHOaho]?(:[A-Za-z0-9\\._\\-~%]*){0,6}$"
+ },
+ {
+ "description": "This is the CPE 2.3 regexp: https://csrc.nist.gov/schema/cpe/2.3/cpe-naming_2.3.xsd",
+ "type": "string",
+ "pattern": "^cpe:2\\.3:[aho\\*\\-](:(((\\?*|\\*?)([a-zA-Z0-9\\-\\._]|(\\\\[\\\\\\*\\?!\"#$$%&'\\(\\)\\+,/:;<=>@\\[\\]\\^`\\{\\|}~]))+(\\?*|\\*?))|[\\*\\-])){5}(:(([a-zA-Z]{2,3}(-([a-zA-Z]{2}|[0-9]{3}))?)|[\\*\\-]))(:(((\\?*|\\*?)([a-zA-Z0-9\\-\\._]|(\\\\[\\\\\\*\\?!\"#$$%&'\\(\\)\\+,/:;<=>@\\[\\]\\^`\\{\\|}~]))+(\\?*|\\*?))|[\\*\\-])){4}$"
+ }
+ ],
+ "examples": [
+ "cpe:/a:microsoft:internet_explorer:8.0.6001:beta",
+ "cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"
+ ]
+ },
+ "digest": {
+ "$id": "https://clairproject.org/api/http/v1/digest.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Digest",
+ "description": "A digest acts as a content identifier, enabling content addressability.",
+ "oneOf": [
+ {
+ "$comment": "SHA256: MUST be implemented",
+ "description": "SHA256",
+ "type": "string",
+ "pattern": "^sha256:[a-f0-9]{64}$"
+ },
+ {
+ "$comment": "SHA512: MAY be implemented",
+ "description": "SHA512",
+ "type": "string",
+ "pattern": "^sha512:[a-f0-9]{128}$"
+ },
+ {
+ "$comment": "BLAKE3: MAY be implemented",
+ "description": "BLAKE3\n\n**Currently not implemented.**",
+ "type": "string",
+ "pattern": "^blake3:[a-f0-9]{64}$"
+ }
+ ]
+ },
+ "distribution": {
+ "$id": "https://clairproject.org/api/http/v1/distribution.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Distribution",
+ "type": "object",
+ "description": "Distribution is the accompanying system context of a Package.",
+ "properties": {
+ "id": {
+ "description": "Unique ID for this Distribution. May be unique to the response document, not the whole system.",
+ "type": "string"
+ },
+ "did": {
+ "description": "A lower-case string (no spaces or other characters outside of 0–9, a–z, \".\", \"_\", and \"-\") identifying the operating system, excluding any version information and suitable for processing by scripts or usage in generated filenames.",
+ "type": "string"
+ },
+ "name": {
+ "description": "A string identifying the operating system.",
+ "type": "string"
+ },
+ "version": {
+ "description": "A string identifying the operating system version, excluding any OS name information, possibly including a release code name, and suitable for presentation to the user.",
+ "type": "string"
+ },
+ "version_code_name": {
+ "description": "A lower-case string (no spaces or other characters outside of 0–9, a–z, \".\", \"_\", and \"-\") identifying the operating system release code name, excluding any OS name information or release version, and suitable for processing by scripts or usage in generated filenames.",
+ "type": "string"
+ },
+ "version_id": {
+ "description": "A lower-case string (mostly numeric, no spaces or other characters outside of 0–9, a–z, \".\", \"_\", and \"-\") identifying the operating system version, excluding any OS name information or release code name.",
+ "type": "string"
+ },
+ "arch": {
+ "description": "A string identifying the OS architecture.",
+ "type": "string"
+ },
+ "cpe": {
+ "description": "Common Platform Enumeration name.",
+ "$ref": "cpe.schema.json"
+ },
+ "pretty_name": {
+ "description": "A pretty operating system name in a format suitable for presentation to the user.",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "id"
+ ],
+ "examples": [
+ {
+ "id": "1",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04",
+ "pretty_name": "Ubuntu 18.04.3 LTS"
+ }
+ ]
+ },
+ "environment": {
+ "$id": "https://clairproject.org/api/http/v1/environment.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Environment",
+ "type": "object",
+ "description": "Environment describes the surrounding environment a package was discovered in.",
+ "properties": {
+ "package_db": {
+ "description": "The database the associated Package was discovered in.",
+ "type": "string"
+ },
+ "distribution_id": {
+ "description": "The ID of the Distribution of the associated Package.",
+ "type": "string"
+ },
+ "introduced_in": {
+ "description": "The Layer the associated Package was introduced in.",
+ "$ref": "digest.schema.json"
+ },
+ "repository_ids": {
+ "description": "The IDs of the Repositories of the associated Package.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "examples": [
+ {
+ "value": {
+ "package_db": "var/lib/dpkg/status",
+ "introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
+ "distribution_id": "1"
+ }
+ }
+ ]
+ },
+ "error": {
+ "$id": "https://clairproject.org/api/http/v1/error.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Error",
+ "type": "object",
+ "description": "A general error response.",
+ "properties": {
+ "code": {
+ "type": "string",
+ "description": "a code for this particular error"
+ },
+ "message": {
+ "type": "string",
+ "description": "a message with further detail"
+ }
+ },
+ "required": [
+ "message"
+ ]
+ },
+ "index_report": {
+ "$id": "https://clairproject.org/api/http/v1/index_report.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Index Report",
+ "type": "object",
+ "description": "An index of the contents of a Manifest.",
+ "properties": {
+ "manifest_hash": {
+ "$ref": "digest.schema.json",
+ "description": "The Manifest's digest."
+ },
+ "state": {
+ "type": "string",
+ "description": "The current state of the index operation"
+ },
+ "err": {
+ "type": "string",
+ "description": "An error message on event of unsuccessful index"
+ },
+ "success": {
+ "type": "boolean",
+ "description": "A bool indicating succcessful index"
+ },
+ "packages": {
+ "type": "object",
+ "description": "A map of Package objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "package.schema.json"
+ }
+ },
+ "distributions": {
+ "type": "object",
+ "description": "A map of Distribution objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "distribution.schema.json"
+ }
+ },
+ "repository": {
+ "type": "object",
+ "description": "A map of Repository objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "repository.schema.json"
+ }
+ },
+ "environments": {
+ "type": "object",
+ "description": "A map of Environment arrays indexed by a Package's identifier.",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "$ref": "environment.schema.json"
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "manifest_hash",
+ "state",
+ "success"
+ ]
+ },
+ "index_state": {
+ "$id": "https://clairproject.org/api/http/v1/index_state.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Index State",
+ "type": "object",
+ "description": "Information on the state of the indexer system.",
+ "properties": {
+ "state": {
+ "type": "string",
+ "description": "an opaque token"
+ }
+ },
+ "required": [
+ "state"
+ ]
+ },
+ "layer": {
+ "$id": "https://clairproject.org/api/http/v1/layer.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Layer",
+ "type": "object",
+ "description": "Layer is a description of a container layer. It should contain enough information to fetch the layer.",
+ "properties": {
+ "hash": {
+ "$ref": "digest.schema.json",
+ "description": "Digest of the layer blob."
+ },
+ "uri": {
+ "type": "string",
+ "description": "A URI indicating where the layer blob can be downloaded from."
+ },
+ "headers": {
+ "description": "Any additional HTTP-style headers needed for requesting layers.",
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\-_]+$": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "media_type": {
+ "description": "The OCI Layer media type for this layer.",
+ "type": "string",
+ "pattern": "^application/vnd\\.oci\\.image\\.layer\\.v1\\.tar(\\+(gzip|zstd))?$"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "hash",
+ "uri"
+ ]
+ },
+ "manifest": {
+ "$id": "https://clairproject.org/api/http/v1/manifest.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Manifest",
+ "type": "object",
+ "description": "A description of an OCI Image Manifest.",
+ "properties": {
+ "hash": {
+ "$ref": "digest.schema.json",
+ "description": "The OCI Image Manifest's digest.\n\nThis is used as an identifier throughout the system. This **SHOULD** be the same as the OCI Image Manifest's digest, but this is not enforced."
+ },
+ "layers": {
+ "type": "array",
+ "description": "The OCI Layers making up the Image, in order.",
+ "items": {
+ "$ref": "layer.schema.json"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "hash"
+ ],
+ "examples": [
+ {
+ "hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
+ "layers": [
+ {
+ "hash": "sha256:2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
+ "uri": "https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
+ "headers": {
+ "Authoriztion": [
+ "Bearer hunter2"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "normalized_severity": {
+ "$id": "https://clairproject.org/api/http/v1/normalized_severity.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Normalized Severity",
+ "description": "Standardized severity values.",
+ "enum": [
+ "Unknown",
+ "Negligible",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "notification_page": {
+ "$id": "https://clairproject.org/api/http/v1/notification_page.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Notification Page",
+ "type": "object",
+ "description": "A page description and list of notifications.",
+ "properties": {
+ "page": {
+ "description": "An object informing the client the next page to retrieve.",
+ "type": "object",
+ "properties": {
+ "size": {
+ "type": "integer"
+ },
+ "next": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "const": "-1"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "size"
+ ]
+ },
+ "notifications": {
+ "description": "Notifications within this page.",
+ "type": "array",
+ "items": {
+ "$ref": "notification.schema.json"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "page",
+ "notifications"
+ ],
+ "examples": [
+ {
+ "page": {
+ "size": 100,
+ "next": "1b4d0db2-e757-4150-bbbb-543658144205"
+ },
+ "notifications": [
+ {
+ "id": "5e4b387e-88d3-4364-86fd-063447a6fad2",
+ "manifest": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
+ "reason": "added",
+ "vulnerability": {
+ "name": "CVE-2009-5155",
+ "fixed_in_version": "v0.0.1",
+ "links": "http://example.com/CVE-2009-5155",
+ "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"",
+ "normalized_severity": "Unknown",
+ "package": {
+ "id": "10",
+ "name": "libapt-pkg5.0",
+ "version": "1.6.11",
+ "kind": "BINARY",
+ "arch": "x86",
+ "source": {
+ "id": "9",
+ "name": "apt",
+ "version": "1.6.11",
+ "kind": "SOURCE",
+ "source": null
+ }
+ },
+ "distribution": {
+ "id": "1",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04",
+ "pretty_name": "Ubuntu 18.04.3 LTS"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "notification": {
+ "$id": "https://clairproject.org/api/http/v1/notification.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Notification",
+ "type": "object",
+ "description": "A change in a manifest affected by a vulnerability.",
+ "properties": {
+ "id": {
+ "description": "Unique identifier for this notification.",
+ "type": "string"
+ },
+ "manifest": {
+ "$ref": "digest.schema.json",
+ "description": "The digest of the manifest affected by the provided vulnerability."
+ },
+ "reason": {
+ "description": "The reason for the notifcation.",
+ "enum": [
+ "added",
+ "removed"
+ ]
+ },
+ "vulnerability": {
+ "$ref": "vulnerability_summary.schema.json"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "manifest",
+ "reason",
+ "vulnerability"
+ ]
+ },
+ "package": {
+ "$id": "https://clairproject.org/api/http/v1/package.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Package",
+ "type": "object",
+ "description": "Description of installed software.",
+ "properties": {
+ "id": {
+ "description": "Unique ID for this Package. May be unique to the response document, not the whole system.",
+ "type": "string"
+ },
+ "name": {
+ "description": "Identifier of this Package.\n\nThe uniqueness and scoping of this name depends on the packaging system.",
+ "type": "string"
+ },
+ "version": {
+ "description": "Version of this Package, as reported by the packaging system.",
+ "type": "string"
+ },
+ "kind": {
+ "description": "The \"kind\" of this Package.",
+ "enum": [
+ "BINARY",
+ "SOURCE"
+ ],
+ "default": "BINARY"
+ },
+ "source": {
+ "$ref": "#",
+ "description": "Source Package that produced the current binary Package, if known."
+ },
+ "normalized_version": {
+ "description": "Normalized representation of the discoverd version.\n\nThe format is not specific, but is guarenteed to be forward compatible.",
+ "type": "string"
+ },
+ "module": {
+ "description": "An identifier for intra-Repository grouping of packages.\n\nLikely only relevant on rpm-based systems.",
+ "type": "string"
+ },
+ "arch": {
+ "description": "Native architecture for the Package.",
+ "type": "string",
+ "$comment": "This should become and enum in the future."
+ },
+ "cpe": {
+ "$ref": "cpe.schema.json",
+ "description": "CPE Name for the Package."
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "name",
+ "version"
+ ],
+ "examples": [
+ {
+ "id": "10",
+ "name": "libapt-pkg5.0",
+ "version": "1.6.11",
+ "kind": "binary",
+ "normalized_version": "",
+ "arch": "x86",
+ "module": "",
+ "cpe": "",
+ "source": {
+ "id": "9",
+ "name": "apt",
+ "version": "1.6.11",
+ "kind": "source",
+ "source": null
+ }
+ }
+ ]
+ },
+ "range": {
+ "$id": "https://clairproject.org/api/http/v1/range.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Range",
+ "type": "object",
+ "description": "A range of versions.",
+ "properties": {
+ "[": {
+ "type": "string",
+ "description": "Lower bound, inclusive."
+ },
+ ")": {
+ "type": "string",
+ "description": "Upper bound, exclusive."
+ }
+ },
+ "minProperties": 1,
+ "additionalProperties": false
+ },
+ "repository": {
+ "$id": "https://clairproject.org/api/http/v1/repository.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Repository",
+ "type": "object",
+ "description": "Description of a software repository",
+ "properties": {
+ "id": {
+ "description": "Unique ID for this Repository. May be unique to the response document, not the whole system.",
+ "type": "string"
+ },
+ "name": {
+ "description": "Human-relevant name for the Repository.",
+ "type": "string"
+ },
+ "key": {
+ "description": "Machine-relevant name for the Repository.",
+ "type": "string"
+ },
+ "uri": {
+ "description": "URI describing the Repository.",
+ "type": "string",
+ "format": "uri"
+ },
+ "cpe": {
+ "description": "CPE name for the Repository.",
+ "$ref": "cpe.schema.json"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "id"
+ ]
+ },
+ "update_diff": {
+ "$id": "https://clairproject.org/api/http/v1/update_diff.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Update Difference",
+ "type": "object",
+ "description": "**This is an internal type, documented for completeness.**\n\nTKTK",
+ "additionalProperties": false,
+ "required": []
+ },
+ "vulnerability_core": {
+ "$id": "https://clairproject.org/api/http/v1/vulnerability_core.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Vulnerability Core",
+ "type": "object",
+ "description": "The core elements of vulnerabilities in the Clair system.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Human-readable name, as presented in the vendor data."
+ },
+ "fixed_in_version": {
+ "type": "string",
+ "description": "Version string, as presented in the vendor data."
+ },
+ "severity": {
+ "type": "string",
+ "description": "Severity, as presented in the vendor data."
+ },
+ "normalized_severity": {
+ "$ref": "normalized_severity.schema.json",
+ "description": "A well defined set of severity strings guaranteed to be present."
+ },
+ "range": {
+ "$ref": "range.schema.json",
+ "description": "Range of versions the vulnerability applies to."
+ },
+ "arch_op": {
+ "description": "Flag indicating how the referenced package's \"arch\" member should be interpreted.",
+ "enum": [
+ "equals",
+ "not equals",
+ "pattern match"
+ ]
+ },
+ "package": {
+ "$ref": "package.schema.json",
+ "description": "A package description"
+ },
+ "distribution": {
+ "$ref": "distribution.schema.json",
+ "description": "A distribution description"
+ },
+ "repository": {
+ "$ref": "repository.schema.json",
+ "description": "A repository description"
+ }
+ },
+ "required": [
+ "name",
+ "normalized_severity"
+ ],
+ "dependentRequired": {
+ "package": [
+ "arch_op"
+ ]
+ },
+ "anyOf": [
+ {
+ "required": [
+ "package"
+ ]
+ },
+ {
+ "required": [
+ "repository"
+ ]
+ },
+ {
+ "required": [
+ "distribution"
+ ]
+ }
+ ]
+ },
+ "vulnerability_report": {
+ "$id": "https://clairproject.org/api/http/v1/vulnerability_report.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Vulnerability Report",
+ "type": "object",
+ "description": "A report with discovered packages, package environments, and package vulnerabilities within a Manifest.",
+ "properties": {
+ "manifest_hash": {
+ "$ref": "digest.schema.json",
+ "description": "The Manifest's digest."
+ },
+ "packages": {
+ "type": "object",
+ "description": "A map of Package objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "package.schema.json"
+ }
+ },
+ "distributions": {
+ "type": "object",
+ "description": "A map of Distribution objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "distribution.schema.json"
+ }
+ },
+ "repository": {
+ "type": "object",
+ "description": "A map of Repository objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "repository.schema.json"
+ }
+ },
+ "environments": {
+ "type": "object",
+ "description": "A map of Environment arrays indexed by a Package's identifier.",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "$ref": "environment.schema.json"
+ }
+ }
+ },
+ "vulnerabilities": {
+ "type": "object",
+ "description": "A map of Vulnerabilities indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "vulnerability.schema.json"
+ }
+ },
+ "package_vulnerabilities": {
+ "type": "object",
+ "description": "A mapping of Vulnerability identifier lists indexed by Package identifier.",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "enrichments": {
+ "type": "object",
+ "description": "A mapping of extra \"enrichment\" data by type",
+ "additionalProperties": {
+ "type": "array"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "distributions",
+ "environments",
+ "manifest_hash",
+ "packages",
+ "package_vulnerabilities",
+ "vulnerabilities"
+ ]
+ },
+ "vulnerability": {
+ "$id": "https://clairproject.org/api/http/v1/vulnerability.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Vulnerability",
+ "type": "object",
+ "description": "Description of a software flaw.",
+ "$ref": "vulnerability_core.schema.json",
+ "properties": {
+ "id": {
+ "description": "",
+ "type": "string"
+ },
+ "updater": {
+ "description": "",
+ "type": "string"
+ },
+ "description": {
+ "description": "",
+ "type": "string"
+ },
+ "issued": {
+ "description": "",
+ "type": "string",
+ "format": "date-time"
+ },
+ "links": {
+ "description": "",
+ "type": "string"
+ }
+ },
+ "unevaluatedProperties": false,
+ "required": [
+ "id",
+ "updater"
+ ],
+ "examples": [
+ {
+ "id": "356835",
+ "updater": "ubuntu",
+ "name": "CVE-2009-5155",
+ "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.",
+ "links": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-5155 http://people.canonical.com/~ubuntu-security/cve/2009/CVE-2009-5155.html https://sourceware.org/bugzilla/show_bug.cgi?id=11053 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22793 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32806 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34238 https://sourceware.org/bugzilla/show_bug.cgi?id=18986",
+ "severity": "Low",
+ "normalized_severity": "Low",
+ "package": {
+ "id": "0",
+ "name": "glibc",
+ "version": "2.27-0ubuntu1",
+ "kind": "binary",
+ "source": null
+ },
+ "dist": {
+ "id": "0",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04",
+ "arch": "amd64"
+ },
+ "repo": {
+ "id": "0",
+ "name": "Ubuntu 18.04.3 LTS"
+ },
+ "issued": "2019-10-12T07:20:50.52Z",
+ "fixed_in_version": "2.28-0ubuntu1"
+ }
+ ]
+ },
+ "vulnerability_summary": {
+ "$id": "https://clairproject.org/api/http/v1/vulnerability_summary.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Vulnerability Summary",
+ "type": "object",
+ "description": "A summary of a vulnerability.",
+ "$ref": "vulnerability_core.schema.json",
+ "unevaluatedProperties": false,
+ "examples": [
+ {
+ "name": "CVE-2009-5155",
+ "description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.",
+ "normalized_severity": "Low",
+ "fixed_in_version": "v0.0.1",
+ "links": "http://link-to-advisory",
+ "package": {
+ "id": "0",
+ "name": "glibc",
+ "version": "v0.0.1-rc1"
+ },
+ "dist": {
+ "id": "0",
+ "did": "ubuntu",
+ "name": "Ubuntu",
+ "version": "18.04.3 LTS (Bionic Beaver)",
+ "version_code_name": "bionic",
+ "version_id": "18.04"
+ },
+ "repo": {
+ "id": "0",
+ "name": "Ubuntu 18.04.3 LTS"
+ }
+ }
+ ]
+ }
+ },
+ "responses": {
+ "bad_request": {
+ "description": "Bad Request",
+ "content": {
+ "application/vnd.clair.error.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ },
+ "oops": {
+ "description": "Internal Server Error",
+ "content": {
+ "application/vnd.clair.error.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ },
+ "not_found": {
+ "description": "Not Found",
+ "content": {
+ "application/vnd.clair.error.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ },
+ "unsupported_media_type": {
+ "description": "Unsupported Media Type",
+ "content": {
+ "application/vnd.clair.error.v1+json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/error"
+ }
+ }
+ }
+ }
+ },
+ "parameters": {
+ "digest": {
+ "description": "OCI-compatible digest of a referred object.",
+ "name": "digest",
+ "in": "path",
+ "schema": {
+ "$ref": "#/components/schemas/digest"
+ },
+ "required": true
+ }
+ },
+ "headers": {
+ "Clair-Error": {
+ "description": "This is a trailer containing any errors encountered while writing the response.",
+ "style": "simple",
+ "schema": {
+ "type": "string"
+ }
+ },
+ "Etag": {
+ "description": "HTTP [ETag header](https://httpwg.org/specs/rfc9110.html#field.etag)",
+ "style": "simple",
+ "schema": {
+ "type": "string"
+ }
+ },
+ "Link": {
+ "description": "Web Linking [Link header](https://httpwg.org/specs/rfc8288.html#header)",
+ "style": "simple",
+ "schema": {
+ "type": "string"
+ }
+ },
+ "Location": {
+ "description": "HTTP [Location header](https://httpwg.org/specs/rfc9110.html#field.location)",
+ "style": "simple",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
+ "securitySchemes": {
+ "psk": {
+ "type": "http",
+ "scheme": "bearer",
+ "bearerFormat": "JWT with preshared key and allow-listed issuers",
+ "description": "Clair's authentication scheme."
+ }
+ }
+ }
+}
diff --git a/httptransport/api/v1/openapi.yaml b/httptransport/api/v1/openapi.yaml
new file mode 100644
index 0000000000..364f52422b
--- /dev/null
+++ b/httptransport/api/v1/openapi.yaml
@@ -0,0 +1,1146 @@
+openapi: 3.1.0
+info:
+ title: Clair Container Analyzer
+ description: |-
+ Clair is a set of cooperating microservices which can index and match a container image's content with known vulnerabilities.
+
+ **Note:** Any endpoints tagged "internal" are documented for completeness but are considered exempt from versioning.
+ version: 1.2.0
+ contact:
+ name: Clair Team
+ url: http://github.com/quay/clair
+ email: quay-devel@redhat.com
+ license:
+ name: Apache License 2.0
+ url: http://www.apache.org/licenses/
+externalDocs:
+ url: https://quay.github.io/clair/
+tags:
+ - name: indexer
+ - name: matcher
+ - name: notifier
+ - name: internal
+paths:
+ /indexer/api/v1/index_report:
+ post:
+ operationId: Index
+ requestBody:
+ description: Manifest to index.
+ required: true
+ content:
+ application/vnd.clair.manifest.v1+json:
+ schema:
+ $ref: '#/components/schemas/manifest'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/manifest'
+ responses:
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ "201":
+ description: |-
+ IndexReport created.
+
+ Clients may want to avoid reading the body if simply submitting the manifest for later vulnerability reporting.
+ content:
+ application/vnd.clair.index_report.v1+json:
+ schema:
+ $ref: '#/components/schemas/index_report'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/index_report'
+ headers:
+ Location:
+ $ref: '#/components/headers/Location'
+ Link:
+ $ref: '#/components/headers/Link'
+ links:
+ retrieve:
+ operationId: GetIndexReport
+ parameters:
+ digest: $request.body#/hash
+ delete:
+ operationId: DeleteManifest
+ parameters:
+ digest: $request.body#/hash
+ report:
+ operationId: GetVulnerabilityReport
+ parameters:
+ digest: $request.body#/hash
+ "412":
+ description: Precondition Failed
+ tags:
+ - indexer
+ summary: Index the contents of a Manifest
+ description: By submitting a Manifest object to this endpoint Clair will fetch the layers, scan each layer's contents, and provide an index of discovered packages, repository and distribution information.
+ delete:
+ operationId: DeleteManifests
+ requestBody:
+ description: Array of manifest digests to delete.
+ required: true
+ content:
+ application/vnd.clair.bulk_delete.v1+json:
+ schema:
+ $ref: '#/components/schemas/bulk_delete'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bulk_delete'
+ responses:
+ "200":
+ description: Successfully deleted manifests.
+ headers:
+ Clair-Error:
+ $ref: '#/components/headers/Clair-Error'
+ content:
+ application/vnd.clair.bulk_delete.v1+json:
+ schema:
+ $ref: '#/components/schemas/bulk_delete'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/bulk_delete'
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ tags:
+ - indexer
+ summary: Delete the referenced manifests.
+ description: Given a Manifest's content addressable hash, any data related to it will be removed if it exists.
+ /indexer/api/v1/index_report/{digest}:
+ delete:
+ operationId: DeleteManifest
+ responses:
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ "204":
+ description: Success
+ tags:
+ - indexer
+ summary: Delete the referenced manifest.
+ description: Given a Manifest's content addressable hash, any data related to it will be removed it it exists.
+ get:
+ operationId: GetIndexReport
+ responses:
+ "200":
+ description: IndexReport retrieved
+ headers:
+ Clair-Error:
+ $ref: '#/components/headers/Clair-Error'
+ content:
+ application/vnd.clair.index_report.v1+json:
+ schema:
+ $ref: '#/components/schemas/index_report'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/index_report'
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ "404":
+ $ref: '#/components/responses/not_found'
+ tags:
+ - indexer
+ summary: Retrieve the IndexReport for the referenced manifest.
+ description: Given a Manifest's content addressable hash, an IndexReport will be retrieved if it exists.
+ parameters:
+ - $ref: '#/components/parameters/digest'
+ /indexer/api/v1/index_state:
+ get:
+ operationId: IndexState
+ responses:
+ "200":
+ description: Indexer State
+ headers:
+ Etag:
+ $ref: '#/components/headers/Etag'
+ content:
+ application/vnd.clair.index_state.v1+json:
+ schema:
+ $ref: '#/components/schemas/index_state'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/index_state'
+ "304":
+ description: Not Modified
+ tags:
+ - indexer
+ summary: Report the indexer's internal configuration and state.
+ description: |-
+ The index state endpoint returns a json structure indicating the indexer's internal configuration state.
+ A client may be interested in this as a signal that manifests may need to be re-indexed.
+ /indexer/api/v1/internal/affected_manifest:
+ post:
+ tags:
+ - internal
+ - indexer
+ operationId: AffectedManifests
+ responses:
+ "200":
+ description: TODO
+ headers:
+ Clair-Error:
+ $ref: '#/components/headers/Clair-Error'
+ content:
+ application/vnd.clair.affected_manifests.v1+json:
+ schema:
+ $ref: '#/components/schemas/affected_manifests'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/affected_manifests'
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ summary: Retrieve the set of manifests affected by the provided vulnerabilities.
+ description: ""
+ x-cli-ignore: true
+ /matcher/api/v1/internal/update_diff:
+ get:
+ tags:
+ - internal
+ - matcher
+ operationId: GetUpdateDiff
+ responses:
+ "200":
+ description: TODO
+ headers:
+ Clair-Error:
+ $ref: '#/components/headers/Clair-Error'
+ content:
+ application/vnd.clair.update_diff.v1+json:
+ schema:
+ $ref: '#/components/schemas/update_diff'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/update_diff'
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ parameters:
+ - in: query
+ name: cur
+ schema:
+ $ref: '#/components/schemas/token'
+ description: TKTK
+ - in: query
+ name: prev
+ schema:
+ $ref: '#/components/schemas/token'
+ description: TKTK
+ x-cli-ignore: true
+ /matcher/api/v1/internal/update_operation:
+ post:
+ tags:
+ - internal
+ - matcher
+ operationId: UpdateOperation
+ responses:
+ "200":
+ description: TODO
+ headers:
+ Clair-Error:
+ $ref: '#/components/headers/Clair-Error'
+ content:
+ application/vnd.clair.affected_manifests.v1+json:
+ schema:
+ $ref: '#/components/schemas/affected_manifests'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/affected_manifests'
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ x-cli-ignore: true
+ /matcher/api/v1/vulnerability_report/{digest}:
+ get:
+ operationId: GetVulnerabilityReport
+ responses:
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ "201":
+ description: Vulnerability Report Created
+ content:
+ application/vnd.clair.vulnerability_report.v1+json:
+ schema:
+ $ref: '#/components/schemas/vulnerability_report'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/vulnerability_report'
+ "404":
+ $ref: '#/components/responses/not_found'
+ tags:
+ - matcher
+ summary: Retrieve a VulnerabilityReport for the referenced manifest.
+ description: Given a Manifest's content addressable hash a VulnerabilityReport will be created. The Manifest **must** have been Indexed first via the Index endpoint.
+ parameters:
+ - $ref: '#/components/parameters/digest'
+ /notifier/api/v1/notification/{id}:
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ $ref: '#/components/schemas/token'
+ description: A notification ID returned by a callback
+ delete:
+ operationId: DeleteNotification
+ responses:
+ "200":
+ description: Success
+ headers:
+ Clair-Error:
+ $ref: '#/components/headers/Clair-Error'
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ "204":
+ description: TODO
+ tags:
+ - notifier
+ summary: Delete the referenced notification set.
+ description: |-
+ Issues a delete of the provided notification id and all associated notifications.
+ After this delete clients will no longer be able to retrieve notifications.
+ get:
+ operationId: GetNotification
+ parameters:
+ - in: query
+ name: page_size
+ schema:
+ type: integer
+ description: The maximum number of notifications to deliver in a single page.
+ - in: query
+ name: next
+ schema:
+ type: string
+ description: The next page to fetch via id. Typically this number is provided on initial response in the "page.next" field. The first request should omit this field.
+ responses:
+ "200":
+ description: A paginated list of notifications
+ headers:
+ Clair-Error:
+ $ref: '#/components/headers/Clair-Error'
+ content:
+ application/vnd.clair.notification_page.v1+json:
+ schema:
+ $ref: '#/components/schemas/notification_page'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/notification_page'
+ "400":
+ $ref: '#/components/responses/bad_request'
+ "415":
+ $ref: '#/components/responses/unsupported_media_type'
+ default:
+ $ref: '#/components/responses/oops'
+ "304":
+ description: Not modified
+ tags:
+ - notifier
+ summary: Retrieve pages of the referenced notification set.
+ description: By performing a GET with an id as a path parameter, the client will retrieve a paginated response of notification objects.
+security: []
+webhooks:
+ notification:
+ post:
+ tags:
+ - notifier
+ requestBody:
+ content:
+ application/vnd.clair.notification.v1+json:
+ schema:
+ $ref: '#/components/schemas/notification'
+ responses:
+ "200":
+ description: TODO
+components:
+ schemas:
+ token:
+ type: string
+ description: An opaque token previously obtained from the service.
+ affected_manifests:
+ $id: https://clairproject.org/api/http/v1/affected_manifests.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Affected Manifests
+ type: object
+ description: |-
+ **This is an internal type, documented for completeness.**
+
+ Manifests affected by the specified vulnerability objects.
+ properties:
+ vulnerabilities:
+ type: object
+ description: Vulnerability objects.
+ additionalProperties:
+ $ref: vulnerability.schema.json
+ vulnerable_manifests:
+ type: object
+ description: Mapping of manifest digests to vulnerability identifiers.
+ additionalProperties:
+ type: array
+ items:
+ type: string
+ description: An identifier to be used in the "#/vulnerabilities" object.
+ required:
+ - vulnerable_manifests
+ bulk_delete:
+ $id: https://clairproject.org/api/http/v1/bulk_delete.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Bulk Delete
+ type: array
+ description: Array of manifest digests to delete from the system.
+ items:
+ $ref: digest.schema.json
+ description: Manifest digest to delete from the system.
+ examples:
+ - - sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3
+ cpe:
+ $id: https://clairproject.org/api/http/v1/cpe.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Common Platform Enumeration Name
+ description: This is a CPE Name in either v2.2 "URI" form or v2.3 "Formatted String" form.
+ $comment: Clair only produces v2.3 CPE Names. Any v2.2 Names will be normalized into v2.3 form.
+ oneOf:
+ - description: 'This is the CPE 2.2 regexp: https://cpe.mitre.org/specification/2.2/cpe-language_2.2.xsd'
+ type: string
+ pattern: ^[c][pP][eE]:/[AHOaho]?(:[A-Za-z0-9\._\-~%]*){0,6}$
+ - description: 'This is the CPE 2.3 regexp: https://csrc.nist.gov/schema/cpe/2.3/cpe-naming_2.3.xsd'
+ type: string
+ pattern: ^cpe:2\.3:[aho\*\-](:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?!"#$$%&'\(\)\+,/:;<=>@\[\]\^`\{\|}~]))+(\?*|\*?))|[\*\-])){5}(:(([a-zA-Z]{2,3}(-([a-zA-Z]{2}|[0-9]{3}))?)|[\*\-]))(:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?!"#$$%&'\(\)\+,/:;<=>@\[\]\^`\{\|}~]))+(\?*|\*?))|[\*\-])){4}$
+ examples:
+ - cpe:/a:microsoft:internet_explorer:8.0.6001:beta
+ - cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*
+ digest:
+ $id: https://clairproject.org/api/http/v1/digest.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Digest
+ description: A digest acts as a content identifier, enabling content addressability.
+ oneOf:
+ - $comment: 'SHA256: MUST be implemented'
+ description: SHA256
+ type: string
+ pattern: ^sha256:[a-f0-9]{64}$
+ - $comment: 'SHA512: MAY be implemented'
+ description: SHA512
+ type: string
+ pattern: ^sha512:[a-f0-9]{128}$
+ - $comment: 'BLAKE3: MAY be implemented'
+ description: |-
+ BLAKE3
+
+ **Currently not implemented.**
+ type: string
+ pattern: ^blake3:[a-f0-9]{64}$
+ distribution:
+ $id: https://clairproject.org/api/http/v1/distribution.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Distribution
+ type: object
+ description: Distribution is the accompanying system context of a Package.
+ properties:
+ id:
+ description: Unique ID for this Distribution. May be unique to the response document, not the whole system.
+ type: string
+ did:
+ description: A lower-case string (no spaces or other characters outside of 0–9, a–z, ".", "_", and "-") identifying the operating system, excluding any version information and suitable for processing by scripts or usage in generated filenames.
+ type: string
+ name:
+ description: A string identifying the operating system.
+ type: string
+ version:
+ description: A string identifying the operating system version, excluding any OS name information, possibly including a release code name, and suitable for presentation to the user.
+ type: string
+ version_code_name:
+ description: A lower-case string (no spaces or other characters outside of 0–9, a–z, ".", "_", and "-") identifying the operating system release code name, excluding any OS name information or release version, and suitable for processing by scripts or usage in generated filenames.
+ type: string
+ version_id:
+ description: A lower-case string (mostly numeric, no spaces or other characters outside of 0–9, a–z, ".", "_", and "-") identifying the operating system version, excluding any OS name information or release code name.
+ type: string
+ arch:
+ description: A string identifying the OS architecture.
+ type: string
+ cpe:
+ description: Common Platform Enumeration name.
+ $ref: cpe.schema.json
+ pretty_name:
+ description: A pretty operating system name in a format suitable for presentation to the user.
+ type: string
+ additionalProperties: false
+ required:
+ - id
+ examples:
+ - id: "1"
+ did: ubuntu
+ name: Ubuntu
+ version: 18.04.3 LTS (Bionic Beaver)
+ version_code_name: bionic
+ version_id: "18.04"
+ pretty_name: Ubuntu 18.04.3 LTS
+ environment:
+ $id: https://clairproject.org/api/http/v1/environment.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Environment
+ type: object
+ description: Environment describes the surrounding environment a package was discovered in.
+ properties:
+ package_db:
+ description: The database the associated Package was discovered in.
+ type: string
+ distribution_id:
+ description: The ID of the Distribution of the associated Package.
+ type: string
+ introduced_in:
+ description: The Layer the associated Package was introduced in.
+ $ref: digest.schema.json
+ repository_ids:
+ description: The IDs of the Repositories of the associated Package.
+ type: array
+ items:
+ type: string
+ additionalProperties: false
+ examples:
+ - value:
+ package_db: var/lib/dpkg/status
+ introduced_in: sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a
+ distribution_id: "1"
+ error:
+ $id: https://clairproject.org/api/http/v1/error.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Error
+ type: object
+ description: A general error response.
+ properties:
+ code:
+ type: string
+ description: a code for this particular error
+ message:
+ type: string
+ description: a message with further detail
+ required:
+ - message
+ index_report:
+ $id: https://clairproject.org/api/http/v1/index_report.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Index Report
+ type: object
+ description: An index of the contents of a Manifest.
+ properties:
+ manifest_hash:
+ $ref: digest.schema.json
+ description: The Manifest's digest.
+ state:
+ type: string
+ description: The current state of the index operation
+ err:
+ type: string
+ description: An error message on event of unsuccessful index
+ success:
+ type: boolean
+ description: A bool indicating succcessful index
+ packages:
+ type: object
+ description: A map of Package objects indexed by a document-local identifier.
+ additionalProperties:
+ $ref: package.schema.json
+ distributions:
+ type: object
+ description: A map of Distribution objects indexed by a document-local identifier.
+ additionalProperties:
+ $ref: distribution.schema.json
+ repository:
+ type: object
+ description: A map of Repository objects indexed by a document-local identifier.
+ additionalProperties:
+ $ref: repository.schema.json
+ environments:
+ type: object
+ description: A map of Environment arrays indexed by a Package's identifier.
+ additionalProperties:
+ type: array
+ items:
+ $ref: environment.schema.json
+ additionalProperties: false
+ required:
+ - manifest_hash
+ - state
+ - success
+ index_state:
+ $id: https://clairproject.org/api/http/v1/index_state.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Index State
+ type: object
+ description: Information on the state of the indexer system.
+ properties:
+ state:
+ type: string
+ description: an opaque token
+ required:
+ - state
+ layer:
+ $id: https://clairproject.org/api/http/v1/layer.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Layer
+ type: object
+ description: Layer is a description of a container layer. It should contain enough information to fetch the layer.
+ properties:
+ hash:
+ $ref: digest.schema.json
+ description: Digest of the layer blob.
+ uri:
+ type: string
+ description: A URI indicating where the layer blob can be downloaded from.
+ headers:
+ description: Any additional HTTP-style headers needed for requesting layers.
+ type: object
+ patternProperties:
+ ^[a-zA-Z0-9\-_]+$:
+ type: array
+ items:
+ type: string
+ media_type:
+ description: The OCI Layer media type for this layer.
+ type: string
+ pattern: ^application/vnd\.oci\.image\.layer\.v1\.tar(\+(gzip|zstd))?$
+ additionalProperties: false
+ required:
+ - hash
+ - uri
+ manifest:
+ $id: https://clairproject.org/api/http/v1/manifest.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Manifest
+ type: object
+ description: A description of an OCI Image Manifest.
+ properties:
+ hash:
+ $ref: digest.schema.json
+ description: |-
+ The OCI Image Manifest's digest.
+
+ This is used as an identifier throughout the system. This **SHOULD** be the same as the OCI Image Manifest's digest, but this is not enforced.
+ layers:
+ type: array
+ description: The OCI Layers making up the Image, in order.
+ items:
+ $ref: layer.schema.json
+ additionalProperties: false
+ required:
+ - hash
+ examples:
+ - hash: sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3
+ layers:
+ - hash: sha256:2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36
+ uri: https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36
+ headers:
+ Authoriztion:
+ - Bearer hunter2
+ normalized_severity:
+ $id: https://clairproject.org/api/http/v1/normalized_severity.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Normalized Severity
+ description: Standardized severity values.
+ enum:
+ - Unknown
+ - Negligible
+ - Low
+ - Medium
+ - High
+ - Critical
+ notification_page:
+ $id: https://clairproject.org/api/http/v1/notification_page.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Notification Page
+ type: object
+ description: A page description and list of notifications.
+ properties:
+ page:
+ description: An object informing the client the next page to retrieve.
+ type: object
+ properties:
+ size:
+ type: integer
+ next:
+ oneOf:
+ - type: string
+ - const: "-1"
+ additionalProperties: false
+ required:
+ - size
+ notifications:
+ description: Notifications within this page.
+ type: array
+ items:
+ $ref: notification.schema.json
+ additionalProperties: false
+ required:
+ - page
+ - notifications
+ examples:
+ - page:
+ size: 100
+ next: 1b4d0db2-e757-4150-bbbb-543658144205
+ notifications:
+ - id: 5e4b387e-88d3-4364-86fd-063447a6fad2
+ manifest: sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a
+ reason: added
+ vulnerability:
+ name: CVE-2009-5155
+ fixed_in_version: v0.0.1
+ links: http://example.com/CVE-2009-5155
+ description: In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match."
+ normalized_severity: Unknown
+ package:
+ id: "10"
+ name: libapt-pkg5.0
+ version: 1.6.11
+ kind: BINARY
+ arch: x86
+ source:
+ id: "9"
+ name: apt
+ version: 1.6.11
+ kind: SOURCE
+ source: null
+ distribution:
+ id: "1"
+ did: ubuntu
+ name: Ubuntu
+ version: 18.04.3 LTS (Bionic Beaver)
+ version_code_name: bionic
+ version_id: "18.04"
+ pretty_name: Ubuntu 18.04.3 LTS
+ notification:
+ $id: https://clairproject.org/api/http/v1/notification.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Notification
+ type: object
+ description: A change in a manifest affected by a vulnerability.
+ properties:
+ id:
+ description: Unique identifier for this notification.
+ type: string
+ manifest:
+ $ref: digest.schema.json
+ description: The digest of the manifest affected by the provided vulnerability.
+ reason:
+ description: The reason for the notifcation.
+ enum:
+ - added
+ - removed
+ vulnerability:
+ $ref: vulnerability_summary.schema.json
+ additionalProperties: false
+ required:
+ - id
+ - manifest
+ - reason
+ - vulnerability
+ package:
+ $id: https://clairproject.org/api/http/v1/package.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Package
+ type: object
+ description: Description of installed software.
+ properties:
+ id:
+ description: Unique ID for this Package. May be unique to the response document, not the whole system.
+ type: string
+ name:
+ description: |-
+ Identifier of this Package.
+
+ The uniqueness and scoping of this name depends on the packaging system.
+ type: string
+ version:
+ description: Version of this Package, as reported by the packaging system.
+ type: string
+ kind:
+ description: The "kind" of this Package.
+ enum:
+ - BINARY
+ - SOURCE
+ default: BINARY
+ source:
+ $ref: '#'
+ description: Source Package that produced the current binary Package, if known.
+ normalized_version:
+ description: |-
+ Normalized representation of the discoverd version.
+
+ The format is not specific, but is guarenteed to be forward compatible.
+ type: string
+ module:
+ description: |-
+ An identifier for intra-Repository grouping of packages.
+
+ Likely only relevant on rpm-based systems.
+ type: string
+ arch:
+ description: Native architecture for the Package.
+ type: string
+ $comment: This should become and enum in the future.
+ cpe:
+ $ref: cpe.schema.json
+ description: CPE Name for the Package.
+ additionalProperties: false
+ required:
+ - name
+ - version
+ examples:
+ - id: "10"
+ name: libapt-pkg5.0
+ version: 1.6.11
+ kind: binary
+ normalized_version: ""
+ arch: x86
+ module: ""
+ cpe: ""
+ source:
+ id: "9"
+ name: apt
+ version: 1.6.11
+ kind: source
+ source: null
+ range:
+ $id: https://clairproject.org/api/http/v1/range.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Range
+ type: object
+ description: A range of versions.
+ properties:
+ '[':
+ type: string
+ description: Lower bound, inclusive.
+ ):
+ type: string
+ description: Upper bound, exclusive.
+ minProperties: 1
+ additionalProperties: false
+ repository:
+ $id: https://clairproject.org/api/http/v1/repository.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Repository
+ type: object
+ description: Description of a software repository
+ properties:
+ id:
+ description: Unique ID for this Repository. May be unique to the response document, not the whole system.
+ type: string
+ name:
+ description: Human-relevant name for the Repository.
+ type: string
+ key:
+ description: Machine-relevant name for the Repository.
+ type: string
+ uri:
+ description: URI describing the Repository.
+ type: string
+ format: uri
+ cpe:
+ description: CPE name for the Repository.
+ $ref: cpe.schema.json
+ additionalProperties: false
+ required:
+ - id
+ update_diff:
+ $id: https://clairproject.org/api/http/v1/update_diff.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Update Difference
+ type: object
+ description: |-
+ **This is an internal type, documented for completeness.**
+
+ TKTK
+ additionalProperties: false
+ required: []
+ vulnerability_core:
+ $id: https://clairproject.org/api/http/v1/vulnerability_core.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Vulnerability Core
+ type: object
+ description: The core elements of vulnerabilities in the Clair system.
+ properties:
+ name:
+ type: string
+ description: Human-readable name, as presented in the vendor data.
+ fixed_in_version:
+ type: string
+ description: Version string, as presented in the vendor data.
+ severity:
+ type: string
+ description: Severity, as presented in the vendor data.
+ normalized_severity:
+ $ref: normalized_severity.schema.json
+ description: A well defined set of severity strings guaranteed to be present.
+ range:
+ $ref: range.schema.json
+ description: Range of versions the vulnerability applies to.
+ arch_op:
+ description: Flag indicating how the referenced package's "arch" member should be interpreted.
+ enum:
+ - equals
+ - not equals
+ - pattern match
+ package:
+ $ref: package.schema.json
+ description: A package description
+ distribution:
+ $ref: distribution.schema.json
+ description: A distribution description
+ repository:
+ $ref: repository.schema.json
+ description: A repository description
+ required:
+ - name
+ - normalized_severity
+ dependentRequired:
+ package:
+ - arch_op
+ anyOf:
+ - required:
+ - package
+ - required:
+ - repository
+ - required:
+ - distribution
+ vulnerability_report:
+ $id: https://clairproject.org/api/http/v1/vulnerability_report.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Vulnerability Report
+ type: object
+ description: A report with discovered packages, package environments, and package vulnerabilities within a Manifest.
+ properties:
+ manifest_hash:
+ $ref: digest.schema.json
+ description: The Manifest's digest.
+ packages:
+ type: object
+ description: A map of Package objects indexed by a document-local identifier.
+ additionalProperties:
+ $ref: package.schema.json
+ distributions:
+ type: object
+ description: A map of Distribution objects indexed by a document-local identifier.
+ additionalProperties:
+ $ref: distribution.schema.json
+ repository:
+ type: object
+ description: A map of Repository objects indexed by a document-local identifier.
+ additionalProperties:
+ $ref: repository.schema.json
+ environments:
+ type: object
+ description: A map of Environment arrays indexed by a Package's identifier.
+ additionalProperties:
+ type: array
+ items:
+ $ref: environment.schema.json
+ vulnerabilities:
+ type: object
+ description: A map of Vulnerabilities indexed by a document-local identifier.
+ additionalProperties:
+ $ref: vulnerability.schema.json
+ package_vulnerabilities:
+ type: object
+ description: A mapping of Vulnerability identifier lists indexed by Package identifier.
+ additionalProperties:
+ type: array
+ items:
+ type: string
+ enrichments:
+ type: object
+ description: A mapping of extra "enrichment" data by type
+ additionalProperties:
+ type: array
+ additionalProperties: false
+ required:
+ - distributions
+ - environments
+ - manifest_hash
+ - packages
+ - package_vulnerabilities
+ - vulnerabilities
+ vulnerability:
+ $id: https://clairproject.org/api/http/v1/vulnerability.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Vulnerability
+ type: object
+ description: Description of a software flaw.
+ $ref: vulnerability_core.schema.json
+ properties:
+ id:
+ description: ""
+ type: string
+ updater:
+ description: ""
+ type: string
+ description:
+ description: ""
+ type: string
+ issued:
+ description: ""
+ type: string
+ format: date-time
+ links:
+ description: ""
+ type: string
+ unevaluatedProperties: false
+ required:
+ - id
+ - updater
+ examples:
+ - id: "356835"
+ updater: ubuntu
+ name: CVE-2009-5155
+ description: In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.
+ links: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-5155 http://people.canonical.com/~ubuntu-security/cve/2009/CVE-2009-5155.html https://sourceware.org/bugzilla/show_bug.cgi?id=11053 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22793 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32806 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34238 https://sourceware.org/bugzilla/show_bug.cgi?id=18986
+ severity: Low
+ normalized_severity: Low
+ package:
+ id: "0"
+ name: glibc
+ version: 2.27-0ubuntu1
+ kind: binary
+ source: null
+ dist:
+ id: "0"
+ did: ubuntu
+ name: Ubuntu
+ version: 18.04.3 LTS (Bionic Beaver)
+ version_code_name: bionic
+ version_id: "18.04"
+ arch: amd64
+ repo:
+ id: "0"
+ name: Ubuntu 18.04.3 LTS
+ issued: "2019-10-12T07:20:50.52Z"
+ fixed_in_version: 2.28-0ubuntu1
+ vulnerability_summary:
+ $id: https://clairproject.org/api/http/v1/vulnerability_summary.schema.json
+ $schema: https://json-schema.org/draft/2020-12/schema
+ title: Vulnerability Summary
+ type: object
+ description: A summary of a vulnerability.
+ $ref: vulnerability_core.schema.json
+ unevaluatedProperties: false
+ examples:
+ - name: CVE-2009-5155
+ description: In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.
+ normalized_severity: Low
+ fixed_in_version: v0.0.1
+ links: http://link-to-advisory
+ package:
+ id: "0"
+ name: glibc
+ version: v0.0.1-rc1
+ dist:
+ id: "0"
+ did: ubuntu
+ name: Ubuntu
+ version: 18.04.3 LTS (Bionic Beaver)
+ version_code_name: bionic
+ version_id: "18.04"
+ repo:
+ id: "0"
+ name: Ubuntu 18.04.3 LTS
+ responses:
+ bad_request:
+ description: Bad Request
+ content:
+ application/vnd.clair.error.v1+json:
+ schema:
+ $ref: '#/components/schemas/error'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/error'
+ oops:
+ description: Internal Server Error
+ content:
+ application/vnd.clair.error.v1+json:
+ schema:
+ $ref: '#/components/schemas/error'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/error'
+ not_found:
+ description: Not Found
+ content:
+ application/vnd.clair.error.v1+json:
+ schema:
+ $ref: '#/components/schemas/error'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/error'
+ unsupported_media_type:
+ description: Unsupported Media Type
+ content:
+ application/vnd.clair.error.v1+json:
+ schema:
+ $ref: '#/components/schemas/error'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/error'
+ parameters:
+ digest:
+ description: OCI-compatible digest of a referred object.
+ name: digest
+ in: path
+ schema:
+ $ref: '#/components/schemas/digest'
+ required: true
+ headers:
+ Clair-Error:
+ description: This is a trailer containing any errors encountered while writing the response.
+ style: simple
+ schema:
+ type: string
+ Etag:
+ description: HTTP [ETag header](https://httpwg.org/specs/rfc9110.html#field.etag)
+ style: simple
+ schema:
+ type: string
+ Link:
+ description: Web Linking [Link header](https://httpwg.org/specs/rfc8288.html#header)
+ style: simple
+ schema:
+ type: string
+ Location:
+ description: HTTP [Location header](https://httpwg.org/specs/rfc9110.html#field.location)
+ style: simple
+ required: true
+ schema:
+ type: string
+ securitySchemes:
+ psk:
+ type: http
+ scheme: bearer
+ bearerFormat: JWT with preshared key and allow-listed issuers
+ description: Clair's authentication scheme.
diff --git a/httptransport/discoveryhandler.go b/httptransport/discoveryhandler.go
index 2d8d0acff0..42e6eb2047 100644
--- a/httptransport/discoveryhandler.go
+++ b/httptransport/discoveryhandler.go
@@ -4,9 +4,12 @@ import (
"bytes"
"context"
_ "embed" // for json and etag
+ "encoding/json"
"errors"
"io"
"net/http"
+ "slices"
+ "sync"
"time"
"github.com/quay/zlog"
@@ -16,18 +19,37 @@ import (
"github.com/quay/clair/v4/middleware/compress"
)
-//go:generate go run openapigen.go
+//go:generate env -C api zsh ./openapi.zsh
var (
- //go:embed openapi.json
+ //go:embed api/v1/openapi.json
openapiJSON []byte
- //go:embed openapi.etag
- openapiJSONEtag string
+ //go:embed api/v1/openapi.yaml
+ openapiYAML []byte
+ //go:embed api/v1/openapi.etag
+ openapiEtag string
+
+ // Compacted version of [openapiJSON] for the wire.
+ //
+ // Doing this means we can keep a nicer-diffing version checked in.
+ compactOpenapiJSON = sync.OnceValue(func() []byte {
+ var buf bytes.Buffer
+ buf.Grow(len(openapiJSON))
+ if err := json.Compact(&buf, openapiJSON); err != nil {
+ panic(err)
+ }
+ b := buf.Bytes()
+ return slices.Clip(b)
+ })
)
// DiscoveryHandler serves the embedded OpenAPI spec.
func DiscoveryHandler(_ context.Context, prefix string, topt otelhttp.Option) http.Handler {
- allow := []string{`application/json`, `application/vnd.oai.openapi+json`}
+ allow := []string{
+ `application/openapi+json`, `application/openapi+yaml`, // New types: https://datatracker.ietf.org/doc/draft-ietf-httpapi-rest-api-mediatypes/
+ `application/json`, `application/yaml`, // Format types.
+ `application/vnd.oai.openapi+json`, `application/vnd.oai.openapi+yaml`, // Older vendor-tree types.
+ }
// These functions are written back-to-front.
var inner http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@@ -41,10 +63,21 @@ func DiscoveryHandler(_ context.Context, prefix string, topt otelhttp.Option) ht
default:
apiError(ctx, w, http.StatusInternalServerError, "unexpected error: %v", err)
}
- w.Header().Set("etag", openapiJSONEtag)
+ h := w.Header()
+ kind := h.Get(`Content-Type`)
+ var src *bytes.Reader
+ switch kind[len(kind)-4:] {
+ case "json":
+ src = bytes.NewReader(compactOpenapiJSON())
+ case "yaml":
+ src = bytes.NewReader(openapiYAML)
+ default:
+ apiError(ctx, w, http.StatusInternalServerError, "unexpected error: unknown content-type kind: %q", kind)
+ }
+ h.Set("Etag", openapiEtag)
var err error
defer writerError(w, &err)()
- _, err = io.Copy(w, bytes.NewReader(openapiJSON))
+ _, err = io.Copy(w, src)
})
inner = otelhttp.NewHandler(
compress.Handler(discoverywrapper.wrap(prefix, inner)),
diff --git a/httptransport/discoveryhandler_test.go b/httptransport/discoveryhandler_test.go
index 4ebee7d0fd..17c645bf88 100644
--- a/httptransport/discoveryhandler_test.go
+++ b/httptransport/discoveryhandler_test.go
@@ -1,108 +1,72 @@
package httptransport
import (
- "bytes"
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
"testing"
- "github.com/google/go-cmp/cmp"
- "github.com/google/go-cmp/cmp/cmpopts"
"github.com/quay/zlog"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
- "go.opentelemetry.io/otel/trace"
+ "go.opentelemetry.io/otel/trace/noop"
)
-func TestDiscoveryEndpoint(t *testing.T) {
- ctx := zlog.Test(context.Background(), t)
- h := DiscoveryHandler(ctx, OpenAPIV1Path, otelhttp.WithTracerProvider(trace.NewNoopTracerProvider()))
+func TestDiscovery(t *testing.T) {
+ t.Run("Endpoint", func(t *testing.T) {
+ ctx := zlog.Test(context.Background(), t)
+ h := DiscoveryHandler(ctx, OpenAPIV1Path, otelhttp.WithTracerProvider(noop.NewTracerProvider()))
- r := httptest.NewRecorder()
- req := httptest.NewRequest("GET", OpenAPIV1Path, nil).WithContext(ctx)
- req.Header.Set("Accept", "application/yaml, application/json; q=0.4, application/vnd.oai.openapi+json; q=1.0")
- h.ServeHTTP(r, req)
-
- resp := r.Result()
- if resp.StatusCode != http.StatusOK {
- t.Fatalf("got status code: %v want status code: %v", resp.StatusCode, http.StatusOK)
- }
- if got, want := resp.Header.Get("content-type"), "application/vnd.oai.openapi+json"; got != want {
- t.Errorf("got: %q, want: %q", got, want)
- }
-
- buf, err := io.ReadAll(resp.Body)
- if err != nil {
- t.Fatalf("failed to ready response body: %v", err)
- }
-
- m := map[string]interface{}{}
- err = json.Unmarshal(buf, &m)
- if err != nil {
- t.Fatalf("failed to json parse returned bytes: %v", err)
- }
-
- if _, ok := m["openapi"]; !ok {
- t.Fatalf("returned json did not container openapi key at the root")
- }
- t.Logf("openapi verion: %v", m["openapi"])
-}
-
-func TestDiscoveryFailure(t *testing.T) {
- ctx := zlog.Test(context.Background(), t)
- h := DiscoveryHandler(ctx, OpenAPIV1Path, otelhttp.WithTracerProvider(trace.NewNoopTracerProvider()))
-
- r := httptest.NewRecorder()
- // Needed because handlers exit the goroutine.
- done := make(chan struct{})
- go func() {
- defer close(done)
+ r := httptest.NewRecorder()
req := httptest.NewRequest("GET", OpenAPIV1Path, nil).WithContext(ctx)
- req.Header.Set("Accept", "application/yaml")
+ req.Header.Set("Accept", "application/yaml; q=0.4, application/json; q=0.4, application/vnd.oai.openapi+json; q=0.6, application/openapi+json")
h.ServeHTTP(r, req)
- }()
- <-done
-
- resp := r.Result()
- t.Log(resp.Status)
- if got, want := resp.StatusCode, http.StatusUnsupportedMediaType; got != want {
- t.Errorf("got status code: %v want status code: %v", got, want)
- }
-}
-func TestEmbedding(t *testing.T) {
- d := t.TempDir()
- var buf bytes.Buffer
- cmd := exec.Command("go", "run", "openapigen.go", "-in", "../openapi.yaml", "-out", d)
- cmd.Stdout = &buf
- cmd.Stderr = &buf
- t.Log(cmd.Args)
- if err := cmd.Run(); err != nil {
- t.Error(err)
- t.Error(buf.String())
- }
+ resp := r.Result()
+ if resp.StatusCode != http.StatusOK {
+ t.Fatalf("got status code: %v want status code: %v", resp.StatusCode, http.StatusOK)
+ }
+ if got, want := resp.Header.Get("content-type"), "application/openapi+json"; got != want {
+ t.Errorf("got: %q, want: %q", got, want)
+ }
- for _, n := range []string{
- "openapi.json", "openapi.etag"} {
- nf, err := os.ReadFile(filepath.Join(d, n))
+ buf, err := io.ReadAll(resp.Body)
if err != nil {
- t.Error(err)
- continue
+ t.Fatalf("failed to ready response body: %v", err)
}
- of, err := os.ReadFile(n)
+
+ m := make(map[string]any)
+ err = json.Unmarshal(buf, &m)
if err != nil {
- t.Error(err)
- continue
+ t.Fatalf("failed to json parse returned bytes: %v", err)
+ }
+
+ if _, ok := m["openapi"]; !ok {
+ t.Fatalf("returned json did not container openapi key at the root")
}
- if got, want := string(nf), string(of); !cmp.Equal(got, want) {
- t.Error(cmp.Diff(got, want, cmpopts.AcyclicTransformer("normalizeWhitespace", func(s string) []string { return strings.Split(s, "\n") })))
- t.Log("\n\tYou probably edited the openapi.yaml and forgot to run `go generate` here.")
+ t.Logf("openapi verion: %v", m["openapi"])
+ })
+
+ t.Run("Failure", func(t *testing.T) {
+ ctx := zlog.Test(context.Background(), t)
+ h := DiscoveryHandler(ctx, OpenAPIV1Path, otelhttp.WithTracerProvider(noop.NewTracerProvider()))
+
+ r := httptest.NewRecorder()
+ // Needed because handlers exit the goroutine.
+ done := make(chan struct{})
+ go func() {
+ defer close(done)
+ req := httptest.NewRequest("GET", OpenAPIV1Path, nil).WithContext(ctx)
+ req.Header.Set("Accept", "application/xml")
+ h.ServeHTTP(r, req)
+ }()
+ <-done
+
+ resp := r.Result()
+ t.Log(resp.Status)
+ if got, want := resp.StatusCode, http.StatusUnsupportedMediaType; got != want {
+ t.Errorf("got status code: %v want status code: %v", got, want)
}
- }
+ })
}
diff --git a/httptransport/indexer_v1.go b/httptransport/indexer_v1.go
index 86fa050bb3..a1e4e0e874 100644
--- a/httptransport/indexer_v1.go
+++ b/httptransport/indexer_v1.go
@@ -255,7 +255,7 @@ func (h *IndexerV1) affectedManifests(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
apiError(ctx, w, http.StatusMethodNotAllowed, "method disallowed: %s", r.Method)
}
- allow := []string{"application/vnd.clair.affectedmanifests.v1+json", "application/json"}
+ allow := []string{"application/vnd.clair.affected_manifests.v1+json", "application/json"}
switch err := pickContentType(w, r, allow); {
case errors.Is(err, nil): // OK
case errors.Is(err, ErrMediaType):
diff --git a/httptransport/openapi.etag b/httptransport/openapi.etag
deleted file mode 100644
index 1da246c82e..0000000000
--- a/httptransport/openapi.etag
+++ /dev/null
@@ -1 +0,0 @@
-"a16d4a25e54a4cfe7fbf4e234af1c7585e840fef19c4f84aba1e814233c3b281"
\ No newline at end of file
diff --git a/httptransport/openapi.json b/httptransport/openapi.json
deleted file mode 100644
index 69a4c1a385..0000000000
--- a/httptransport/openapi.json
+++ /dev/null
@@ -1 +0,0 @@
-{"components":{"examples":{"Distribution":{"value":{"arch":"","cpe":"","did":"ubuntu","id":"1","name":"Ubuntu","pretty_name":"Ubuntu 18.04.3 LTS","version":"18.04.3 LTS (Bionic Beaver)","version_code_name":"bionic","version_id":"18.04"}},"Environment":{"value":{"distribution_id":"1","introduced_in":"sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a","package_db":"var/lib/dpkg/status"}},"Package":{"value":{"arch":"x86","cpe":"","id":"10","kind":"binary","module":"","name":"libapt-pkg5.0","normalized_version":"","source":{"id":"9","kind":"source","name":"apt","source":null,"version":"1.6.11"},"version":"1.6.11"}},"VulnSummary":{"value":{"description":"In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"","dist":{"arch":"","cpe":"","did":"ubuntu","id":"0","name":"Ubuntu","pretty_name":"","version":"18.04.3 LTS (Bionic Beaver)","version_code_name":"bionic","version_id":"18.04"},"fixed_in_version":"v0.0.1","links":"http://link-to-advisory","name":"CVE-2009-5155","normalized_severity":"Low","package":{"id":"0","kind":"","name":"glibc","package_db":"","repository_hint":"","source":null,"version":""},"repo":{"id":"0","key":"","name":"Ubuntu 18.04.3 LTS","uri":""}}},"Vulnerability":{"value":{"description":"In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"","dist":{"arch":"","cpe":"","did":"ubuntu","id":"0","name":"Ubuntu","pretty_name":"","version":"18.04.3 LTS (Bionic Beaver)","version_code_name":"bionic","version_id":"18.04"},"fixed_in_version":"2.28-0ubuntu1","id":"356835","issued":"2019-10-12T07:20:50.52Z","links":"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-5155 http://people.canonical.com/~ubuntu-security/cve/2009/CVE-2009-5155.html https://sourceware.org/bugzilla/show_bug.cgi?id=11053 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22793 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32806 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34238 https://sourceware.org/bugzilla/show_bug.cgi?id=18986\"","name":"CVE-2009-5155","normalized_severity":"Low","package":{"id":"0","kind":"","name":"glibc","package_db":"","repository_hint":"","source":null,"version":""},"repo":{"id":"0","key":"","name":"Ubuntu 18.04.3 LTS","uri":""},"severity":"Low","updater":""}}},"responses":{"BadRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Bad Request"},"InternalServerError":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Internal Server Error"},"MethodNotAllowed":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Method Not Allowed"},"NotFound":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not Found"}},"schemas":{"BulkDelete":{"description":"An array of Digests to be deleted.","items":{"$ref":"#/components/schemas/Digest"},"title":"BulkDelete","type":"array"},"Callback":{"description":"A callback for clients to retrieve notifications","properties":{"callback":{"description":"the url where notifications can be retrieved","example":"http://clair-notifier/notifier/api/v1/notification/269886f3-0146-4f08-9bf7-cb1138d48643","type":"string"},"notification_id":{"description":"the unique identifier for this set of notifications","example":"269886f3-0146-4f08-9bf7-cb1138d48643","type":"string"}},"title":"Callback","type":"object"},"Digest":{"description":"A digest string with prefixed algorithm. The format is described here: https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests\nDigests are used throughout the API to identify Layers and Manifests.","example":"sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3","title":"Digest","type":"string"},"Distribution":{"description":"An indexed distribution discovered in a layer. See https://www.freedesktop.org/software/systemd/man/os-release.html for explanations and example of fields.","example":{"$ref":"#/components/examples/Distribution/value"},"properties":{"arch":{"type":"string"},"cpe":{"type":"string"},"did":{"type":"string"},"id":{"description":"A unique ID representing this distribution","type":"string"},"name":{"type":"string"},"pretty_name":{"type":"string"},"version":{"type":"string"},"version_code_name":{"type":"string"},"version_id":{"type":"string"}},"required":["id","did","name","version","version_code_name","version_id","arch","cpe","pretty_name"],"title":"Distribution","type":"object"},"Environment":{"description":"The environment a particular package was discovered in.","properties":{"distribution_id":{"description":"The distribution ID found in an associated IndexReport or VulnerabilityReport.","example":"1","type":"string"},"introduced_in":{"$ref":"#/components/schemas/Digest"},"package_db":{"description":"The filesystem path or unique identifier of a package database.","example":"var/lib/dpkg/status","type":"string"}},"required":["package_db","introduced_in","distribution_id"],"title":"Environment","type":"object"},"Error":{"description":"A general error schema returned when status is not 200 OK","properties":{"code":{"description":"a code for this particular error","type":"string"},"message":{"description":"a message with further detail","type":"string"}},"title":"Error","type":"object"},"IndexReport":{"description":"A report of the Index process for a particular manifest. A client's usage of this is largely information. Clair uses this report for matching Vulnerabilities.","properties":{"distributions":{"additionalProperties":{"$ref":"#/components/schemas/Distribution"},"description":"A map of Distribution objects keyed by their Distribution.id discovered in the manifest.","example":{"1":{"$ref":"#/components/examples/Distribution/value"}},"type":"object"},"environments":{"additionalProperties":{"items":{"$ref":"#/components/schemas/Environment"},"type":"array"},"description":"A map of lists containing Environment objects keyed by the associated Package.id.","example":{"10":[{"distribution_id":"1","introduced_in":"sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a","package_db":"var/lib/dpkg/status"}]},"type":"object"},"err":{"description":"An error message on event of unsuccessful index","example":"","type":"string"},"manifest_hash":{"$ref":"#/components/schemas/Digest"},"packages":{"additionalProperties":{"$ref":"#/components/schemas/Package"},"description":"A map of Package objects indexed by Package.id","example":{"10":{"$ref":"#/components/examples/Package/value"}},"type":"object"},"state":{"description":"The current state of the index operation","example":"IndexFinished","type":"string"},"success":{"description":"A bool indicating succcessful index","example":true,"type":"boolean"}},"required":["manifest_hash","state","packages","distributions","environments","success","err"],"title":"IndexReport","type":"object"},"Layer":{"description":"A Layer within a Manifest and where Clair may retrieve it.","properties":{"hash":{"$ref":"#/components/schemas/Digest"},"headers":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"map of arrays of header values keyed by header value. e.g. map[string][]string","type":"object"},"uri":{"description":"A URI describing where the layer may be found. Implementations MUST support http(s) schemes and MAY support additional schemes.","example":"https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36","type":"string"}},"required":["hash","uri","headers"],"title":"Layer","type":"object"},"Manifest":{"description":"A Manifest representing a container. The 'layers' array must preserve the original container's layer order for accurate usage.","properties":{"hash":{"$ref":"#/components/schemas/Digest"},"layers":{"items":{"$ref":"#/components/schemas/Layer"},"type":"array"}},"required":["hash","layers"],"title":"Manifest","type":"object"},"Notification":{"description":"A notification expressing a change in a manifest affected by a vulnerability.","properties":{"id":{"description":"a unique identifier for this notification","example":"5e4b387e-88d3-4364-86fd-063447a6fad2","type":"string"},"manifest":{"description":"The hash of the manifest affected by the provided vulnerability.","example":"sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a","type":"string"},"reason":{"description":"the reason for the notifcation, [added | removed]","example":"added","type":"string"},"vulnerability":{"$ref":"#/components/schemas/VulnSummary"}},"title":"Notification","type":"object"},"Package":{"description":"A package discovered by indexing a Manifest","example":{"$ref":"#/components/examples/Package/value"},"properties":{"arch":{"description":"The package's target system architecture","type":"string"},"cpe":{"description":"A CPE identifying the package","type":"string"},"id":{"description":"A unique ID representing this package","type":"string"},"kind":{"description":"Kind of package. Source | Binary","type":"string"},"module":{"description":"A module further defining a namespace for a package","type":"string"},"name":{"description":"Name of the Package","type":"string"},"normalized_version":{"$ref":"#/components/schemas/Version"},"source":{"$ref":"#/components/schemas/Package"},"version":{"description":"Version of the Package","type":"string"}},"required":["id","name","version"],"title":"Package","type":"object"},"Page":{"description":"A page object indicating to the client how to retrieve multiple pages of a particular entity.","properties":{"next":{"description":"The next id to submit to the api to continue paging","example":"1b4d0db2-e757-4150-bbbb-543658144205","type":"string"},"size":{"description":"The maximum number of elements in a page","example":1,"type":"int"}},"title":"Page"},"PagedNotifications":{"description":"A page object followed by a list of notifications","properties":{"notifications":{"description":"A list of notifications within this page","items":{"$ref":"#/components/schemas/Notification"},"type":"array"},"page":{"description":"A page object informing the client the next page to retrieve. If page.next becomes \"-1\" the client should stop paging.","example":{"next":"1b4d0db2-e757-4150-bbbb-543658144205","size":100},"type":"object"}},"title":"PagedNotifications","type":"object"},"Repository":{"description":"A package repository","properties":{"cpe":{"type":"string"},"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"},"uri":{"type":"string"}},"title":"Repository","type":"object"},"State":{"description":"an opaque identifier","example":{"state":"aae368a064d7c5a433d0bf2c4f5554cc"},"properties":{"state":{"description":"an opaque identifier","type":"string"}},"required":["state"],"title":"State","type":"object"},"Version":{"description":"Version is a normalized claircore version, composed of a \"kind\" and an array of integers such that two versions of the same kind have the correct ordering when the integers are compared pair-wise.","example":"pep440:0.0.0.0.0.0.0.0.0","title":"Version","type":"string"},"VulnSummary":{"description":"A summary of a vulnerability","properties":{"description":{"description":"the vulnerability name","example":"In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.\"","type":"string"},"distribution":{"$ref":"#/components/schemas/Distribution"},"fixed_in_version":{"description":"The version which the vulnerability is fixed in. Empty if not fixed.","example":"v0.0.1","type":"string"},"links":{"description":"links to external information about vulnerability","example":"http://link-to-advisory","type":"string"},"name":{"description":"the vulnerability name","example":"CVE-2009-5155","type":"string"},"normalized_severity":{"description":"A well defined set of severity strings guaranteed to be present.","enum":["Unknown","Negligible","Low","Medium","High","Critical"],"type":"string"},"package":{"$ref":"#/components/schemas/Package"},"repository":{"$ref":"#/components/schemas/Repository"}},"title":"VulnSummary","type":"object"},"Vulnerability":{"description":"A unique vulnerability indexed by Clair","example":{"$ref":"#/components/examples/Vulnerability/value"},"properties":{"description":{"description":"A description of this specific vulnerability.","type":"string"},"distribution":{"$ref":"#/components/schemas/Distribution"},"fixed_in_version":{"description":"A unique ID representing this vulnerability.","type":"string"},"id":{"description":"A unique ID representing this vulnerability.","type":"string"},"issued":{"description":"The timestamp in which the vulnerability was issued","type":"string"},"links":{"description":"A space separate list of links to any external information.","type":"string"},"name":{"description":"Name of this specific vulnerability.","type":"string"},"normalized_severity":{"description":"A well defined set of severity strings guaranteed to be present.","enum":["Unknown","Negligible","Low","Medium","High","Critical"],"type":"string"},"package":{"$ref":"#/components/schemas/Package"},"range":{"description":"The range of package versions affected by this vulnerability.","type":"string"},"repository":{"$ref":"#/components/schemas/Repository"},"severity":{"description":"A severity keyword taken verbatim from the vulnerability source.","type":"string"},"updater":{"description":"A unique ID representing this vulnerability.","type":"string"}},"required":["id","updater","name","description","links","severity","normalized_severity","fixed_in_version"],"title":"Vulnerability","type":"object"},"VulnerabilityReport":{"description":"A report expressing discovered packages, package environments, and package vulnerabilities within a Manifest.","properties":{"distributions":{"additionalProperties":{"$ref":"#/components/schemas/Distribution"},"description":"A map of Distribution objects indexed by Distribution.id.","example":{"1":{"$ref":"#/components/examples/Distribution/value"}},"type":"object"},"environments":{"additionalProperties":{"items":{"$ref":"#/components/schemas/Environment"},"type":"array"},"description":"A mapping of Environment lists indexed by Package.id","example":{"10":[{"distribution_id":"1","introduced_in":"sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a","package_db":"var/lib/dpkg/status"}]},"type":"object"},"manifest_hash":{"$ref":"#/components/schemas/Digest"},"package_vulnerabilities":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"description":"A mapping of Vulnerability.id lists indexed by Package.id.","example":{"10":["356835"]}},"packages":{"additionalProperties":{"$ref":"#/components/schemas/Package"},"description":"A map of Package objects indexed by Package.id","example":{"10":{"$ref":"#/components/examples/Package/value"}},"type":"object"},"vulnerabilities":{"additionalProperties":{"$ref":"#/components/schemas/Vulnerability"},"description":"A map of Vulnerabilities indexed by Vulnerability.id","example":{"356835":{"$ref":"#/components/examples/Vulnerability/value"}},"type":"object"}},"required":["manifest_hash","packages","distributions","environments","vulnerabilities","package_vulnerabilities"],"title":"VulnerabilityReport","type":"object"}}},"info":{"contact":{"email":"quay-devel@redhat.com","name":"Clair Team","url":"http://github.com/quay/clair"},"description":"ClairV4 is a set of cooperating microservices which scan, index, and match your container's content with known vulnerabilities.","license":{"name":"Apache License 2.0","url":"http://www.apache.org/licenses/"},"termsOfService":"","title":"ClairV4","version":"1.1"},"openapi":"3.0.2","paths":{"/indexer/api/v1/index_report":{"delete":{"description":"Given a Manifest's content addressable hash, any data related to it will be removed if it exists.","operationId":"DeleteManifests","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDelete"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDelete"}}},"description":"OK"},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}},"summary":"Delete the IndexReport and associated information for the given Manifest hashes, if they exist.","tags":["Indexer"]},"post":{"description":"By submitting a Manifest object to this endpoint Clair will fetch the layers, scan each layer's contents, and provide an index of discovered packages, repository and distribution information.","operationId":"Index","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Manifest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexReport"}}},"description":"IndexReport Created"},"400":{"$ref":"#/components/responses/BadRequest"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"500":{"$ref":"#/components/responses/InternalServerError"}},"summary":"Index the contents of a Manifest","tags":["Indexer"]}},"/indexer/api/v1/index_report/{manifest_hash}":{"delete":{"description":"Given a Manifest's content addressable hash, any data related to it will be removed it it exists.","operationId":"DeleteManifest","parameters":[{"description":"A digest of a manifest that has been indexed previous to this request.","in":"path","name":"manifest_hash","required":true,"schema":{"$ref":"#/components/schemas/Digest"}}],"responses":{"204":{"description":"OK"},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}},"summary":"Delete the IndexReport and associated information for the given Manifest hash, if exists.","tags":["Indexer"]},"get":{"description":"Given a Manifest's content addressable hash an IndexReport will be retrieved if exists.","operationId":"GetIndexReport","parameters":[{"description":"A digest of a manifest that has been indexed previous to this request.","in":"path","name":"manifest_hash","required":true,"schema":{"$ref":"#/components/schemas/Digest"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexReport"}}},"description":"IndexReport retrieved"},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"500":{"$ref":"#/components/responses/InternalServerError"}},"summary":"Retrieve an IndexReport for the given Manifest hash if exists.","tags":["Indexer"]}},"/indexer/api/v1/index_state":{"get":{"description":"The index state endpoint returns a json structure indicating the indexer's internal configuration state.\nA client may be interested in this as a signal that manifests may need to be re-indexed.","operationId":"IndexState","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/State"}}},"description":"Indexer State","headers":{"Etag":{"description":"Entity Tag","schema":{"type":"string"}}}},"304":{"description":"Indexer State Unchanged"}},"summary":"Report the indexer's internal configuration and state.","tags":["Indexer"]}},"/matcher/api/v1/vulnerability_report/{manifest_hash}":{"get":{"description":"Given a Manifest's content addressable hash a VulnerabilityReport will be created. The Manifest **must** have been Indexed first via the Index endpoint.","operationId":"GetVulnerabilityReport","parameters":[{"description":"A digest of a manifest that has been indexed previous to this request.","in":"path","name":"manifest_hash","required":true,"schema":{"$ref":"#/components/schemas/Digest"}}],"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VulnerabilityReport"}}},"description":"VulnerabilityReport Created"},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"500":{"$ref":"#/components/responses/InternalServerError"}},"summary":"Retrieve a VulnerabilityReport for a given manifest's content addressable hash.","tags":["Matcher"]}},"/notifier/api/v1/notification/{notification_id}":{"delete":{"description":"Issues a delete of the provided notification id and all associated notifications. After this delete clients will no longer be able to retrieve notifications.","operationId":"DeleteNotification","parameters":[{"description":"A notification ID returned by a callback","in":"path","name":"notification_id","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"400":{"$ref":"#/components/responses/BadRequest"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"500":{"$ref":"#/components/responses/InternalServerError"}},"tags":["Notifier"]},"get":{"description":"By performing a GET with a notification_id as a path parameter, the client will retrieve a paginated response of notification objects.","operationId":"GetNotification","parameters":[{"description":"A notification ID returned by a callback","in":"path","name":"notification_id","schema":{"type":"string"}},{"description":"The maximum number of notifications to deliver in a single page.","in":"query","name":"page_size","schema":{"type":"int"}},{"description":"The next page to fetch via id. Typically this number is provided on initial response in the page.next field. The first GET request may omit this field.","in":"query","name":"next","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagedNotifications"}}},"description":"A paginated list of notifications"},"400":{"$ref":"#/components/responses/BadRequest"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"500":{"$ref":"#/components/responses/InternalServerError"}},"summary":"Retrieve a paginated result of notifications for the provided id.","tags":["Notifier"]}}}}
\ No newline at end of file
diff --git a/httptransport/openapigen.go b/httptransport/openapigen.go
deleted file mode 100644
index 84146868d7..0000000000
--- a/httptransport/openapigen.go
+++ /dev/null
@@ -1,83 +0,0 @@
-//go:build tools
-// +build tools
-
-// Openapigen is a script to take the OpenAPI YAML file, turn it into a JSON
-// document, and write out files for use with the "embed" package.
-package main
-
-import (
- "bytes"
- "crypto/sha256"
- "encoding/json"
- "flag"
- "fmt"
- "io"
- "log"
- "os"
- "path/filepath"
-
- "gopkg.in/yaml.v3"
-)
-
-func main() {
- inFile := flag.String("in", "../openapi.yaml", "input YAML file")
- outDir := flag.String("out", ".", "output directory")
- flag.Parse()
-
- inF, err := os.Open(*inFile)
- if inF != nil {
- defer inF.Close()
- }
- if err != nil {
- log.Fatal(err)
- }
-
- tmp := map[interface{}]interface{}{}
- if err := yaml.NewDecoder(inF).Decode(&tmp); err != nil {
- log.Fatal(err)
- }
- embed, err := json.Marshal(convert(tmp))
- if err != nil {
- log.Fatal(err)
- }
- ck := sha256.Sum256(embed)
-
- outF, err := os.OpenFile(filepath.Join(*outDir, `openapi.json`), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
- if err != nil {
- log.Fatal(err)
- }
- defer outF.Close()
- if _, err := io.Copy(outF, bytes.NewReader(embed)); err != nil {
- log.Fatal(err)
- }
- outF, err = os.OpenFile(filepath.Join(*outDir, `openapi.etag`), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
- if err != nil {
- log.Fatal(err)
- }
- defer outF.Close()
- if _, err := fmt.Fprintf(outF, `"%x"`, ck); err != nil {
- log.Fatal(err)
- }
-}
-
-// Convert yoinked from:
-// https://stackoverflow.com/questions/40737122/convert-yaml-to-json-without-struct/40737676#40737676
-func convert(i interface{}) interface{} {
- switch x := i.(type) {
- case map[interface{}]interface{}:
- m2 := map[string]interface{}{}
- for k, v := range x {
- m2[fmt.Sprint(k)] = convert(v)
- }
- return m2
- case []interface{}:
- for i, v := range x {
- x[i] = convert(v)
- }
- case map[string]interface{}:
- for k, v := range x {
- x[k] = convert(v)
- }
- }
- return i
-}
diff --git a/httptransport/types/v1/affected_manifests.schema.json b/httptransport/types/v1/affected_manifests.schema.json
new file mode 100644
index 0000000000..1f12fee324
--- /dev/null
+++ b/httptransport/types/v1/affected_manifests.schema.json
@@ -0,0 +1,30 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/affected_manifests.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Affected Manifests",
+ "type": "object",
+ "description": "**This is an internal type, documented for completeness.**\n\nManifests affected by the specified vulnerability objects.",
+ "properties": {
+ "vulnerabilities": {
+ "type": "object",
+ "description": "Vulnerability objects.",
+ "additionalProperties": {
+ "$ref": "vulnerability.schema.json"
+ }
+ },
+ "vulnerable_manifests": {
+ "type": "object",
+ "description": "Mapping of manifest digests to vulnerability identifiers.",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "description": "An identifier to be used in the \"#/vulnerabilities\" object."
+ }
+ }
+ }
+ },
+ "required": [
+ "vulnerable_manifests"
+ ]
+}
diff --git a/httptransport/types/v1/bulk_delete.schema.json b/httptransport/types/v1/bulk_delete.schema.json
new file mode 100644
index 0000000000..9306e2c893
--- /dev/null
+++ b/httptransport/types/v1/bulk_delete.schema.json
@@ -0,0 +1,11 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/bulk_delete.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Bulk Delete",
+ "type": "array",
+ "description": "Array of manifest digests to delete from the system.",
+ "items": {
+ "$ref": "digest.schema.json",
+ "description": "Manifest digest to delete from the system."
+ }
+}
diff --git a/httptransport/types/v1/cpe.schema.json b/httptransport/types/v1/cpe.schema.json
new file mode 100644
index 0000000000..9b5a9aed81
--- /dev/null
+++ b/httptransport/types/v1/cpe.schema.json
@@ -0,0 +1,19 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/cpe.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Common Platform Enumeration Name",
+ "description": "This is a CPE Name in either v2.2 \"URI\" form or v2.3 \"Formatted String\" form.",
+ "$comment": "Clair only produces v2.3 CPE Names. Any v2.2 Names will be normalized into v2.3 form.",
+ "oneOf": [
+ {
+ "description": "This is the CPE 2.2 regexp: https://cpe.mitre.org/specification/2.2/cpe-language_2.2.xsd",
+ "type": "string",
+ "pattern": "^[c][pP][eE]:/[AHOaho]?(:[A-Za-z0-9\\._\\-~%]*){0,6}$"
+ },
+ {
+ "description": "This is the CPE 2.3 regexp: https://csrc.nist.gov/schema/cpe/2.3/cpe-naming_2.3.xsd",
+ "type": "string",
+ "pattern": "^cpe:2\\.3:[aho\\*\\-](:(((\\?*|\\*?)([a-zA-Z0-9\\-\\._]|(\\\\[\\\\\\*\\?!\"#$$%&'\\(\\)\\+,/:;<=>@\\[\\]\\^`\\{\\|}~]))+(\\?*|\\*?))|[\\*\\-])){5}(:(([a-zA-Z]{2,3}(-([a-zA-Z]{2}|[0-9]{3}))?)|[\\*\\-]))(:(((\\?*|\\*?)([a-zA-Z0-9\\-\\._]|(\\\\[\\\\\\*\\?!\"#$$%&'\\(\\)\\+,/:;<=>@\\[\\]\\^`\\{\\|}~]))+(\\?*|\\*?))|[\\*\\-])){4}$"
+ }
+ ]
+}
diff --git a/httptransport/types/v1/digest.schema.json b/httptransport/types/v1/digest.schema.json
new file mode 100644
index 0000000000..8ca37862ce
--- /dev/null
+++ b/httptransport/types/v1/digest.schema.json
@@ -0,0 +1,26 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/digest.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Digest",
+ "description": "A digest acts as a content identifier, enabling content addressability.",
+ "oneOf": [
+ {
+ "$comment": "SHA256: MUST be implemented",
+ "description": "SHA256",
+ "type": "string",
+ "pattern": "^sha256:[a-f0-9]{64}$"
+ },
+ {
+ "$comment": "SHA512: MAY be implemented",
+ "description": "SHA512",
+ "type": "string",
+ "pattern": "^sha512:[a-f0-9]{128}$"
+ },
+ {
+ "$comment": "BLAKE3: MAY be implemented",
+ "description": "BLAKE3\n\n**Currently not implemented.**",
+ "type": "string",
+ "pattern": "^blake3:[a-f0-9]{64}$"
+ }
+ ]
+}
diff --git a/httptransport/types/v1/distribution.schema.json b/httptransport/types/v1/distribution.schema.json
new file mode 100644
index 0000000000..fa473bb4f6
--- /dev/null
+++ b/httptransport/types/v1/distribution.schema.json
@@ -0,0 +1,49 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/distribution.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Distribution",
+ "type": "object",
+ "description": "Distribution is the accompanying system context of a Package.",
+ "properties": {
+ "id": {
+ "description": "Unique ID for this Distribution. May be unique to the response document, not the whole system.",
+ "type": "string"
+ },
+ "did": {
+ "description": "A lower-case string (no spaces or other characters outside of 0–9, a–z, \".\", \"_\", and \"-\") identifying the operating system, excluding any version information and suitable for processing by scripts or usage in generated filenames.",
+ "type": "string"
+ },
+ "name": {
+ "description": "A string identifying the operating system.",
+ "type": "string"
+ },
+ "version": {
+ "description": "A string identifying the operating system version, excluding any OS name information, possibly including a release code name, and suitable for presentation to the user.",
+ "type": "string"
+ },
+ "version_code_name": {
+ "description": "A lower-case string (no spaces or other characters outside of 0–9, a–z, \".\", \"_\", and \"-\") identifying the operating system release code name, excluding any OS name information or release version, and suitable for processing by scripts or usage in generated filenames.",
+ "type": "string"
+ },
+ "version_id": {
+ "description": "A lower-case string (mostly numeric, no spaces or other characters outside of 0–9, a–z, \".\", \"_\", and \"-\") identifying the operating system version, excluding any OS name information or release code name.",
+ "type": "string"
+ },
+ "arch": {
+ "description": "A string identifying the OS architecture.",
+ "type": "string"
+ },
+ "cpe": {
+ "description": "Common Platform Enumeration name.",
+ "$ref": "cpe.schema.json"
+ },
+ "pretty_name": {
+ "description": "A pretty operating system name in a format suitable for presentation to the user.",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "id"
+ ]
+}
diff --git a/httptransport/types/v1/environment.schema.json b/httptransport/types/v1/environment.schema.json
new file mode 100644
index 0000000000..20d7a5f0b8
--- /dev/null
+++ b/httptransport/types/v1/environment.schema.json
@@ -0,0 +1,29 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/environment.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Environment",
+ "type": "object",
+ "description": "Environment describes the surrounding environment a package was discovered in.",
+ "properties": {
+ "package_db": {
+ "description": "The database the associated Package was discovered in.",
+ "type": "string"
+ },
+ "distribution_id": {
+ "description": "The ID of the Distribution of the associated Package.",
+ "type": "string"
+ },
+ "introduced_in": {
+ "description": "The Layer the associated Package was introduced in.",
+ "$ref": "digest.schema.json"
+ },
+ "repository_ids": {
+ "description": "The IDs of the Repositories of the associated Package.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/httptransport/types/v1/error.schema.json b/httptransport/types/v1/error.schema.json
new file mode 100644
index 0000000000..ffb1209425
--- /dev/null
+++ b/httptransport/types/v1/error.schema.json
@@ -0,0 +1,20 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/error.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Error",
+ "type": "object",
+ "description": "A general error response.",
+ "properties": {
+ "code": {
+ "type": "string",
+ "description": "a code for this particular error"
+ },
+ "message": {
+ "type": "string",
+ "description": "a message with further detail"
+ }
+ },
+ "required": [
+ "message"
+ ]
+}
diff --git a/httptransport/types/v1/index_report.schema.json b/httptransport/types/v1/index_report.schema.json
new file mode 100644
index 0000000000..f6fbb17f3f
--- /dev/null
+++ b/httptransport/types/v1/index_report.schema.json
@@ -0,0 +1,62 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/index_report.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Index Report",
+ "type": "object",
+ "description": "An index of the contents of a Manifest.",
+ "properties": {
+ "manifest_hash": {
+ "$ref": "digest.schema.json",
+ "description": "The Manifest's digest."
+ },
+ "state": {
+ "type": "string",
+ "description": "The current state of the index operation"
+ },
+ "err": {
+ "type": "string",
+ "description": "An error message on event of unsuccessful index"
+ },
+ "success": {
+ "type": "boolean",
+ "description": "A bool indicating succcessful index"
+ },
+ "packages": {
+ "type": "object",
+ "description": "A map of Package objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "package.schema.json"
+ }
+ },
+ "distributions": {
+ "type": "object",
+ "description": "A map of Distribution objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "distribution.schema.json"
+ }
+ },
+ "repository": {
+ "type": "object",
+ "description": "A map of Repository objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "repository.schema.json"
+ }
+ },
+ "environments": {
+ "type": "object",
+ "description": "A map of Environment arrays indexed by a Package's identifier.",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "$ref": "environment.schema.json"
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "manifest_hash",
+ "state",
+ "success"
+ ]
+}
diff --git a/httptransport/types/v1/index_state.schema.json b/httptransport/types/v1/index_state.schema.json
new file mode 100644
index 0000000000..19645519cb
--- /dev/null
+++ b/httptransport/types/v1/index_state.schema.json
@@ -0,0 +1,16 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/index_state.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Index State",
+ "type": "object",
+ "description": "Information on the state of the indexer system.",
+ "properties": {
+ "state": {
+ "type": "string",
+ "description": "an opaque token"
+ }
+ },
+ "required": [
+ "state"
+ ]
+}
diff --git a/httptransport/types/v1/layer.schema.json b/httptransport/types/v1/layer.schema.json
new file mode 100644
index 0000000000..f69f81aac0
--- /dev/null
+++ b/httptransport/types/v1/layer.schema.json
@@ -0,0 +1,39 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/layer.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Layer",
+ "type": "object",
+ "description": "Layer is a description of a container layer. It should contain enough information to fetch the layer.",
+ "properties": {
+ "hash": {
+ "$ref": "digest.schema.json",
+ "description": "Digest of the layer blob."
+ },
+ "uri": {
+ "type": "string",
+ "description": "A URI indicating where the layer blob can be downloaded from."
+ },
+ "headers": {
+ "description": "Any additional HTTP-style headers needed for requesting layers.",
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\-_]+$": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "media_type": {
+ "description": "The OCI Layer media type for this layer.",
+ "type": "string",
+ "pattern": "^application/vnd\\.oci\\.image\\.layer\\.v1\\.tar(\\+(gzip|zstd))?$"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "hash",
+ "uri"
+ ]
+}
diff --git a/httptransport/types/v1/manifest.schema.json b/httptransport/types/v1/manifest.schema.json
new file mode 100644
index 0000000000..15face0a91
--- /dev/null
+++ b/httptransport/types/v1/manifest.schema.json
@@ -0,0 +1,24 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/manifest.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Manifest",
+ "type": "object",
+ "description": "A description of an OCI Image Manifest.",
+ "properties": {
+ "hash": {
+ "$ref": "digest.schema.json",
+ "description": "The OCI Image Manifest's digest.\n\nThis is used as an identifier throughout the system. This **SHOULD** be the same as the OCI Image Manifest's digest, but this is not enforced."
+ },
+ "layers": {
+ "type": "array",
+ "description": "The OCI Layers making up the Image, in order.",
+ "items": {
+ "$ref": "layer.schema.json"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "hash"
+ ]
+}
diff --git a/httptransport/types/v1/normalized_severity.schema.json b/httptransport/types/v1/normalized_severity.schema.json
new file mode 100644
index 0000000000..c3ef09d055
--- /dev/null
+++ b/httptransport/types/v1/normalized_severity.schema.json
@@ -0,0 +1,14 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/normalized_severity.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Normalized Severity",
+ "description": "Standardized severity values.",
+ "enum": [
+ "Unknown",
+ "Negligible",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+}
diff --git a/httptransport/types/v1/notification.schema.json b/httptransport/types/v1/notification.schema.json
new file mode 100644
index 0000000000..d9deb2d665
--- /dev/null
+++ b/httptransport/types/v1/notification.schema.json
@@ -0,0 +1,34 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/notification.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Notification",
+ "type": "object",
+ "description": "A change in a manifest affected by a vulnerability.",
+ "properties": {
+ "id": {
+ "description": "Unique identifier for this notification.",
+ "type": "string"
+ },
+ "manifest": {
+ "$ref": "digest.schema.json",
+ "description": "The digest of the manifest affected by the provided vulnerability."
+ },
+ "reason": {
+ "description": "The reason for the notifcation.",
+ "enum": [
+ "added",
+ "removed"
+ ]
+ },
+ "vulnerability": {
+ "$ref": "vulnerability_summary.schema.json"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "manifest",
+ "reason",
+ "vulnerability"
+ ]
+}
diff --git a/httptransport/types/v1/notification_page.schema.json b/httptransport/types/v1/notification_page.schema.json
new file mode 100644
index 0000000000..8a01866856
--- /dev/null
+++ b/httptransport/types/v1/notification_page.schema.json
@@ -0,0 +1,44 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/notification_page.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Notification Page",
+ "type": "object",
+ "description": "A page description and list of notifications.",
+ "properties": {
+ "page": {
+ "description": "An object informing the client the next page to retrieve.",
+ "type": "object",
+ "properties": {
+ "size": {
+ "type": "integer"
+ },
+ "next": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "const": "-1"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "size"
+ ]
+ },
+ "notifications": {
+ "description": "Notifications within this page.",
+ "type": "array",
+ "items": {
+ "$ref": "notification.schema.json"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "page",
+ "notifications"
+ ]
+}
diff --git a/httptransport/types/v1/package.schema.json b/httptransport/types/v1/package.schema.json
new file mode 100644
index 0000000000..a4a54cd9af
--- /dev/null
+++ b/httptransport/types/v1/package.schema.json
@@ -0,0 +1,55 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/package.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Package",
+ "type": "object",
+ "description": "Description of installed software.",
+ "properties": {
+ "id": {
+ "description": "Unique ID for this Package. May be unique to the response document, not the whole system.",
+ "type": "string"
+ },
+ "name": {
+ "description": "Identifier of this Package.\n\nThe uniqueness and scoping of this name depends on the packaging system.",
+ "type": "string"
+ },
+ "version": {
+ "description": "Version of this Package, as reported by the packaging system.",
+ "type": "string"
+ },
+ "kind": {
+ "description": "The \"kind\" of this Package.",
+ "enum": [
+ "BINARY",
+ "SOURCE"
+ ],
+ "default": "BINARY"
+ },
+ "source": {
+ "$ref": "#",
+ "description": "Source Package that produced the current binary Package, if known."
+ },
+ "normalized_version": {
+ "description": "Normalized representation of the discoverd version.\n\nThe format is not specific, but is guarenteed to be forward compatible.",
+ "type": "string"
+ },
+ "module": {
+ "description": "An identifier for intra-Repository grouping of packages.\n\nLikely only relevant on rpm-based systems.",
+ "type": "string"
+ },
+ "arch": {
+ "description": "Native architecture for the Package.",
+ "type": "string",
+ "$comment": "This should become and enum in the future."
+ },
+ "cpe": {
+ "$ref": "cpe.schema.json",
+ "description": "CPE Name for the Package."
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "name",
+ "version"
+ ]
+}
diff --git a/httptransport/types/v1/range.schema.json b/httptransport/types/v1/range.schema.json
new file mode 100644
index 0000000000..924a430f80
--- /dev/null
+++ b/httptransport/types/v1/range.schema.json
@@ -0,0 +1,19 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/range.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Range",
+ "type": "object",
+ "description": "A range of versions.",
+ "properties": {
+ "[": {
+ "type": "string",
+ "description": "Lower bound, inclusive."
+ },
+ ")": {
+ "type": "string",
+ "description": "Upper bound, exclusive."
+ }
+ },
+ "minProperties": 1,
+ "additionalProperties": false
+}
diff --git a/httptransport/types/v1/repository.schema.json b/httptransport/types/v1/repository.schema.json
new file mode 100644
index 0000000000..1bb0bd9410
--- /dev/null
+++ b/httptransport/types/v1/repository.schema.json
@@ -0,0 +1,34 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/repository.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Repository",
+ "type": "object",
+ "description": "Description of a software repository",
+ "properties": {
+ "id": {
+ "description": "Unique ID for this Repository. May be unique to the response document, not the whole system.",
+ "type": "string"
+ },
+ "name": {
+ "description": "Human-relevant name for the Repository.",
+ "type": "string"
+ },
+ "key": {
+ "description": "Machine-relevant name for the Repository.",
+ "type": "string"
+ },
+ "uri": {
+ "description": "URI describing the Repository.",
+ "type": "string",
+ "format": "uri"
+ },
+ "cpe": {
+ "description": "CPE name for the Repository.",
+ "$ref": "cpe.schema.json"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "id"
+ ]
+}
diff --git a/httptransport/types/v1/types.go b/httptransport/types/v1/types.go
new file mode 100644
index 0000000000..a0f14687bb
--- /dev/null
+++ b/httptransport/types/v1/types.go
@@ -0,0 +1,157 @@
+// Package types provides concrete types for the HTTP API.
+package types
+
+import (
+ "embed"
+ "encoding/json"
+ "fmt"
+ "time"
+)
+
+//go:embed *.schema.json
+var Schema embed.FS
+
+// Indexer types
+type (
+ Manifest struct {
+ Hash string `json:"hash"`
+ Layers []Layer `json:"layers,omitempty"`
+ }
+
+ Layer struct {
+ Hash string `json:"hash"`
+ URI string `json:"uri"`
+ Headers map[string][]string `json:"headers,omitempty"`
+ }
+
+ IndexReport struct {
+ Hash string `json:"manifest_hash"`
+ State string `json:"state"`
+ Err string `json:"err,omitempty"`
+ Packages map[string]*Package `json:"packages,omitempty"`
+ Distributions map[string]*Distribution `json:"distributions,omitempty"`
+ Repositories map[string]*Repository `json:"repository,omitempty"`
+ Environments map[string][]*Environment `json:"environments,omitempty"`
+ Success bool `json:"success"`
+ }
+
+ Package struct {
+ ID string `json:"id"`
+ Name string `json:"name,omitempty"`
+ Version string `json:"version,omitempty"`
+ Kind string `json:"kind,omitempty"`
+ Source *Package `json:"source,omitempty"`
+ NormalizedVersion string `json:"normalized_version,omitempty"`
+ Module string `json:"module,omitempty"`
+ Arch string `json:"arch,omitempty"`
+ CPE string `json:"cpe,omitempty"`
+ }
+
+ Distribution struct {
+ ID string `json:"id"`
+ DID string `json:"did,omitempty"`
+ Name string `json:"name,omitempty"`
+ Version string `json:"version,omitempty"`
+ VersionCodeName string `json:"version_code_name,omitempty"`
+ VersionID string `json:"version_id,omitempty"`
+ Arch string `json:"arch,omitempty"`
+ CPE string `json:"cpe,omitempty"`
+ PrettyName string `json:"pretty_name,omitempty"`
+ }
+
+ Repository struct {
+ ID string `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+ Key string `json:"key,omitempty"`
+ URI string `json:"uri,omitempty"`
+ CPE string `json:"cpe,omitempty"`
+ }
+
+ Environment struct {
+ IntroducedIn string `json:"introduced_in"`
+ PackageDB string `json:"package_db,omitempty"`
+ DistributionID string `json:"distribution_id,omitempty"`
+ RepositoryIDs []string `json:"repository_ids,omitempty"`
+ }
+
+ IndexerState struct {
+ State string
+ }
+
+ VulnerabilityBatch struct {
+ Vulnerabilities []Vulnerability
+ }
+)
+
+// Matcher types
+type (
+ VulnerabilityReport struct {
+ Hash string `json:"manifest_hash"`
+ Packages map[string]*Package `json:"packages,omitempty"`
+ Vulnerabilities map[string]*Vulnerability `json:"vulnerabilities,omitempty"`
+ Environments map[string][]*Environment `json:"environments,omitempty"`
+ PackageVulnerabilities map[string][]string `json:"package_vulnerabilities,omitempty"`
+ Distributions map[string]*Distribution `json:"distributions,omitempty"`
+ Repositories map[string]*Repository `json:"repository,omitempty"`
+ Enrichments map[string][]json.RawMessage `json:"enrichments,omitempty"`
+ }
+
+ Vulnerability struct {
+ ID string `json:"id"`
+ Updater string `json:"updater,omitempty"`
+ Name string `json:"name,omitempty"`
+ Issued time.Time `json:"issued"`
+ Severity string `json:"severity,omitempty"`
+ NormalizedSeverity string `json:"normalized_severity,omitempty"`
+ Description string `json:"description,omitempty"`
+ Links string `json:"links,omitempty"`
+ Package *Package `json:"package,omitempty"`
+ Dist *Distribution `json:"distribution,omitempty"`
+ Repo *Repository `json:"repository,omitempty"`
+ FixedInVersion string `json:"fixed_in_version"`
+ Range *Range `json:"range,omitempty"`
+ ArchOperation string `json:"arch_op,omitempty"`
+ }
+
+ Range struct {
+ Lower string `json:"[,omitempty"`
+ Upper string `json:"),omitempty"`
+ }
+
+ UpdateKind int
+
+ UpdateOperation struct {
+ Ref string `json:"ref"`
+ Updater string `json:"updater"`
+ Fingerprint []byte `json:"fingerprint"`
+ Date time.Time `json:"date"`
+ Kind UpdateKind `json:"kind"`
+ }
+
+ UpdateDiff struct {
+ Prev UpdateOperation `json:"prev"`
+ Cur UpdateOperation `json:"cur"`
+ Added []Vulnerability `json:"added"`
+ Removed []Vulnerability `json:"removed"`
+ }
+)
+
+//go:generate go run golang.org/x/tools/cmd/stringer@latest -type UpdateKind -linecomment
+
+const (
+ _ UpdateKind = iota
+ UpdateVulnerability // vulnerability
+ UpdateEnrichment // enrichment
+)
+
+// API types
+type (
+ Error struct {
+ Code int
+ Message string
+ }
+)
+
+func (e *Error) Error() string {
+ return fmt.Sprintf("%s (HTTP %d)", e.Message, e.Code)
+}
diff --git a/httptransport/types/v1/update_diff.schema.json b/httptransport/types/v1/update_diff.schema.json
new file mode 100644
index 0000000000..6986db50b8
--- /dev/null
+++ b/httptransport/types/v1/update_diff.schema.json
@@ -0,0 +1,9 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/update_diff.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Update Difference",
+ "type": "object",
+ "description": "**This is an internal type, documented for completeness.**\n\nTKTK",
+ "additionalProperties": false,
+ "required": [ ]
+}
diff --git a/httptransport/types/v1/updatekind_string.go b/httptransport/types/v1/updatekind_string.go
new file mode 100644
index 0000000000..39d8627236
--- /dev/null
+++ b/httptransport/types/v1/updatekind_string.go
@@ -0,0 +1,25 @@
+// Code generated by "stringer -type UpdateKind -linecomment"; DO NOT EDIT.
+
+package types
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[UpdateVulnerability-1]
+ _ = x[UpdateEnrichment-2]
+}
+
+const _UpdateKind_name = "vulnerabilityenrichment"
+
+var _UpdateKind_index = [...]uint8{0, 13, 23}
+
+func (i UpdateKind) String() string {
+ i -= 1
+ if i < 0 || i >= UpdateKind(len(_UpdateKind_index)-1) {
+ return "UpdateKind(" + strconv.FormatInt(int64(i+1), 10) + ")"
+ }
+ return _UpdateKind_name[_UpdateKind_index[i]:_UpdateKind_index[i+1]]
+}
diff --git a/httptransport/types/v1/vulnerability.schema.json b/httptransport/types/v1/vulnerability.schema.json
new file mode 100644
index 0000000000..2cb9f7501c
--- /dev/null
+++ b/httptransport/types/v1/vulnerability.schema.json
@@ -0,0 +1,36 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/vulnerability.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Vulnerability",
+ "type": "object",
+ "description": "Description of a software flaw.",
+ "$ref": "vulnerability_core.schema.json",
+ "properties": {
+ "id": {
+ "description": "",
+ "type": "string"
+ },
+ "updater": {
+ "description": "",
+ "type": "string"
+ },
+ "description": {
+ "description": "",
+ "type": "string"
+ },
+ "issued": {
+ "description": "",
+ "type": "string",
+ "format": "date-time"
+ },
+ "links": {
+ "description": "",
+ "type": "string"
+ }
+ },
+ "unevaluatedProperties": false,
+ "required": [
+ "id",
+ "updater"
+ ]
+}
diff --git a/httptransport/types/v1/vulnerability_core.schema.json b/httptransport/types/v1/vulnerability_core.schema.json
new file mode 100644
index 0000000000..b5f665b97d
--- /dev/null
+++ b/httptransport/types/v1/vulnerability_core.schema.json
@@ -0,0 +1,75 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/vulnerability_core.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Vulnerability Core",
+ "type": "object",
+ "description": "The core elements of vulnerabilities in the Clair system.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Human-readable name, as presented in the vendor data."
+ },
+ "fixed_in_version": {
+ "type": "string",
+ "description": "Version string, as presented in the vendor data."
+ },
+ "severity": {
+ "type": "string",
+ "description": "Severity, as presented in the vendor data."
+ },
+ "normalized_severity": {
+ "$ref": "normalized_severity.schema.json",
+ "description": "A well defined set of severity strings guaranteed to be present."
+ },
+ "range": {
+ "$ref": "range.schema.json",
+ "description": "Range of versions the vulnerability applies to."
+ },
+ "arch_op": {
+ "description": "Flag indicating how the referenced package's \"arch\" member should be interpreted.",
+ "enum": [
+ "equals",
+ "not equals",
+ "pattern match"
+ ]
+ },
+ "package": {
+ "$ref": "package.schema.json",
+ "description": "A package description"
+ },
+ "distribution": {
+ "$ref": "distribution.schema.json",
+ "description": "A distribution description"
+ },
+ "repository": {
+ "$ref": "repository.schema.json",
+ "description": "A repository description"
+ }
+ },
+ "required": [
+ "name",
+ "normalized_severity"
+ ],
+ "dependentRequired": {
+ "package": [
+ "arch_op"
+ ]
+ },
+ "anyOf": [
+ {
+ "required": [
+ "package"
+ ]
+ },
+ {
+ "required": [
+ "repository"
+ ]
+ },
+ {
+ "required": [
+ "distribution"
+ ]
+ }
+ ]
+}
diff --git a/httptransport/types/v1/vulnerability_report.schema.json b/httptransport/types/v1/vulnerability_report.schema.json
new file mode 100644
index 0000000000..8f2658560d
--- /dev/null
+++ b/httptransport/types/v1/vulnerability_report.schema.json
@@ -0,0 +1,77 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/vulnerability_report.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Vulnerability Report",
+ "type": "object",
+ "description": "A report with discovered packages, package environments, and package vulnerabilities within a Manifest.",
+ "properties": {
+ "manifest_hash": {
+ "$ref": "digest.schema.json",
+ "description": "The Manifest's digest."
+ },
+ "packages": {
+ "type": "object",
+ "description": "A map of Package objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "package.schema.json"
+ }
+ },
+ "distributions": {
+ "type": "object",
+ "description": "A map of Distribution objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "distribution.schema.json"
+ }
+ },
+ "repository": {
+ "type": "object",
+ "description": "A map of Repository objects indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "repository.schema.json"
+ }
+ },
+ "environments": {
+ "type": "object",
+ "description": "A map of Environment arrays indexed by a Package's identifier.",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "$ref": "environment.schema.json"
+ }
+ }
+ },
+ "vulnerabilities": {
+ "type": "object",
+ "description": "A map of Vulnerabilities indexed by a document-local identifier.",
+ "additionalProperties": {
+ "$ref": "vulnerability.schema.json"
+ }
+ },
+ "package_vulnerabilities": {
+ "type": "object",
+ "description": "A mapping of Vulnerability identifier lists indexed by Package identifier.",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "enrichments": {
+ "type": "object",
+ "description": "A mapping of extra \"enrichment\" data by type",
+ "additionalProperties": {
+ "type": "array"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "distributions",
+ "environments",
+ "manifest_hash",
+ "packages",
+ "package_vulnerabilities",
+ "vulnerabilities"
+ ]
+}
diff --git a/httptransport/types/v1/vulnerability_summary.schema.json b/httptransport/types/v1/vulnerability_summary.schema.json
new file mode 100644
index 0000000000..8fac0115e5
--- /dev/null
+++ b/httptransport/types/v1/vulnerability_summary.schema.json
@@ -0,0 +1,9 @@
+{
+ "$id": "https://clairproject.org/api/http/v1/vulnerability_summary.schema.json",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Vulnerability Summary",
+ "type": "object",
+ "description": "A summary of a vulnerability.",
+ "$ref": "vulnerability_core.schema.json",
+ "unevaluatedProperties": false
+}
diff --git a/openapi.yaml b/openapi.yaml
deleted file mode 100644
index 81fab1f116..0000000000
--- a/openapi.yaml
+++ /dev/null
@@ -1,934 +0,0 @@
----
-openapi: "3.0.2"
-info:
- title: "ClairV4"
- description: >-
- ClairV4 is a set of cooperating microservices which scan, index, and
- match your container's content with known vulnerabilities.
- version: "1.1"
- termsOfService: ""
- contact:
- name: "Clair Team"
- url: "http://github.com/quay/clair"
- email: "quay-devel@redhat.com"
- license:
- name: "Apache License 2.0"
- url: "http://www.apache.org/licenses/"
-
-paths:
- /notifier/api/v1/notification/{notification_id}:
- delete:
- tags:
- - Notifier
- operationId: "DeleteNotification"
- description: >-
- Issues a delete of the provided notification id and all associated
- notifications. After this delete clients will no longer be able to
- retrieve notifications.
- parameters:
- - in: path
- name: notification_id
- schema:
- type: string
- description: "A notification ID returned by a callback"
- responses:
- 200:
- description: "OK"
- 400:
- $ref: '#/components/responses/BadRequest'
- 405:
- $ref: '#/components/responses/MethodNotAllowed'
- 500:
- $ref: '#/components/responses/InternalServerError'
- get:
- tags:
- - Notifier
- operationId: "GetNotification"
- summary: Retrieve a paginated result of notifications for the provided id.
- description: >-
- By performing a GET with a notification_id as a path parameter, the
- client will retrieve a paginated response of notification objects.
- parameters:
- - in: path
- name: notification_id
- schema:
- type: string
- description: "A notification ID returned by a callback"
- - in: query
- name: page_size
- schema:
- type: int
- description: >-
- The maximum number of notifications to deliver in a single page.
- - in: query
- name: next
- schema:
- type: string
- description: >-
- The next page to fetch via id. Typically this number is provided
- on initial response in the page.next field.
- The first GET request may omit this field.
- responses:
- 200:
- description: "A paginated list of notifications"
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/PagedNotifications'
- 400:
- $ref: '#/components/responses/BadRequest'
- 405:
- $ref: '#/components/responses/MethodNotAllowed'
- 500:
- $ref: '#/components/responses/InternalServerError'
-
- /indexer/api/v1/index_report:
- post:
- tags:
- - Indexer
- operationId: "Index"
- summary: "Index the contents of a Manifest"
- description: >-
- By submitting a Manifest object to this endpoint Clair will fetch the
- layers, scan each layer's contents, and provide an index of discovered
- packages, repository and distribution information.
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Manifest'
- responses:
- 201:
- description: IndexReport Created
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/IndexReport'
- 400:
- $ref: '#/components/responses/BadRequest'
- 405:
- $ref: '#/components/responses/MethodNotAllowed'
- 500:
- $ref: '#/components/responses/InternalServerError'
- delete:
- tags:
- - Indexer
- operationId: "DeleteManifests"
- summary: >-
- Delete the IndexReport and associated information for the given
- Manifest hashes, if they exist.
- description: >-
- Given a Manifest's content addressable hash, any data related to it
- will be removed if it exists.
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/BulkDelete'
- responses:
- 200:
- description: "OK"
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/BulkDelete'
- 400:
- $ref: '#/components/responses/BadRequest'
- 500:
- $ref: '#/components/responses/InternalServerError'
-
- /indexer/api/v1/index_report/{manifest_hash}:
- delete:
- tags:
- - Indexer
- operationId: "DeleteManifest"
- summary: >-
- Delete the IndexReport and associated information for the given
- Manifest hash, if exists.
- description: >-
- Given a Manifest's content addressable hash, any data related to it
- will be removed it it exists.
- parameters:
- - name: manifest_hash
- in: path
- description: >-
- A digest of a manifest that has been indexed previous to this
- request.
- required: true
- schema:
- $ref: '#/components/schemas/Digest'
- responses:
- 204:
- description: "OK"
- 400:
- $ref: '#/components/responses/BadRequest'
- 500:
- $ref: '#/components/responses/InternalServerError'
- get:
- tags:
- - Indexer
- operationId: "GetIndexReport"
- summary: "Retrieve an IndexReport for the given Manifest hash if exists."
- description: >-
- Given a Manifest's content addressable hash an IndexReport will
- be retrieved if exists.
- parameters:
- - name: manifest_hash
- in: path
- description: >-
- A digest of a manifest that has been indexed previous to this
- request.
- required: true
- schema:
- $ref: '#/components/schemas/Digest'
- responses:
- 200:
- description: IndexReport retrieved
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/IndexReport'
- 400:
- $ref: '#/components/responses/BadRequest'
- 404:
- $ref: '#/components/responses/NotFound'
- 405:
- $ref: '#/components/responses/MethodNotAllowed'
- 500:
- $ref: '#/components/responses/InternalServerError'
-
- /matcher/api/v1/vulnerability_report/{manifest_hash}:
- get:
- tags:
- - Matcher
- operationId: "GetVulnerabilityReport"
- summary: >-
- Retrieve a VulnerabilityReport for a given manifest's content
- addressable hash.
- description: >-
- Given a Manifest's content addressable hash a VulnerabilityReport
- will be created. The Manifest **must** have been Indexed first
- via the Index endpoint.
- parameters:
- - name: manifest_hash
- in: path
- description: >-
- A digest of a manifest that has been indexed previous to this
- request.
- required: true
- schema:
- $ref: '#/components/schemas/Digest'
- responses:
- 201:
- description: VulnerabilityReport Created
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/VulnerabilityReport'
- 400:
- $ref: '#/components/responses/BadRequest'
- 404:
- $ref: '#/components/responses/NotFound'
- 405:
- $ref: '#/components/responses/MethodNotAllowed'
- 500:
- $ref: '#/components/responses/InternalServerError'
-
- /indexer/api/v1/index_state:
- get:
- tags:
- - Indexer
- operationId: IndexState
- summary: Report the indexer's internal configuration and state.
- description: >-
- The index state endpoint returns a json structure indicating the
- indexer's internal configuration state.
-
- A client may be interested in this as a signal that manifests may need
- to be re-indexed.
- responses:
- 200:
- description: Indexer State
- headers:
- Etag:
- description: 'Entity Tag'
- schema: {type: string}
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/State'
- 304:
- description: Indexer State Unchanged
-
-components:
- responses:
- BadRequest:
- description: Bad Request
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
-
- MethodNotAllowed:
- description: Method Not Allowed
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
-
- InternalServerError:
- description: Internal Server Error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
-
- NotFound:
- description: Not Found
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/Error'
-
- examples:
- Environment:
- value:
- package_db: "var/lib/dpkg/status"
- introduced_in: >-
- sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a
- distribution_id: "1"
-
- Vulnerability:
- value:
- id: "356835"
- updater: ""
- name: "CVE-2009-5155"
- description: >-
- In the GNU C Library (aka glibc or libc6) before 2.28,
- parse_reg_exp in posix/regcomp.c misparses alternatives,
- which allows attackers to cause a denial of service (assertion
- failure and application exit) or trigger an incorrect result
- by attempting a regular-expression match."
- links: >-
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-5155
- http://people.canonical.com/~ubuntu-security/cve/2009/CVE-2009-5155.html
- https://sourceware.org/bugzilla/show_bug.cgi?id=11053
- https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22793
- https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32806
- https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34238
- https://sourceware.org/bugzilla/show_bug.cgi?id=18986"
- severity: "Low"
- normalized_severity: "Low"
- package:
- id: "0"
- name: "glibc"
- version: ""
- kind: ""
- source: null
- package_db: ""
- repository_hint: ""
- dist:
- id: "0"
- did: "ubuntu"
- name: "Ubuntu"
- version: "18.04.3 LTS (Bionic Beaver)"
- version_code_name: "bionic"
- version_id: "18.04"
- arch: ""
- cpe: ""
- pretty_name: ""
- repo:
- id: "0"
- name: "Ubuntu 18.04.3 LTS"
- key: ""
- uri: ""
- issued: "2019-10-12T07:20:50.52Z"
- fixed_in_version: "2.28-0ubuntu1"
-
- Distribution:
- value:
- id: "1"
- did: "ubuntu"
- name: "Ubuntu"
- version: "18.04.3 LTS (Bionic Beaver)"
- version_code_name: "bionic"
- version_id: "18.04"
- arch: ""
- cpe: ""
- pretty_name: "Ubuntu 18.04.3 LTS"
-
- Package:
- value:
- id: "10"
- name: "libapt-pkg5.0"
- version: "1.6.11"
- kind: "binary"
- normalized_version: ""
- arch: "x86"
- module: ""
- cpe: ""
- source:
- id: "9"
- name: "apt"
- version: "1.6.11"
- kind: "source"
- source: null
-
- VulnSummary:
- value:
- name: "CVE-2009-5155"
- description: >-
- In the GNU C Library (aka glibc or libc6) before 2.28,
- parse_reg_exp in posix/regcomp.c misparses alternatives,
- which allows attackers to cause a denial of service (assertion
- failure and application exit) or trigger an incorrect result
- by attempting a regular-expression match."
- normalized_severity: "Low"
- fixed_in_version: "v0.0.1"
- links: "http://link-to-advisory"
- package:
- id: "0"
- name: "glibc"
- version: ""
- kind: ""
- source: null
- package_db: ""
- repository_hint: ""
- dist:
- id: "0"
- did: "ubuntu"
- name: "Ubuntu"
- version: "18.04.3 LTS (Bionic Beaver)"
- version_code_name: "bionic"
- version_id: "18.04"
- arch: ""
- cpe: ""
- pretty_name: ""
- repo:
- id: "0"
- name: "Ubuntu 18.04.3 LTS"
- key: ""
- uri: ""
-
- schemas:
- Page:
- title: Page
- description: >-
- A page object indicating to the client how to retrieve multiple pages of
- a particular entity.
- properties:
- size:
- description: "The maximum number of elements in a page"
- type: int
- example: 1
- next:
- description: "The next id to submit to the api to continue paging"
- type: string
- example: "1b4d0db2-e757-4150-bbbb-543658144205"
-
- PagedNotifications:
- title: PagedNotifications
- type: object
- description: "A page object followed by a list of notifications"
- properties:
- page:
- description: >-
- A page object informing the client the next page to retrieve.
- If page.next becomes "-1" the client should stop paging.
- type: object
- example:
- size: 100
- next: "1b4d0db2-e757-4150-bbbb-543658144205"
- notifications:
- description: "A list of notifications within this page"
- type: array
- items:
- $ref: '#/components/schemas/Notification'
-
- Callback:
- title: Callback
- type: object
- description: "A callback for clients to retrieve notifications"
- properties:
- notification_id:
- description: "the unique identifier for this set of notifications"
- type: string
- example: "269886f3-0146-4f08-9bf7-cb1138d48643"
- callback:
- description: "the url where notifications can be retrieved"
- type: string
- example: >-
- http://clair-notifier/notifier/api/v1/notification/269886f3-0146-4f08-9bf7-cb1138d48643
-
- VulnSummary:
- title: VulnSummary
- type: object
- description: "A summary of a vulnerability"
- properties:
- name:
- description: "the vulnerability name"
- type: string
- example: "CVE-2009-5155"
- fixed_in_version:
- description: >-
- The version which the vulnerability is fixed in. Empty if not fixed.
- type: string
- example: "v0.0.1"
- links:
- description: "links to external information about vulnerability"
- type: string
- example: "http://link-to-advisory"
- description:
- description: "the vulnerability name"
- type: string
- example: >-
- In the GNU C Library (aka glibc or libc6) before 2.28,
- parse_reg_exp in posix/regcomp.c misparses alternatives,
- which allows attackers to cause a denial of service (assertion
- failure and application exit) or trigger an incorrect result
- by attempting a regular-expression match."
- normalized_severity:
- description: >-
- A well defined set of severity strings guaranteed to be present.
- type: string
- enum: [Unknown, Negligible, Low, Medium, High, Critical]
- package:
- $ref: '#/components/schemas/Package'
- distribution:
- $ref: '#/components/schemas/Distribution'
- repository:
- $ref: '#/components/schemas/Repository'
-
- Notification:
- title: Notification
- type: object
- description: >-
- A notification expressing a change in a manifest affected by a
- vulnerability.
- properties:
- id:
- description: "a unique identifier for this notification"
- type: string
- example: "5e4b387e-88d3-4364-86fd-063447a6fad2"
- manifest:
- description: >-
- The hash of the manifest affected by the provided vulnerability.
- type: string
- example: >-
- sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a
- reason:
- description: "the reason for the notifcation, [added | removed]"
- type: string
- example: "added"
- vulnerability:
- $ref: '#/components/schemas/VulnSummary'
-
- Environment:
- title: Environment
- type: object
- description: "The environment a particular package was discovered in."
- properties:
- package_db:
- description: >-
- The filesystem path or unique identifier of a package database.
- type: string
- example: "var/lib/dpkg/status"
- introduced_in:
- $ref: '#/components/schemas/Digest'
- distribution_id:
- description: >-
- The distribution ID found in an associated IndexReport or
- VulnerabilityReport.
- type: string
- example: "1"
- required:
- - package_db
- - introduced_in
- - distribution_id
-
- IndexReport:
- title: IndexReport
- type: object
- description: >-
- A report of the Index process for a particular manifest. A
- client's usage of this is largely information. Clair uses this
- report for matching Vulnerabilities.
- properties:
- manifest_hash:
- $ref: '#/components/schemas/Digest'
- state:
- description: "The current state of the index operation"
- type: string
- example: "IndexFinished"
- packages:
- type: object
- description: "A map of Package objects indexed by Package.id"
- example:
- "10":
- $ref: '#/components/examples/Package/value'
- additionalProperties:
- $ref: '#/components/schemas/Package'
- distributions:
- type: object
- description: >-
- A map of Distribution objects keyed by their Distribution.id
- discovered in the manifest.
- example:
- "1":
- $ref: '#/components/examples/Distribution/value'
- additionalProperties:
- $ref: '#/components/schemas/Distribution'
- environments:
- type: object
- description: >-
- A map of lists containing Environment objects keyed by the
- associated Package.id.
- example:
- "10":
- # swagger bug does not allow inline reference here -_-
- # - $ref: '#/components/examples/Environment/value'
- - package_db: "var/lib/dpkg/status"
- introduced_in: >-
- sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a
- distribution_id: "1"
-
- additionalProperties:
- type: array
- items:
- $ref: '#/components/schemas/Environment'
- success:
- type: boolean
- description: "A bool indicating succcessful index"
- example: true
- err:
- type: string
- description: "An error message on event of unsuccessful index"
- example: ""
- required:
- - manifest_hash
- - state
- - packages
- - distributions
- - environments
- - success
- - err
-
- VulnerabilityReport:
- title: VulnerabilityReport
- type: object
- description: >-
- A report expressing discovered packages, package environments,
- and package vulnerabilities within a Manifest.
- properties:
- manifest_hash:
- $ref: '#/components/schemas/Digest'
- packages:
- type: object
- description: "A map of Package objects indexed by Package.id"
- example:
- "10":
- $ref: '#/components/examples/Package/value'
- additionalProperties:
- $ref: '#/components/schemas/Package'
- distributions:
- type: object
- description: >-
- A map of Distribution objects indexed by Distribution.id.
- example:
- "1":
- $ref: '#/components/examples/Distribution/value'
- additionalProperties:
- $ref: '#/components/schemas/Distribution'
- environments:
- type: object
- description: "A mapping of Environment lists indexed by Package.id"
- example:
- "10":
- # swagger bug does not allow inline reference here -_-
- # - $ref: '#/components/examples/Environment/value'
- - package_db: "var/lib/dpkg/status"
- introduced_in: >-
- sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a
- distribution_id: "1"
- additionalProperties:
- type: array
- items:
- $ref: '#/components/schemas/Environment'
- vulnerabilities:
- description: "A map of Vulnerabilities indexed by Vulnerability.id"
- type: object
- example:
- "356835":
- $ref: '#/components/examples/Vulnerability/value'
- additionalProperties:
- $ref: '#/components/schemas/Vulnerability'
- package_vulnerabilities:
- description: >-
- A mapping of Vulnerability.id lists indexed by Package.id.
- example:
- "10":
- - "356835"
- additionalProperties:
- type: array
- items:
- type: string
- required:
- - manifest_hash
- - packages
- - distributions
- - environments
- - vulnerabilities
- - package_vulnerabilities
-
- Vulnerability:
- title: Vulnerability
- type: object
- description: "A unique vulnerability indexed by Clair"
- example:
- $ref: '#/components/examples/Vulnerability/value'
- properties:
- id:
- description: "A unique ID representing this vulnerability."
- type: string
- updater:
- description: "A unique ID representing this vulnerability."
- type: string
- name:
- description: "Name of this specific vulnerability."
- type: string
- description:
- description: "A description of this specific vulnerability."
- type: string
- links:
- description: >-
- A space separate list of links to any external information.
- type: string
- severity:
- description: >-
- A severity keyword taken verbatim from the vulnerability source.
- type: string
- normalized_severity:
- description: >-
- A well defined set of severity strings guaranteed to be present.
- type: string
- enum: [Unknown, Negligible, Low, Medium, High, Critical]
- package:
- $ref: '#/components/schemas/Package'
- distribution:
- $ref: '#/components/schemas/Distribution'
- repository:
- $ref: '#/components/schemas/Repository'
- issued:
- description: >-
- The timestamp in which the vulnerability was issued
- type: string
- range:
- description: >-
- The range of package versions affected by this vulnerability.
- type: string
- fixed_in_version:
- description: "A unique ID representing this vulnerability."
- type: string
- required:
- - id
- - updater
- - name
- - description
- - links
- - severity
- - normalized_severity
- - fixed_in_version
-
- Distribution:
- title: Distribution
- type: object
- description: >-
- An indexed distribution discovered in a layer. See
- https://www.freedesktop.org/software/systemd/man/os-release.html
- for explanations and example of fields.
- example:
- $ref: '#/components/examples/Distribution/value'
- properties:
- id:
- description: "A unique ID representing this distribution"
- type: string
- did:
- type: string
- name:
- type: string
- version:
- type: string
- version_code_name:
- type: string
- version_id:
- type: string
- arch:
- type: string
- cpe:
- type: string
- pretty_name:
- type: string
- required:
- - id
- - did
- - name
- - version
- - version_code_name
- - version_id
- - arch
- - cpe
- - pretty_name
-
- Package:
- title: Package
- type: object
- description: "A package discovered by indexing a Manifest"
- example:
- $ref: '#/components/examples/Package/value'
- properties:
- id:
- description: "A unique ID representing this package"
- type: string
- name:
- description: "Name of the Package"
- type: string
- version:
- description: "Version of the Package"
- type: string
- kind:
- description: "Kind of package. Source | Binary"
- type: string
- source:
- $ref: '#/components/schemas/Package'
- normalized_version:
- $ref: '#/components/schemas/Version'
- arch:
- description: "The package's target system architecture"
- type: string
- module:
- description: "A module further defining a namespace for a package"
- type: string
- cpe:
- description: "A CPE identifying the package"
- type: string
- required:
- - id
- - name
- - version
-
- Repository:
- title: Repository
- type: object
- description: "A package repository"
- properties:
- id:
- type: string
- name:
- type: string
- key:
- type: string
- uri:
- type: string
- cpe:
- type: string
-
- Version:
- title: Version
- type: string
- description: >-
- Version is a normalized claircore version, composed of a "kind" and an
- array of integers such that two versions of the same kind have the
- correct ordering when the integers are compared pair-wise.
- example: >-
- pep440:0.0.0.0.0.0.0.0.0
-
- Manifest:
- title: Manifest
- type: object
- description: >-
- A Manifest representing a container. The 'layers' array must
- preserve the original container's layer order for accurate usage.
- properties:
- hash:
- $ref: '#/components/schemas/Digest'
- layers:
- type: array
- items:
- $ref: '#/components/schemas/Layer'
- required:
- - hash
- - layers
-
- Layer:
- title: Layer
- type: object
- description: "A Layer within a Manifest and where Clair may retrieve it."
- properties:
- hash:
- $ref: '#/components/schemas/Digest'
- uri:
- type: string
- description: >-
- A URI describing where the layer may be found. Implementations
- MUST support http(s) schemes and MAY support additional
- schemes.
- example: >-
- https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36
- headers:
- type: object
- description: >-
- map of arrays of header values keyed by header
- value. e.g. map[string][]string
- additionalProperties:
- type: array
- items:
- type: string
- required:
- - hash
- - uri
- - headers
-
- BulkDelete:
- title: 'BulkDelete'
- type: array
- description: 'An array of Digests to be deleted.'
- items:
- $ref: '#/components/schemas/Digest'
-
- Error:
- title: Error
- type: object
- description: "A general error schema returned when status is not 200 OK"
- properties:
- code:
- type: string
- description: "a code for this particular error"
- message:
- type: string
- description: "a message with further detail"
-
- State:
- title: State
- type: object
- description: an opaque identifier
- example:
- state: "aae368a064d7c5a433d0bf2c4f5554cc"
- properties:
- state:
- type: string
- description: an opaque identifier
- required:
- - state
-
- Digest:
- title: Digest
- type: string
- description: >-
- A digest string with prefixed algorithm. The format is described here:
- https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests
-
- Digests are used throughout the API to identify Layers and Manifests.
- example: >-
- sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3