Skip to content

Commit 84a02bb

Browse files
committed
openapi: rebuild OpenAPI spec
Signed-off-by: Hank Donnay <[email protected]>
1 parent 6344749 commit 84a02bb

23 files changed

+4818
-2206
lines changed

Documentation/reference/api.md

Lines changed: 1223 additions & 1096 deletions
Large diffs are not rendered by default.

httptransport/api/lib/oapi.jq

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# vim: set expandtab ts=2 sw=2:
2+
module {
3+
name: "openapi",
4+
};
5+
6+
# Some helper functions:
7+
8+
def ref($ref): # Construct a JSON Schema reference object.
9+
{ "$ref": "\($ref)" }
10+
;
11+
12+
def lref($kind; $id): # Construct a ref object to an OpenAPI component.
13+
ref("#/components/\($kind)/\($id)")
14+
;
15+
16+
def param_ref($id): # Construct a ref object to an OpenAPI parameter component.
17+
lref("parameters"; $id)
18+
;
19+
20+
def response_ref($id): # Construct a ref object to an OpenAPI response component.
21+
lref("responses"; $id)
22+
;
23+
24+
def header_ref($id): # Construct a ref object to an OpenAPI header component.
25+
lref("headers"; $id)
26+
;
27+
28+
def schema_ref($id): # Construct a ref object to an OpenAPI schema component.
29+
lref("schemas"; $id)
30+
;
31+
32+
def mediatype($t; $v): # Return the local vendor mediatype for $t, version $v.
33+
"application/vnd.clair.\($t).\($v)+json"
34+
;
35+
36+
def mediatype($t): # As mediatype/2, but with the default of "v1".
37+
mediatype($t; "v1")
38+
;
39+
40+
def contenttype($t; $v): # Construct an OpenAPI content type object for $t, version $v.
41+
{ (mediatype($t; $v)): { "schema": schema_ref($t) } }
42+
;
43+
44+
def contenttype($t): # As contenttype/2, but with the default version.
45+
{ (mediatype($t)): { "schema": schema_ref($t) } }
46+
;
47+
48+
def cli_hints: # Add some hints that CLI tools can pick up on to ignore our internal paths.
49+
(.paths[][] | select(objects and (.tags|contains(["internal"]))) ) |= . + {"x-cli-ignore": true}
50+
;
51+
52+
def sort_paths: # Sort the paths object.
53+
.paths |= (. | to_entries | sort_by(.key) | from_entries)
54+
;
55+
56+
def content_defaults: # All responses that don't have a "default" type, pick the first one.
57+
"application/json" as $t |
58+
[["example"], ["examples"]] as $rm |
59+
( .paths[][] | select(objects) | .responses[].content | select(objects and (has($t)|not)) ) |= (. + { $t: (to_entries[0].value | delpaths($rm)) })
60+
|
61+
( .paths[][] | select(objects) | .requestBody.content | select(objects and (has($t)|not)) ) |= (. + { $t: (to_entries[0].value | delpaths($rm)) })
62+
|
63+
( .components.responses[].content | select(has($t)|not) ) |= (. + { $t: (to_entries[0].value | delpaths($rm)) })
64+
;

httptransport/api/openapi.zsh

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/zsh
2+
set -euo pipefail
3+
4+
# This script builds the OpenAPI documents, rendering them into YAML and JSON.
5+
#
6+
# The main inputs for this are the "openapi.jq" files in the "v?" directories.
7+
# These are jq(1) scripts that are executed with no input in the relevant
8+
# directory; they're expected to output a valid OpenAPI document. All the JSON
9+
# Schema documents in the matching "httptransport/types/v?" directory are
10+
# copied into the working directory. Matching files in the "examples"
11+
# subdirectory will be slipstreamed to the expected field.
12+
#
13+
# The result is then "bundled" into one document, then linted, rendered out to
14+
# both YAML and JSON, and strings to be used as HTTP Etags are written out.
15+
16+
for cmd in sha256sum git jq yq npx; do
17+
if ! command -v "$cmd" &>/dev/null; then
18+
print missing needed command: "$cmd" >&2
19+
exit 1
20+
fi
21+
done
22+
local root=$(git rev-parse --show-toplevel)
23+
24+
function jq() {
25+
command jq --exit-status "$@"
26+
}
27+
28+
function yq() {
29+
command yq --exit-status "$@"
30+
}
31+
32+
function schemalint() {
33+
local tmp=$(mktemp --tmpdir schemalint.out.XXX)
34+
trap "
35+
[[ \"\$?\" -eq 0 ]] || cat \"$tmp\"
36+
[[ -f \"$tmp\" ]] && rm \"$tmp\"
37+
" EXIT
38+
npx --yes @sourcemeta/jsonschema metaschema --resolve "$1" "$1" &>>"$tmp"
39+
npx --yes @sourcemeta/jsonschema lint --resolve "$1" "$1" &>>"$tmp"
40+
}
41+
42+
function widdershins() {
43+
local tmp=$(mktemp --tmpdir widdershins.out.XXX)
44+
trap "
45+
[[ \"\$?\" -eq 0 ]] || cat \"$tmp\"
46+
[[ -f \"$tmp\" ]] && rm \"$tmp\"
47+
" EXIT
48+
npx --yes widdershins \
49+
-o "${root}/Documentation/reference/api.md" \
50+
--search false \
51+
--language_tabs python:Python go:Golang javascript:Javascript \
52+
--summary \
53+
"${1?missing OpenAPI document}" &>"$tmp"
54+
}
55+
56+
function render() {
57+
trap '
58+
rm openapi.*.{json,yaml}(N) *.schema.json(N)
59+
popd -q
60+
' EXIT
61+
pushd -q "${1?missing directory argument}"
62+
local v=${1:A:t}
63+
local t=${1:A:h:h}/types/v1
64+
65+
schemalint "$t"
66+
for f in ${t}/*.schema.json; do
67+
local ex=examples/${${f:t}%.schema.json}.json
68+
if [[ -f "$ex" ]]; then
69+
jq --slurpfile ex "${ex}" 'setpath(["examples"]; $ex)' "$f" > "${f:t}"
70+
else
71+
cp "$f" .
72+
fi
73+
done
74+
75+
jq --null-input \
76+
'reduce (inputs|(.["$id"]|split("/")|.[-1]|rtrimstr(".schema.json")) as $k|{components:{schemas:{$k:.}}}) as $it({};. * $it)'\
77+
*.schema.json >openapi.types.json
78+
79+
80+
jq --null-input -L "${1:A:h}/lib" --from-file openapi.jq >openapi.frag.json
81+
jq --null-input 'reduce inputs as $it({};. * $it)' openapi.{frag,types}.json >openapi.json
82+
83+
yq -pj eval . <openapi.json >openapi.yaml
84+
# Need some validator that actually works >:(
85+
86+
sha256sum openapi.json |
87+
awk '{printf "\"%s\"", $1 >"openapi.etag" }'
88+
}
89+
90+
# Process all the openapi generation scripts.
91+
for d in ${root}/httptransport/api/v*/openapi.jq(om); do
92+
render "${d:h}"
93+
done
94+
95+
# Generate documentation for the highest version.
96+
widdershins "${root}"/httptransport/api/v*/openapi.yaml(NnOn[1])
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[
2+
"sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3"
3+
]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"cpe:/a:microsoft:internet_explorer:8.0.6001:beta"
2+
"cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"id": "1",
3+
"did": "ubuntu",
4+
"name": "Ubuntu",
5+
"version": "18.04.3 LTS (Bionic Beaver)",
6+
"version_code_name": "bionic",
7+
"version_id": "18.04",
8+
"pretty_name": "Ubuntu 18.04.3 LTS"
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"value": {
3+
"package_db": "var/lib/dpkg/status",
4+
"introduced_in": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
5+
"distribution_id": "1"
6+
}
7+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"hash": "sha256:fc84b5febd328eccaa913807716887b3eb5ed08bc22cc6933a9ebf82766725e3",
3+
"layers": [
4+
{
5+
"hash": "sha256:2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
6+
"uri": "https://storage.example.com/blob/2f077db56abccc19f16f140f629ae98e904b4b7d563957a7fc319bd11b82ba36",
7+
"headers": {
8+
"Authoriztion": [
9+
"Bearer hunter2"
10+
]
11+
}
12+
}
13+
]
14+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"page": {
3+
"size": 100,
4+
"next": "1b4d0db2-e757-4150-bbbb-543658144205"
5+
},
6+
"notifications": [
7+
{
8+
"id": "5e4b387e-88d3-4364-86fd-063447a6fad2",
9+
"manifest": "sha256:35c102085707f703de2d9eaad8752d6fe1b8f02b5d2149f1d8357c9cc7fb7d0a",
10+
"reason": "added",
11+
"vulnerability": {
12+
"name": "CVE-2009-5155",
13+
"fixed_in_version": "v0.0.1",
14+
"links": "http://example.com/CVE-2009-5155",
15+
"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.\"",
16+
"normalized_severity": "Unknown",
17+
"package": {
18+
"id": "10",
19+
"name": "libapt-pkg5.0",
20+
"version": "1.6.11",
21+
"kind": "BINARY",
22+
"arch": "x86",
23+
"source": {
24+
"id": "9",
25+
"name": "apt",
26+
"version": "1.6.11",
27+
"kind": "SOURCE",
28+
"source": null
29+
}
30+
},
31+
"distribution": {
32+
"id": "1",
33+
"did": "ubuntu",
34+
"name": "Ubuntu",
35+
"version": "18.04.3 LTS (Bionic Beaver)",
36+
"version_code_name": "bionic",
37+
"version_id": "18.04",
38+
"pretty_name": "Ubuntu 18.04.3 LTS"
39+
}
40+
}
41+
}
42+
]
43+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"id": "10",
3+
"name": "libapt-pkg5.0",
4+
"version": "1.6.11",
5+
"kind": "binary",
6+
"normalized_version": "",
7+
"arch": "x86",
8+
"module": "",
9+
"cpe": "",
10+
"source": {
11+
"id": "9",
12+
"name": "apt",
13+
"version": "1.6.11",
14+
"kind": "source",
15+
"source": null
16+
}
17+
}

0 commit comments

Comments
 (0)