mirror of
https://github.com/project-zot/zot.git
synced 2024-12-30 22:34:13 -05:00
ext: use distribution spec route prefix for extension api
Following the spec defined here https://github.com/opencontainers/distribution-spec/tree/main/extensions Signed-off-by: Shivam Mishra <shimish2@cisco.com>
This commit is contained in:
parent
c1bf4456d0
commit
36c9631000
50 changed files with 1076 additions and 395 deletions
2
.github/workflows/ci-cd.yml
vendored
2
.github/workflows/ci-cd.yml
vendored
|
@ -56,7 +56,7 @@ jobs:
|
|||
- name: Install other dependencies
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
go install github.com/swaggo/swag/cmd/swag@v1.6.3
|
||||
sudo apt-get update
|
||||
sudo apt-get install rpm
|
||||
sudo apt-get install snapd
|
||||
|
|
4
Makefile
4
Makefile
|
@ -102,11 +102,11 @@ check: ./golangcilint.yaml $(GOLINTER)
|
|||
$(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags stress,extended,containers_image_openpgp ./...
|
||||
|
||||
swagger/docs.go:
|
||||
swag -v || go install github.com/swaggo/swag/cmd/swag
|
||||
swag -v || go install github.com/swaggo/swag/cmd/swag@1.6.3
|
||||
swag init -o swagger -g pkg/api/routes.go
|
||||
|
||||
.PHONY: swagger
|
||||
swagger: swagger/docs.go
|
||||
swagger: swagger/docs.go pkg/api/routes.go
|
||||
|
||||
.PHONY: update-licenses
|
||||
update-licenses:
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
jsoniter "github.com/json-iterator/go"
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
"gopkg.in/resty.v1"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -323,7 +324,7 @@ func GetCatalog(workdir, url, auth, repo string, requests int, config testConfig
|
|||
}()
|
||||
|
||||
// send request and get response
|
||||
resp, err := client.R().Get(url + "/v2/_catalog")
|
||||
resp, err := client.R().Get(url + constants.RoutePrefix + constants.ExtCatalogPrefix)
|
||||
|
||||
latency = time.Since(start)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
@ -11,12 +11,14 @@
|
|||
"level": "debug"
|
||||
},
|
||||
"extensions": {
|
||||
"metrics": {
|
||||
},
|
||||
"metrics": {},
|
||||
"sync": {
|
||||
"credentialsFile": "./examples/sync-auth-filepath.json",
|
||||
"registries": [{
|
||||
"urls": ["https://registry1:5000"],
|
||||
"registries": [
|
||||
{
|
||||
"urls": [
|
||||
"https://registry1:5000"
|
||||
],
|
||||
"onDemand": false,
|
||||
"pollInterval": "6h",
|
||||
"tlsVerify": true,
|
||||
|
@ -35,7 +37,8 @@
|
|||
"prefix": "/repo2/repo"
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
"search": {
|
||||
"cve": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion":"1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot",
|
||||
"commit": true
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion":"1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot",
|
||||
"gc": false,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
@ -9,16 +9,27 @@
|
|||
"realm": "zot",
|
||||
"accessControl": {
|
||||
"**": {
|
||||
"defaultPolicy": ["read", "create"]
|
||||
"defaultPolicy": [
|
||||
"read",
|
||||
"create"
|
||||
]
|
||||
},
|
||||
"tmp/**": {
|
||||
"defaultPolicy": ["read", "create", "update"]
|
||||
"defaultPolicy": [
|
||||
"read",
|
||||
"create",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
"infra/**": {
|
||||
"defaultPolicy": ["read"]
|
||||
"defaultPolicy": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
"repos2/repo": {
|
||||
"defaultPolicy": ["read"]
|
||||
"defaultPolicy": [
|
||||
"read"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -26,5 +37,3 @@
|
|||
"level": "debug"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion":"1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
distspecversion: 1.0.1
|
||||
distspecversion: 1.0.1-dev
|
||||
http:
|
||||
address: 127.0.0.1
|
||||
allowreadaccess: false
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion":"1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot",
|
||||
"gc": true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot",
|
||||
"gc": true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot",
|
||||
"dedupe": true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot",
|
||||
"dedupe": true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
@ -17,44 +17,91 @@
|
|||
"**": {
|
||||
"policies": [
|
||||
{
|
||||
"users": ["charlie"],
|
||||
"actions": ["read", "create", "update"]
|
||||
"users": [
|
||||
"charlie"
|
||||
],
|
||||
"actions": [
|
||||
"read",
|
||||
"create",
|
||||
"update"
|
||||
]
|
||||
}
|
||||
],
|
||||
"defaultPolicy": ["read", "create"]
|
||||
"defaultPolicy": [
|
||||
"read",
|
||||
"create"
|
||||
]
|
||||
},
|
||||
"tmp/**": {
|
||||
"defaultPolicy": ["read", "create", "update"]
|
||||
"defaultPolicy": [
|
||||
"read",
|
||||
"create",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
"infra/**": {
|
||||
"policies": [
|
||||
{
|
||||
"users": ["alice", "bob"],
|
||||
"actions": ["create", "read", "update", "delete"]
|
||||
"users": [
|
||||
"alice",
|
||||
"bob"
|
||||
],
|
||||
"actions": [
|
||||
"create",
|
||||
"read",
|
||||
"update",
|
||||
"delete"
|
||||
]
|
||||
},
|
||||
{
|
||||
"users": ["mallory"],
|
||||
"actions": ["create", "read"]
|
||||
"users": [
|
||||
"mallory"
|
||||
],
|
||||
"actions": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
}
|
||||
],
|
||||
"defaultPolicy": ["read"]
|
||||
"defaultPolicy": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
"repos2/repo": {
|
||||
"policies": [
|
||||
{
|
||||
"users": ["charlie"],
|
||||
"actions": ["read", "create"]
|
||||
"users": [
|
||||
"charlie"
|
||||
],
|
||||
"actions": [
|
||||
"read",
|
||||
"create"
|
||||
]
|
||||
},
|
||||
{
|
||||
"users": ["mallory"],
|
||||
"actions": ["create", "read"]
|
||||
"users": [
|
||||
"mallory"
|
||||
],
|
||||
"actions": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
}
|
||||
],
|
||||
"defaultPolicy": ["read"]
|
||||
"defaultPolicy": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
"adminPolicy": {
|
||||
"users": ["admin"],
|
||||
"actions": ["read", "create", "update", "delete"]
|
||||
"users": [
|
||||
"admin"
|
||||
],
|
||||
"actions": [
|
||||
"read",
|
||||
"create",
|
||||
"update",
|
||||
"delete"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -63,4 +110,3 @@
|
|||
"output": "/tmp/zot.log"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion": "1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/zot",
|
||||
"storageDriver": {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion":"1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion":"1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
@ -14,8 +14,11 @@
|
|||
"sync": {
|
||||
"enable": true,
|
||||
"credentialsFile": "./examples/sync-auth-filepath.json",
|
||||
"registries": [{
|
||||
"urls": ["https://registry1:5000"],
|
||||
"registries": [
|
||||
{
|
||||
"urls": [
|
||||
"https://registry1:5000"
|
||||
],
|
||||
"onDemand": false,
|
||||
"pollInterval": "6h",
|
||||
"tlsVerify": true,
|
||||
|
@ -42,7 +45,10 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"urls": ["https://registry2:5000", "https://registry3:5000"],
|
||||
"urls": [
|
||||
"https://registry2:5000",
|
||||
"https://registry3:5000"
|
||||
],
|
||||
"pollInterval": "12h",
|
||||
"tlsVerify": false,
|
||||
"onDemand": false,
|
||||
|
@ -56,7 +62,9 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"urls": ["https://docker.io/library"],
|
||||
"urls": [
|
||||
"https://docker.io/library"
|
||||
],
|
||||
"onDemand": true,
|
||||
"tlsVerify": true,
|
||||
"maxRetries": 6,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion":"1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"distSpecVersion":"1.0.1",
|
||||
"distSpecVersion": "1.0.1-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/tmp/zot"
|
||||
},
|
||||
|
|
17
go.mod
17
go.mod
|
@ -47,7 +47,6 @@ require (
|
|||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/viper v1.11.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/swaggo/http-swagger v1.2.6
|
||||
github.com/swaggo/swag v1.8.1
|
||||
github.com/urfave/cli/v2 v2.4.0
|
||||
github.com/vektah/gqlparser/v2 v2.4.1
|
||||
|
@ -57,9 +56,11 @@ require (
|
|||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require github.com/open-policy-agent/opa v0.37.0 // indirect
|
||||
|
||||
require (
|
||||
github.com/open-policy-agent/opa v0.37.0 // indirect
|
||||
github.com/opencontainers/distribution-spec v1.0.1
|
||||
github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220217185014-dd38b7ed8a99
|
||||
github.com/swaggo/http-swagger v1.2.8
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -90,8 +91,6 @@ require (
|
|||
github.com/PaesslerAG/gval v1.0.0 // indirect
|
||||
github.com/PaesslerAG/jsonpath v0.1.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||
|
@ -179,10 +178,10 @@ require (
|
|||
github.com/go-openapi/analysis v0.21.2 // indirect
|
||||
github.com/go-openapi/errors v0.20.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/loads v0.21.1 // indirect
|
||||
github.com/go-openapi/runtime v0.23.3 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/spec v0.20.6 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.2 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/go-openapi/validate v0.21.0 // indirect
|
||||
|
@ -361,10 +360,10 @@ require (
|
|||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
|
||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
|
|
25
go.sum
25
go.sum
|
@ -303,10 +303,8 @@ github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C6
|
|||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/ReneKroon/ttlcache/v2 v2.10.0/go.mod h1:mBxvsNY+BT8qLLd6CuAJubbKo6r0jh3nb5et22bbfGY=
|
||||
github.com/ReneKroon/ttlcache/v2 v2.11.0 h1:OvlcYFYi941SBN3v9dsDcC2N8vRxyHcCmJb3Vl4QMoM=
|
||||
|
@ -1068,8 +1066,9 @@ github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3Hfo
|
|||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
|
||||
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
|
@ -1103,8 +1102,10 @@ github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFu
|
|||
github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/spec v0.20.1/go.mod h1:93x7oh+d+FQsmsieroS4cmR3u0p/ywH649a3qwC9OsQ=
|
||||
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
|
||||
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
|
||||
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
|
||||
github.com/go-openapi/spec v0.20.5/go.mod h1:QbfOSIVt3/sac+a1wzmKbbcLXm5NdZnyBZYtCijp43o=
|
||||
github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ=
|
||||
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
|
||||
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
|
||||
|
@ -2142,8 +2143,8 @@ github.com/open-policy-agent/opa v0.32.0/go.mod h1:5sJdtc+1/U8zy/j30njpQl6u9rM4M
|
|||
github.com/open-policy-agent/opa v0.35.0/go.mod h1:xEmekKlk6/c+so5HF9wtPnGPXDfBuBsrMGhSHOHEF+U=
|
||||
github.com/open-policy-agent/opa v0.37.0 h1:OUXB+RAcxQpmXeNW2BN1wYzQQvVCPF1T9zv+QXGr9Wg=
|
||||
github.com/open-policy-agent/opa v0.37.0/go.mod h1:xX3NUCZuXK8f0CNhFQvhm4495mZLptf94pIkWRLaFqo=
|
||||
github.com/opencontainers/distribution-spec v1.0.1 h1:hT6tF6uKZAQh+HH3BrJqn7/xHhMoDHzahIg4KxD2DqM=
|
||||
github.com/opencontainers/distribution-spec v1.0.1/go.mod h1:copR2flp+jTEvQIFMb6MIx45OkrxzqyjszPDT3hx/5Q=
|
||||
github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220217185014-dd38b7ed8a99 h1:yGqpYh1h3ZXxGg4Mqd5ZwhlwQ9wXOgvuodxbxJA7iMY=
|
||||
github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220217185014-dd38b7ed8a99/go.mod h1:aA4vdXRS8E1TG7pLZOz85InHi3BiPdErh8IpJN6E0x4=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
|
@ -2546,9 +2547,8 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s
|
|||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM=
|
||||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
|
||||
github.com/swaggo/http-swagger v1.2.6 h1:ihTjChUoSRMpFMjWw+0AkL1Ti4r6v8pCgVYLmQVRlRw=
|
||||
github.com/swaggo/http-swagger v1.2.6/go.mod h1:CcoICgY3yVDk2u1LQUCMHbAj0fjlxIX+873psXlIKNA=
|
||||
github.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
|
||||
github.com/swaggo/http-swagger v1.2.8 h1:TVjxLU7qoqofJ9qynJazmpTGs/p4Kx9FTp7YYwOkJb0=
|
||||
github.com/swaggo/http-swagger v1.2.8/go.mod h1:FrQwV7rx+A5t11PIX8d+tFJa2GKx11RdAXQptllPQHg=
|
||||
github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=
|
||||
github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
|
@ -3099,8 +3099,10 @@ golang.org/x/net v0.0.0-20220127074510-2fabfed7e28f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
|||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y=
|
||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -3310,8 +3312,9 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
|
|
@ -3,6 +3,7 @@ package api
|
|||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -10,6 +11,7 @@ import (
|
|||
glob "github.com/bmatcuk/doublestar/v4"
|
||||
"github.com/gorilla/mux"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
"zotregistry.io/zot/pkg/common"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
)
|
||||
|
@ -191,7 +193,7 @@ func AuthzHandler(ctlr *Controller) mux.MiddlewareFunc {
|
|||
ctx := acCtrlr.getContext(username, request)
|
||||
|
||||
// will return only repos on which client is authorized to read
|
||||
if request.RequestURI == "/v2/_catalog" {
|
||||
if request.RequestURI == fmt.Sprintf("%s%s", constants.RoutePrefix, constants.ExtCatalogPrefix) {
|
||||
next.ServeHTTP(response, request.WithContext(ctx))
|
||||
|
||||
return
|
||||
|
|
|
@ -8,4 +8,5 @@ const (
|
|||
BlobUploadUUID = "Blob-Upload-UUID"
|
||||
DefaultMediaType = "application/json"
|
||||
BinaryMediaType = "application/octet-stream"
|
||||
DefaultMetricsExtensionRoute = "/metrics"
|
||||
)
|
||||
|
|
9
pkg/api/constants/extensions.go
Normal file
9
pkg/api/constants/extensions.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package constants
|
||||
|
||||
// https://github.com/opencontainers/distribution-spec/tree/main/extensions#extensions-api-for-distribution
|
||||
const (
|
||||
ExtCatalogPrefix = "/_catalog"
|
||||
ExtOciDiscoverPrefix = "/_oci/ext/discover"
|
||||
// zot specific extensions.
|
||||
ExtSearchPrefix = RoutePrefix + "/_search"
|
||||
)
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/mitchellh/mapstructure"
|
||||
vldap "github.com/nmcclain/ldap"
|
||||
notreg "github.com/notaryproject/notation/pkg/registry"
|
||||
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
|
||||
|
@ -47,6 +48,7 @@ import (
|
|||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
|
@ -1878,7 +1880,7 @@ func TestAuthorizationWithBasicAuth(t *testing.T) {
|
|||
|
||||
// everybody should have access to /v2/_catalog
|
||||
resp, err = resty.R().SetBasicAuth(username, passphrase).
|
||||
Get(baseURL + "/v2/_catalog")
|
||||
Get(baseURL + constants.RoutePrefix + constants.ExtCatalogPrefix)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
|
@ -3195,7 +3197,7 @@ func TestParallelRequests(t *testing.T) {
|
|||
assert.Equal(t, tagResponse.StatusCode(), http.StatusOK, "response status code should return success code")
|
||||
|
||||
repoResponse, err := client.R().SetBasicAuth(username, passphrase).
|
||||
Get(baseURL + "/v2/_catalog")
|
||||
Get(baseURL + constants.RoutePrefix + constants.ExtCatalogPrefix)
|
||||
assert.Equal(t, err, nil, "Error should be nil")
|
||||
assert.Equal(t, repoResponse.StatusCode(), http.StatusOK, "response status code should return success code")
|
||||
})
|
||||
|
@ -4812,6 +4814,80 @@ func TestPeriodicGC(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestDistSpecExtensions(t *testing.T) {
|
||||
Convey("start zot server with search extension", t, func(c C) {
|
||||
conf := config.New()
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf.HTTP.Port = port
|
||||
|
||||
defaultVal := true
|
||||
|
||||
searchConfig := &extconf.SearchConfig{
|
||||
Enable: &defaultVal,
|
||||
}
|
||||
|
||||
conf.Extensions = &extconf.ExtensionConfig{
|
||||
Search: searchConfig,
|
||||
}
|
||||
|
||||
logFile, err := ioutil.TempFile("", "zot-log*.txt")
|
||||
So(err, ShouldBeNil)
|
||||
conf.Log.Output = logFile.Name()
|
||||
defer os.Remove(logFile.Name()) // clean up
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
|
||||
ctlr.Config.Storage.RootDirectory = t.TempDir()
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
var extensionList distext.ExtensionList
|
||||
|
||||
resp, err := resty.R().Get(baseURL + constants.RoutePrefix + constants.ExtOciDiscoverPrefix)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
err = json.Unmarshal(resp.Body(), &extensionList)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(extensionList.Extensions), ShouldEqual, 1)
|
||||
})
|
||||
|
||||
Convey("start minimal zot server", t, func(c C) {
|
||||
conf := config.New()
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf.HTTP.Port = port
|
||||
|
||||
logFile, err := ioutil.TempFile("", "zot-log*.txt")
|
||||
So(err, ShouldBeNil)
|
||||
conf.Log.Output = logFile.Name()
|
||||
defer os.Remove(logFile.Name()) // clean up
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
|
||||
ctlr.Config.Storage.RootDirectory = t.TempDir()
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
var extensionList distext.ExtensionList
|
||||
resp, err := resty.R().Get(baseURL + constants.RoutePrefix + constants.ExtOciDiscoverPrefix)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
err = json.Unmarshal(resp.Body(), &extensionList)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(extensionList.Extensions), ShouldEqual, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func getAllBlobs(imagePath string) []string {
|
||||
blobList := make([]string, 0)
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
notreg "github.com/notaryproject/notation/pkg/registry"
|
||||
"github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
|
||||
httpSwagger "github.com/swaggo/http-swagger"
|
||||
|
@ -69,6 +70,7 @@ func (rh *RouteHandler) SetupRoutes() {
|
|||
rh.c.Router.Use(AuthzHandler(rh.c))
|
||||
}
|
||||
|
||||
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#endpoints
|
||||
prefixedRouter := rh.c.Router.PathPrefix(constants.RoutePrefix).Subrouter()
|
||||
{
|
||||
prefixedRouter.HandleFunc(fmt.Sprintf("/{name:%s}/tags/list", NameRegexp.String()),
|
||||
|
@ -97,8 +99,10 @@ func (rh *RouteHandler) SetupRoutes() {
|
|||
rh.UpdateBlobUpload).Methods("PUT")
|
||||
prefixedRouter.HandleFunc(fmt.Sprintf("/{name:%s}/blobs/uploads/{session_id}", NameRegexp.String()),
|
||||
rh.DeleteBlobUpload).Methods("DELETE")
|
||||
prefixedRouter.HandleFunc("/_catalog",
|
||||
prefixedRouter.HandleFunc(constants.ExtCatalogPrefix,
|
||||
rh.ListRepositories).Methods(allowedMethods("GET")...)
|
||||
prefixedRouter.HandleFunc(constants.ExtOciDiscoverPrefix,
|
||||
rh.ListExtensions).Methods(allowedMethods("GET")...)
|
||||
prefixedRouter.HandleFunc("/",
|
||||
rh.CheckVersionSupport).Methods(allowedMethods("GET")...)
|
||||
}
|
||||
|
@ -336,6 +340,10 @@ type ImageManifest struct {
|
|||
ispec.Manifest
|
||||
}
|
||||
|
||||
type ExtensionList struct {
|
||||
extensions.ExtensionList
|
||||
}
|
||||
|
||||
// GetManifest godoc
|
||||
// @Summary Get image manifest
|
||||
// @Description Get an image's manifest given a reference or a digest
|
||||
|
@ -1249,6 +1257,19 @@ func (rh *RouteHandler) ListRepositories(response http.ResponseWriter, request *
|
|||
WriteJSON(response, http.StatusOK, is)
|
||||
}
|
||||
|
||||
// ListExtensions godoc
|
||||
// @Summary List Registry level extensions
|
||||
// @Description List all extensions present on registry
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} api.ExtensionList
|
||||
// @Router /v2/_oci/ext/discover [get].
|
||||
func (rh *RouteHandler) ListExtensions(w http.ResponseWriter, r *http.Request) {
|
||||
extensionList := ext.GetExtensions(rh.c.Config)
|
||||
|
||||
WriteJSON(w, http.StatusOK, extensionList)
|
||||
}
|
||||
|
||||
func (rh *RouteHandler) GetMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
m := rh.c.Metrics.ReceiveMetrics()
|
||||
WriteJSON(w, http.StatusOK, m)
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"gopkg.in/resty.v1"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
)
|
||||
|
||||
func TestElevatedPrivilegesTLSNewControllerPrivilegedCert(t *testing.T) {
|
||||
|
@ -106,8 +107,8 @@ func TestElevatedPrivilegesTLSNewControllerPrivilegedCert(t *testing.T) {
|
|||
|
||||
Convey("Certs in privileged path", func() {
|
||||
configPath := makeConfigFile(
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s/v2/_catalog","showspinner":false}]}`,
|
||||
BaseSecureURL2))
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
||||
BaseSecureURL2, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||
defer os.Remove(configPath)
|
||||
|
||||
args := []string{"imagetest"}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"gopkg.in/resty.v1"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
|
||||
|
@ -114,8 +115,8 @@ func TestTLSWithAuth(t *testing.T) {
|
|||
|
||||
args = []string{"imagetest"}
|
||||
configPath = makeConfigFile(
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s/v2/_catalog","showspinner":false}]}`,
|
||||
BaseSecureURL1))
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
||||
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||
defer os.Remove(configPath)
|
||||
imageCmd = NewImageCommand(new(searchService))
|
||||
imageBuff = bytes.NewBufferString("")
|
||||
|
@ -129,8 +130,8 @@ func TestTLSWithAuth(t *testing.T) {
|
|||
user := fmt.Sprintf("%s:%s", username, passphrase)
|
||||
args = []string{"imagetest", "-u", user}
|
||||
configPath = makeConfigFile(
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s/v2/_catalog","showspinner":false}]}`,
|
||||
BaseSecureURL1))
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
||||
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||
defer os.Remove(configPath)
|
||||
imageCmd = NewImageCommand(new(searchService))
|
||||
imageBuff = bytes.NewBufferString("")
|
||||
|
@ -185,8 +186,8 @@ func TestTLSWithoutAuth(t *testing.T) {
|
|||
|
||||
Convey("Certs in user's home", func() {
|
||||
configPath := makeConfigFile(
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s/v2/_catalog","showspinner":false}]}`,
|
||||
BaseSecureURL1))
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
||||
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||
defer os.Remove(configPath)
|
||||
|
||||
home := os.Getenv("HOME")
|
||||
|
@ -250,8 +251,8 @@ func TestTLSBadCerts(t *testing.T) {
|
|||
|
||||
Convey("Test with system certs", func() {
|
||||
configPath := makeConfigFile(
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s/v2/_catalog","showspinner":false}]}`,
|
||||
BaseSecureURL3))
|
||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
||||
BaseSecureURL3, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||
defer os.Remove(configPath)
|
||||
|
||||
args := []string{"imagetest"}
|
||||
|
|
|
@ -5,7 +5,6 @@ package cli //nolint:testpackage
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -216,8 +215,6 @@ func TestConfigCmdMain(t *testing.T) {
|
|||
cmd.SetArgs(args)
|
||||
err := cmd.Execute()
|
||||
So(err, ShouldNotBeNil)
|
||||
fmt.Println(err)
|
||||
fmt.Println(buff.String())
|
||||
So(buff.String(), ShouldContainSubstring, "does not exist")
|
||||
})
|
||||
})
|
||||
|
@ -254,8 +251,6 @@ func TestConfigCmdMain(t *testing.T) {
|
|||
cmd.SetArgs(args)
|
||||
err := cmd.Execute()
|
||||
So(err, ShouldNotBeNil)
|
||||
fmt.Println(err)
|
||||
fmt.Println(buff.String())
|
||||
So(buff.String(), ShouldContainSubstring, "does not exist")
|
||||
})
|
||||
})
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
zotErrors "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
|
@ -320,7 +321,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
}(ctlr)
|
||||
// wait till ready
|
||||
for {
|
||||
res, err := resty.R().Get(url + "/query")
|
||||
res, err := resty.R().Get(url + constants.ExtSearchPrefix)
|
||||
if err == nil && res.StatusCode() == 200 {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
|
@ -332,7 +333,7 @@ func applyDefaultValues(config *config.Config, viperInstance *viper.Viper) {
|
|||
}
|
||||
|
||||
if config.Extensions.Metrics.Prometheus == nil {
|
||||
config.Extensions.Metrics.Prometheus = &extconf.PrometheusConfig{Path: "/metrics"}
|
||||
config.Extensions.Metrics.Prometheus = &extconf.PrometheusConfig{Path: constants.DefaultMetricsExtensionRoute}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/olekukonko/tablewriter"
|
||||
"gopkg.in/yaml.v2"
|
||||
zotErrors "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
)
|
||||
|
||||
type SearchService interface {
|
||||
|
@ -70,7 +71,8 @@ func (service searchService) getAllImages(ctx context.Context, config searchConf
|
|||
|
||||
catalog := &catalogResponse{}
|
||||
|
||||
catalogEndPoint, err := combineServerAndEndpointURL(*config.servURL, "/v2/_catalog")
|
||||
catalogEndPoint, err := combineServerAndEndpointURL(*config.servURL, fmt.Sprintf("%s%s",
|
||||
constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||
if err != nil {
|
||||
if isContextDone(ctx) {
|
||||
return
|
||||
|
@ -453,7 +455,7 @@ func (service searchService) makeGraphQLQuery(ctx context.Context, config search
|
|||
username, password, query string,
|
||||
resultPtr interface{},
|
||||
) error {
|
||||
endPoint, err := combineServerAndEndpointURL(*config.servURL, "/query")
|
||||
endPoint, err := combineServerAndEndpointURL(*config.servURL, constants.ExtSearchPrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -50,14 +50,14 @@ func CheckWorkflows(t *testing.T, config *compliance.Config) {
|
|||
Convey("Make API calls to the controller", t, func(c C) {
|
||||
Convey("Check version", func() {
|
||||
_, _ = Print("\nCheck version")
|
||||
resp, err := resty.R().Get(baseURL + "/v2/")
|
||||
resp, err := resty.R().Get(baseURL + constants.RoutePrefix + "/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
})
|
||||
|
||||
Convey("Get repository catalog", func() {
|
||||
_, _ = Print("\nGet repository catalog")
|
||||
resp, err := resty.R().Get(baseURL + "/v2/_catalog")
|
||||
resp, err := resty.R().Get(baseURL + constants.RoutePrefix + constants.ExtCatalogPrefix)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
So(resp.String(), ShouldNotBeEmpty)
|
||||
|
@ -77,7 +77,8 @@ func CheckWorkflows(t *testing.T, config *compliance.Config) {
|
|||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusAccepted)
|
||||
|
||||
resp, err = resty.R().SetResult(&api.RepositoryList{}).Get(baseURL + "/v2/_catalog")
|
||||
resp, err = resty.R().SetResult(&api.RepositoryList{}).Get(baseURL +
|
||||
constants.RoutePrefix + constants.ExtCatalogPrefix)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
So(resp.String(), ShouldNotBeEmpty)
|
||||
|
|
194
pkg/extensions/_search.md
Normal file
194
pkg/extensions/_search.md
Normal file
|
@ -0,0 +1,194 @@
|
|||
`search` extension
|
||||
===
|
||||
|
||||
`search` extension provides efficient and enhanced registry search capabilities using graphQL backend.
|
||||
|
||||
|
||||
Table of Contents
|
||||
===
|
||||
|
||||
| Supported queries | Input | Ouput | Description | graphQL query |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| [Search images by digest](#search-images-by-digest) | digest | image list | Search all repositories in the registry and return list of images that matches given digest (manifest, config or layers) | ImageListForDigest |
|
||||
| [Search images affected by a given CVE id](#search-images-affected-by-a-given-cve-id) | CVE id | image list | Search the entire registry and return list of images affected by given CVE | ImagesListForCVE |
|
||||
| [List CVEs for a given image](#list-cves-of-given-image) | image | CVE list | Scan given image and return list of CVEs affecting the image | CVEListForImage |
|
||||
| [List images not affected by a given CVE id](#list-images-not-affected-by-a-given-cve-id) | repository, CVE id | image list | Scan all images in a given repository and return list of latest (by date) images not affected by the given CVE |ImagesListWithCVEFixed|
|
||||
| [List the latest image across every repository](#list-the-latest-image-across-every-repository) | \<none\> | image list | Search entire registry and return a list containing the latest (by date) image in each repository | ImageListWithLatestTag |
|
||||
| [List all images with expanded information for a given repository](#list-all-images-with-expanded-information-for-a-given-repository) | repository | image list | List expanded image information for all images (including manifest, all layers, etc) in a given repository | ExpandedRepoInfo |
|
||||
|
||||
# Search images by digest
|
||||
|
||||
**Sample request**
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListForDigest (id:\"63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29\") { Name Tags } }" }' http://localhost:8080/v2/_search
|
||||
```
|
||||
|
||||
**Sample response**
|
||||
|
||||
```
|
||||
{
|
||||
"data": {
|
||||
"ImageListForDigest": [{
|
||||
"Name": "centos",
|
||||
"Tags": ["8"]
|
||||
}, {
|
||||
"Name": "v2/centos",
|
||||
"Tags": ["8"]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Search images affected by a given CVE id
|
||||
|
||||
**Sample request**
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListForCVE (id:\"CVE-2002-1119\") { Name Tags } }" }' http://localhost:8080/v2/_search
|
||||
```
|
||||
|
||||
**Sample response**
|
||||
|
||||
```
|
||||
{
|
||||
"data": {
|
||||
"ImageListForCVE": [{
|
||||
"Name": "centos",
|
||||
"Tags": ["8"]
|
||||
}, {
|
||||
"Name": "v2/centos",
|
||||
"Tags": ["7", "8"]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
# List CVEs of given image
|
||||
|
||||
**Sample reques**t
|
||||
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ CVEListForImage (image:\"centos\" ) { Tag CVEList { Id Title Description Severity PackageList {Name InstalledVersion FixedVersion } } } }" }' http://localhost:8080/v2/_search
|
||||
```
|
||||
|
||||
**Sample response**
|
||||
|
||||
```
|
||||
{
|
||||
"data": {
|
||||
"CVEListForImage": {
|
||||
"Tag": "",
|
||||
"CVEList": [{
|
||||
"Id": "CVE-2021-3712",
|
||||
"Title": "openssl: Read buffer overruns processing ASN.1 strings",
|
||||
"Description": "ASN.1 strings are represented internally within OpenSSL as an ASN1_STRING structure which contains a buffer. Fixed in OpenSSL 1.1.1l (Affected 1.1.1-1.1.1k). Fixed in OpenSSL 1.0.2za (Affected 1.0.2-1.0.2y).",
|
||||
"Severity": "MEDIUM",
|
||||
"PackageList": [{
|
||||
"Name": "openssl-libs",
|
||||
"InstalledVersion": "1:1.1.1g-11.el8",
|
||||
"FixedVersion": "1:1.1.1k-5.el8_5"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
# List images not affected by a given CVE id
|
||||
|
||||
**Sample request**
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListWithCVEFixed (id:\"CVE-2021-3713\",image:\"centos\") { Tags {Name Digest Timestamp} } }" }' http://localhost:8080/v2/_search
|
||||
```
|
||||
|
||||
**Sample response**
|
||||
|
||||
```
|
||||
{
|
||||
"data": {
|
||||
"ImageListWithCVEFixed": {
|
||||
"Tags": [{
|
||||
"Name": "8",
|
||||
"Digest": "sha256:63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29",
|
||||
"Timestamp": "2020-12-08T00:22:52.526672082Z"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# List the latest image across every repository
|
||||
|
||||
**Sample request**
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListWithLatestTag () { Name Latest LastUpdated Description Licenses Vendor Size Labels} }" }' http://localhost:8080/v2/_search
|
||||
```
|
||||
|
||||
**Sample response**
|
||||
|
||||
```
|
||||
{
|
||||
"data": {
|
||||
"ImageListWithLatestTag": [{
|
||||
"Name": "centos",
|
||||
"Latest": "8",
|
||||
"LastUpdated": "2020-12-08T00:22:52.526672082Z",
|
||||
"Description": "",
|
||||
"Licenses": "GPLv2",
|
||||
"Vendor": "CentOS",
|
||||
"Size": "1074",
|
||||
"Labels": ""
|
||||
}, {
|
||||
"Name": "v2/centos",
|
||||
"Latest": "8",
|
||||
"LastUpdated": "2020-12-08T00:22:52.526672082Z",
|
||||
"Description": "",
|
||||
"Licenses": "GPLv2",
|
||||
"Vendor": "CentOS",
|
||||
"Size": "1074",
|
||||
"Labels": ""
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# List all images with expanded information for a given repository
|
||||
|
||||
Sample request
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ExpandedRepoInfo (repo:\"v2/centos\") { Manifests {Digest Tag IsSigned Layers {Size Digest}}} }" }' http://localhost:8080/v2/_search
|
||||
```
|
||||
|
||||
**Sample response**
|
||||
|
||||
```
|
||||
{
|
||||
"data": {
|
||||
"ExpandedRepoInfo": {
|
||||
"Manifests": [{
|
||||
"Digest": "2bacca16b9df395fc855c14ccf50b12b58d35d468b8e7f25758aff90f89bf396",
|
||||
"Tag": "7",
|
||||
"IsSigned": false,
|
||||
"Layers": [{
|
||||
"Size": "76097157",
|
||||
"Digest": "2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc"
|
||||
}]
|
||||
}, {
|
||||
"Digest": "63a795ca90aa6e7cca60941e826810a4cd0a2e73ea02bf458241df2a5c973e29",
|
||||
"Tag": "8",
|
||||
"IsSigned": false,
|
||||
"Layers": [{
|
||||
"Size": "75181999",
|
||||
"Digest": "7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# References
|
||||
[1] https://github.com/opencontainers/distribution-spec/tree/main/extensions
|
|
@ -5,13 +5,16 @@ package extensions
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
goSync "sync"
|
||||
"time"
|
||||
|
||||
gqlHandler "github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/gorilla/mux"
|
||||
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
"zotregistry.io/zot/pkg/extensions/scrub"
|
||||
"zotregistry.io/zot/pkg/extensions/search"
|
||||
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
|
||||
|
@ -61,9 +64,10 @@ func EnableExtensions(config *config.Config, log log.Logger, rootDir string) {
|
|||
*config.Extensions.Metrics.Enable &&
|
||||
config.Extensions.Metrics.Prometheus != nil {
|
||||
if config.Extensions.Metrics.Prometheus.Path == "" {
|
||||
config.Extensions.Metrics.Prometheus.Path = "/metrics"
|
||||
config.Extensions.Metrics.Prometheus.Path = constants.DefaultMetricsExtensionRoute
|
||||
|
||||
log.Warn().Msg("Prometheus instrumentation Path not set, changing to '/metrics'.")
|
||||
log.Warn().Msg(fmt.Sprintf("Prometheus instrumentation Path not set, changing to %s.",
|
||||
constants.DefaultMetricsExtensionRoute))
|
||||
}
|
||||
} else {
|
||||
log.Info().Msg("Metrics config not provided, skipping Metrics config update")
|
||||
|
@ -108,9 +112,34 @@ func EnableScrubExtension(config *config.Config, storeController storage.StoreCo
|
|||
}
|
||||
}
|
||||
|
||||
func getExtension(name, url, description string) distext.Extension {
|
||||
return distext.Extension{
|
||||
Name: name,
|
||||
URL: url,
|
||||
Description: description,
|
||||
}
|
||||
}
|
||||
|
||||
func GetExtensions(config *config.Config) distext.ExtensionList {
|
||||
extensionList := distext.ExtensionList{}
|
||||
|
||||
extensions := make([]distext.Extension, 0)
|
||||
|
||||
if config.Extensions != nil && config.Extensions.Search != nil {
|
||||
searchExt := getExtension("search",
|
||||
"https://github.com/project-zot/zot/tree/main/pkg/extensions/search/_search.md",
|
||||
"search extension to provide various search feature e.g cve")
|
||||
|
||||
extensions = append(extensions, searchExt)
|
||||
}
|
||||
|
||||
extensionList.Extensions = extensions
|
||||
|
||||
return extensionList
|
||||
}
|
||||
|
||||
// SetupRoutes ...
|
||||
func SetupRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||
l log.Logger,
|
||||
func SetupRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController, l log.Logger,
|
||||
) {
|
||||
// fork a new zerolog child to avoid data race
|
||||
log := log.Logger{Logger: l.With().Caller().Timestamp().Logger()}
|
||||
|
@ -125,7 +154,7 @@ func SetupRoutes(config *config.Config, router *mux.Router, storeController stor
|
|||
resConfig = search.GetResolverConfig(log, storeController, false)
|
||||
}
|
||||
|
||||
router.PathPrefix("/query").Methods("GET", "POST", "OPTIONS").
|
||||
router.PathPrefix(constants.ExtSearchPrefix).Methods("OPTIONS", "GET", "POST").
|
||||
Handler(gqlHandler.NewDefaultServer(search.NewExecutableSchema(resConfig)))
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
|
@ -25,6 +26,11 @@ func EnableExtensions(config *config.Config, log log.Logger, rootDir string) {
|
|||
"any extensions, please build zot full binary for this feature")
|
||||
}
|
||||
|
||||
// GetExtensions...
|
||||
func GetExtensions(config *config.Config) distext.ExtensionList {
|
||||
return distext.ExtensionList{}
|
||||
}
|
||||
|
||||
// EnableSyncExtension ...
|
||||
func EnableSyncExtension(ctx context.Context, config *config.Config, wg *goSync.WaitGroup,
|
||||
storeController storage.StoreController, log log.Logger,
|
||||
|
@ -42,7 +48,8 @@ func EnableScrubExtension(config *config.Config, storeController storage.StoreCo
|
|||
}
|
||||
|
||||
// SetupRoutes ...
|
||||
func SetupRoutes(conf *config.Config, router *mux.Router, storeController storage.StoreController, log log.Logger) {
|
||||
func SetupRoutes(conf *config.Config, router *mux.Router, storeController storage.StoreController, log log.Logger,
|
||||
) {
|
||||
log.Warn().Msg("skipping setting up extensions routes because given zot binary doesn't support " +
|
||||
"any extensions, please build zot full binary for this feature")
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"gopkg.in/resty.v1"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
"zotregistry.io/zot/pkg/extensions/search/common"
|
||||
|
@ -24,6 +25,10 @@ import (
|
|||
. "zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
|
||||
const (
|
||||
graphqlQueryPrefix = constants.ExtSearchPrefix
|
||||
)
|
||||
|
||||
// nolint:gochecknoglobals
|
||||
var (
|
||||
rootDir string
|
||||
|
@ -225,12 +230,12 @@ func TestLatestTagSearchHTTP(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -243,7 +248,7 @@ func TestLatestTagSearchHTTP(t *testing.T) {
|
|||
images := responseStruct.ImgListWithLatestTag.Images
|
||||
So(images[0].Latest, ShouldEqual, "0.0.1")
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
|
@ -252,7 +257,7 @@ func TestLatestTagSearchHTTP(t *testing.T) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -273,7 +278,7 @@ func TestLatestTagSearchHTTP(t *testing.T) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -284,7 +289,7 @@ func TestLatestTagSearchHTTP(t *testing.T) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -295,7 +300,7 @@ func TestLatestTagSearchHTTP(t *testing.T) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -307,7 +312,7 @@ func TestLatestTagSearchHTTP(t *testing.T) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query={ImageListWithLatestTag(){Name%20Latest}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -363,14 +368,14 @@ func TestExpandedRepoInfo(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query")
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
query := "{ExpandedRepoInfo(repo:\"zot-test\"){Manifests%20{Digest%20IsSigned%20Tag%20Layers%20{Size%20Digest}}}}"
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query=" + query)
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + query)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -384,13 +389,13 @@ func TestExpandedRepoInfo(t *testing.T) {
|
|||
|
||||
query = "{ExpandedRepoInfo(repo:\"\"){Manifests%20{Digest%20Tag%20IsSigned%20Layers%20{Size%20Digest}}}}"
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query=" + query)
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + query)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
query = "{ExpandedRepoInfo(repo:\"a/zot-test\"){Manifests%20{Digest%20Tag%20IsSigned%20%Layers%20{Size%20Digest}}}}"
|
||||
resp, err = resty.R().Get(baseURL + "/query?query=" + query)
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + query)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -408,7 +413,7 @@ func TestExpandedRepoInfo(t *testing.T) {
|
|||
|
||||
query = "{ExpandedRepoInfo(repo:\"zot-test\"){Manifests%20{Digest%20Tag%20IsSigned%20%Layers%20{Size%20Digest}}}}"
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query=" + query)
|
||||
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + query)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"gopkg.in/resty.v1"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
"zotregistry.io/zot/pkg/extensions/search/common"
|
||||
|
@ -430,7 +431,7 @@ func TestCVESearch(t *testing.T) {
|
|||
err = json.Unmarshal(resp.Body(), &apiErr)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query/")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 401)
|
||||
|
@ -446,11 +447,11 @@ func TestCVESearch(t *testing.T) {
|
|||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
|
@ -461,7 +462,7 @@ func TestCVESearch(t *testing.T) {
|
|||
|
||||
cvid := cveResult.ImgList.CVEResultForImage.CVEList[0].ID
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-test\"){Tags{Name%20Timestamp}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-test\"){Tags{Name%20Timestamp}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
|
@ -470,7 +471,7 @@ func TestCVESearch(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
So(len(imgFixedCVEResult.ImgResults.ImgResultForFixedCVE.Tags), ShouldEqual, 0)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-cve-test\"){Tags{Name%20Timestamp}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-cve-test\"){Tags{Name%20Timestamp}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
|
@ -478,11 +479,11 @@ func TestCVESearch(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
So(len(imgFixedCVEResult.ImgResults.ImgResultForFixedCVE.Tags), ShouldEqual, 0)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-test\"){Tags{Name%20Timestamp}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-test\"){Tags{Name%20Timestamp}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"b/zot-squashfs-test:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"b/zot-squashfs-test:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
|
@ -491,108 +492,108 @@ func TestCVESearch(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
So(len(cveSquashFSResult.ImgList.CVEResultForImage.CVEList), ShouldBeZeroValue)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-squashfs-noindex:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-noindex:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-noindex\"){Tags{Name%20Timestamp}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-noindex\"){Tags{Name%20Timestamp}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-squashfs-invalid-index:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-invalid-index:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-invalid-index\"){Tags{Name%20Timestamp}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-invalid-index\"){Tags{Name%20Timestamp}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-squashfs-noblobs:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-noblobs:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-noblob\"){Tags{Name%20Timestamp}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-noblob\"){Tags{Name%20Timestamp}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-test\"){Tags{Name%20Timestamp}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-test\"){Tags{Name%20Timestamp}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-squashfs-invalid-blob:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-invalid-blob:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-invalid-blob\"){Tags{Name%20Timestamp}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-invalid-blob\"){Tags{Name%20Timestamp}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-squashfs-test\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-test\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"cntos\"){Tag%20CVEList{Id%20Description%20Severity}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"cntos\"){Tag%20CVEList{Id%20Description%20Severity}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListForCVE(id:\"CVE-201-20482\"){Name%20Tags}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test\"){Tag%20CVEList{Id%20Description}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test\"){Tag%20CVEList{Id%20Description}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){Tag}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Tag}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Description%20Severity}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Description%20Severity}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Description%20Severity}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Description%20Severity}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Severity}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Severity}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Description}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Description}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Description}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Description}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
// Testing Invalid Search URL
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(image:\"zot-test:0.0.1\"){Ta%20CVEList{Id%20Description%20Severity}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Ta%20CVEList{Id%20Description%20Severity}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 422)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListForCVE(tet:\"CVE-2018-20482\"){Name%20Tags}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListForCVE(tet:\"CVE-2018-20482\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 422)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageistForCVE(id:\"CVE-2018-20482\"){Name%20Tags}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageistForCVE(id:\"CVE-2018-20482\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 422)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListForCVE(id:\"CVE-2018-20482\"){ame%20Tags}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListForCVE(id:\"CVE-2018-20482\"){ame%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 422)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={CVEListForImage(reo:\"zot-test:1.0.0\"){Tag%20CVEList{Id%20Description%20Severity}}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={CVEListForImage(reo:\"zot-test:1.0.0\"){Tag%20CVEList{Id%20Description%20Severity}}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 422)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/query?query={ImageListForCVE(id:\"" + cvid + "\"){Name%20Tags}}")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.ExtSearchPrefix + "?query={ImageListForCVE(id:\"" + cvid + "\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
})
|
||||
|
@ -648,11 +649,11 @@ func TestCVEConfig(t *testing.T) {
|
|||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
resp, _ := resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/")
|
||||
resp, _ := resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.RoutePrefix + "/")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/_catalog")
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.RoutePrefix + constants.ExtCatalogPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
|
@ -721,7 +722,7 @@ func TestHTTPOptionsResponse(t *testing.T) {
|
|||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
resp, _ := resty.R().Options(baseURL + "/v2/_catalog")
|
||||
resp, _ := resty.R().Options(baseURL + constants.RoutePrefix + constants.ExtCatalogPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNoContent)
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"gopkg.in/resty.v1"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
digestinfo "zotregistry.io/zot/pkg/extensions/search/digest"
|
||||
|
@ -179,13 +180,14 @@ func TestDigestSearchHTTP(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
// "sha" should match all digests in all images
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListForDigest(id:\"sha\"){Name%20Tags}}")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix +
|
||||
"?query={ImageListForDigest(id:\"sha\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -200,7 +202,8 @@ func TestDigestSearchHTTP(t *testing.T) {
|
|||
|
||||
// Call should return {"data":{"ImageListForDigest":[{"Name":"zot-test","Tags":["0.0.1"]}]}}
|
||||
// "2bacca16" should match the manifest of 1 image
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListForDigest(id:\"2bacca16\"){Name%20Tags}}")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix +
|
||||
"?query={ImageListForDigest(id:\"2bacca16\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -215,7 +218,8 @@ func TestDigestSearchHTTP(t *testing.T) {
|
|||
|
||||
// Call should return {"data":{"ImageListForDigest":[{"Name":"zot-test","Tags":["0.0.1"]}]}}
|
||||
// "adf3bb6c" should match the config of 1 image
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListForDigest(id:\"adf3bb6c\"){Name%20Tags}}")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix +
|
||||
"?query={ImageListForDigest(id:\"adf3bb6c\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -230,7 +234,8 @@ func TestDigestSearchHTTP(t *testing.T) {
|
|||
|
||||
// Call should return {"data":{"ImageListForDigest":[{"Name":"zot-cve-test","Tags":["0.0.1"]}]}}
|
||||
// "7a0437f0" should match the layer of 1 image
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListForDigest(id:\"7a0437f0\"){Name%20Tags}}")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix +
|
||||
"?query={ImageListForDigest(id:\"7a0437f0\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -245,7 +250,8 @@ func TestDigestSearchHTTP(t *testing.T) {
|
|||
|
||||
// Call should return {"data":{"ImageListForDigest":[]}}
|
||||
// "1111111" should match 0 images
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListForDigest(id:\"1111111\"){Name%20Tags}}")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix +
|
||||
"?query={ImageListForDigest(id:\"1111111\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -256,7 +262,8 @@ func TestDigestSearchHTTP(t *testing.T) {
|
|||
So(len(responseStruct.ImgListForDigest.Images), ShouldEqual, 0)
|
||||
|
||||
// Call should return {"errors": [{....}]", data":null}}
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListForDigest(id:\"1111111\"){Name%20Tag343s}}")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix +
|
||||
"?query={ImageListForDigest(id:\"1111111\"){Name%20Tag343s}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 422)
|
||||
|
@ -321,12 +328,13 @@ func TestDigestSearchHTTPSubPaths(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query?query={ImageListForDigest(id:\"sha\"){Name%20Tags}}")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix +
|
||||
"?query={ImageListForDigest(id:\"sha\"){Name%20Tags}}")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -380,7 +388,7 @@ func TestDigestSearchDisabled(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
resp, err = resty.R().Get(baseURL + "/query")
|
||||
resp, err = resty.R().Get(baseURL + constants.ExtSearchPrefix)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 404)
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"gopkg.in/resty.v1"
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
|
@ -77,7 +78,7 @@ type Tags struct {
|
|||
func getUpstreamCatalog(client *resty.Client, upstreamURL string, log log.Logger) (catalog, error) {
|
||||
var catalog catalog
|
||||
|
||||
registryCatalogURL := fmt.Sprintf("%s%s", upstreamURL, "/v2/_catalog")
|
||||
registryCatalogURL := fmt.Sprintf("%s%s%s", upstreamURL, constants.RoutePrefix, constants.ExtCatalogPrefix)
|
||||
|
||||
resp, err := client.R().SetHeader("Content-Type", "application/json").Get(registryCatalogURL)
|
||||
if err != nil {
|
||||
|
|
|
@ -37,6 +37,7 @@ import (
|
|||
"gopkg.in/resty.v1"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/api/constants"
|
||||
"zotregistry.io/zot/pkg/cli"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/sync"
|
||||
|
@ -1315,11 +1316,11 @@ func TestNoImagesByRegex(t *testing.T) {
|
|||
dctlr.Shutdown()
|
||||
}()
|
||||
|
||||
resp, err := destClient.R().Get(destBaseURL + "/v2/" + testImage + "/manifests/" + testImageTag)
|
||||
resp, err := destClient.R().Get(destBaseURL + constants.RoutePrefix + testImage + "/manifests/" + testImageTag)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 404)
|
||||
|
||||
resp, err = destClient.R().Get(destBaseURL + "/v2/_catalog")
|
||||
resp, err = destClient.R().Get(destBaseURL + constants.RoutePrefix + constants.ExtCatalogPrefix)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeEmpty)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
@ -1743,7 +1744,7 @@ func TestSubPaths(t *testing.T) {
|
|||
var destTagsList TagsList
|
||||
|
||||
for {
|
||||
resp, err := resty.R().Get(destBaseURL + "/v2" + path.Join(subpath, testImage) + "/tags/list")
|
||||
resp, err := resty.R().Get(destBaseURL + constants.RoutePrefix + path.Join(subpath, testImage) + "/tags/list")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -2169,7 +2170,7 @@ func TestPeriodicallySignaturesErr(t *testing.T) {
|
|||
cosignTag := string(imageManifestDigest.Algorithm()) + "-" + imageManifestDigest.Hex() +
|
||||
"." + remote.SignatureTagSuffix
|
||||
|
||||
getCosignManifestURL := srcBaseURL + path.Join("/v2", repoName, "manifests", cosignTag)
|
||||
getCosignManifestURL := srcBaseURL + path.Join(constants.RoutePrefix, repoName, "manifests", cosignTag)
|
||||
mResp, err := resty.R().Get(getCosignManifestURL)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
|
@ -2444,7 +2445,7 @@ func TestSignatures(t *testing.T) {
|
|||
// test cosign signatures errors
|
||||
// based on manifest digest get cosign manifest
|
||||
cosignEncodedDigest := strings.Replace(digest.String(), ":", "-", 1) + ".sig"
|
||||
getCosignManifestURL := srcBaseURL + path.Join("/v2", repoName, "manifests", cosignEncodedDigest)
|
||||
getCosignManifestURL := srcBaseURL + path.Join(constants.RoutePrefix, repoName, "manifests", cosignEncodedDigest)
|
||||
|
||||
mResp, err := resty.R().Get(getCosignManifestURL)
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -3057,7 +3058,7 @@ func TestSignaturesOnDemand(t *testing.T) {
|
|||
|
||||
// test negative case
|
||||
cosignEncodedDigest := strings.Replace(digest.String(), ":", "-", 1) + ".sig"
|
||||
getCosignManifestURL := srcBaseURL + path.Join("/v2", repoName, "manifests", cosignEncodedDigest)
|
||||
getCosignManifestURL := srcBaseURL + path.Join(constants.RoutePrefix, repoName, "manifests", cosignEncodedDigest)
|
||||
|
||||
mResp, err := resty.R().Get(getCosignManifestURL)
|
||||
So(err, ShouldBeNil)
|
||||
|
|
163
swagger/docs.go
163
swagger/docs.go
|
@ -1,12 +1,13 @@
|
|||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag at
|
||||
// 2019-12-11 12:03:05.055900322 -0800 PST m=+0.052058015
|
||||
// 2022-05-20 22:28:21.990630149 +0000 UTC m=+0.151110280
|
||||
|
||||
package swagger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/template"
|
||||
"github.com/swaggo/swag"
|
||||
|
@ -16,8 +17,8 @@ var doc = `{
|
|||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "APIs for Open Container Initiative Distribution Specification",
|
||||
"title": "Open Container Initiative Distribution Specification",
|
||||
"description": "{{.Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"contact": {
|
||||
"name": "API Support",
|
||||
"url": "http://www.swagger.io/support",
|
||||
|
@ -27,11 +28,66 @@ var doc = `{
|
|||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "v0.1.0-dev"
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/oras/artifacts/v1/{name": {
|
||||
"get": {
|
||||
"description": "Get references for an image given a digest and artifact type",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Get references for an image",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "repository name",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "image digest",
|
||||
"name": "digest",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "artifact type",
|
||||
"name": "artifactType",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "not found",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/": {
|
||||
"get": {
|
||||
"description": "Check if this API version is supported",
|
||||
|
@ -44,7 +100,7 @@ var doc = `{
|
|||
"summary": "Check API support",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"description": "ok\".",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -66,7 +122,6 @@ var doc = `{
|
|||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.RepositoryList"
|
||||
}
|
||||
},
|
||||
|
@ -79,6 +134,26 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v2/_oci/ext/discover": {
|
||||
"get": {
|
||||
"description": "List all extensions present on registry",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "List Registry level extensions",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.ExtensionList"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/{name}/blobs/uploads": {
|
||||
"post": {
|
||||
"description": "Create a new image blob/layer upload",
|
||||
|
@ -107,7 +182,7 @@ var doc = `{
|
|||
"headers": {
|
||||
"Location": {
|
||||
"type": "string",
|
||||
"description": "/v2/{name}/blobs/uploads/{uuid}"
|
||||
"description": "/v2/{name}/blobs/uploads/{session_id}"
|
||||
},
|
||||
"Range": {
|
||||
"type": "string",
|
||||
|
@ -130,9 +205,9 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v2/{name}/blobs/uploads/{uuid}": {
|
||||
"/v2/{name}/blobs/uploads/{session_id}": {
|
||||
"get": {
|
||||
"description": "Get an image's blob/layer upload given a uuid",
|
||||
"description": "Get an image's blob/layer upload given a session_id",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -150,8 +225,8 @@ var doc = `{
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "upload uuid",
|
||||
"name": "uuid",
|
||||
"description": "upload session_id",
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
|
@ -196,8 +271,8 @@ var doc = `{
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "upload uuid",
|
||||
"name": "uuid",
|
||||
"description": "upload session_id",
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
|
@ -249,8 +324,8 @@ var doc = `{
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "upload uuid",
|
||||
"name": "uuid",
|
||||
"description": "upload session_id",
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
|
@ -277,7 +352,7 @@ var doc = `{
|
|||
}
|
||||
},
|
||||
"patch": {
|
||||
"description": "Resume an image's blob/layer upload given an uuid",
|
||||
"description": "Resume an image's blob/layer upload given an session_id",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -295,8 +370,8 @@ var doc = `{
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "upload uuid",
|
||||
"name": "uuid",
|
||||
"description": "upload session_id",
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
|
@ -310,7 +385,7 @@ var doc = `{
|
|||
"headers": {
|
||||
"Location": {
|
||||
"type": "string",
|
||||
"description": "/v2/{name}/blobs/uploads/{uuid}"
|
||||
"description": "/v2/{name}/blobs/uploads/{session_id}"
|
||||
},
|
||||
"Range": {
|
||||
"type": "string",
|
||||
|
@ -375,7 +450,6 @@ var doc = `{
|
|||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.ImageManifest"
|
||||
}
|
||||
}
|
||||
|
@ -444,11 +518,10 @@ var doc = `{
|
|||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.ImageManifest"
|
||||
},
|
||||
"headers": {
|
||||
"api.DistContentDigestKey": {
|
||||
"constants.DistContentDigestKey": {
|
||||
"type": "object",
|
||||
"description": "OK"
|
||||
}
|
||||
|
@ -487,11 +560,10 @@ var doc = `{
|
|||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.ImageManifest"
|
||||
},
|
||||
"headers": {
|
||||
"api.DistContentDigestKey": {
|
||||
"constants.DistContentDigestKey": {
|
||||
"type": "object",
|
||||
"description": "OK"
|
||||
}
|
||||
|
@ -629,7 +701,7 @@ var doc = `{
|
|||
"type": "string"
|
||||
},
|
||||
"headers": {
|
||||
"api.DistContentDigestKey": {
|
||||
"cosntants.DistContentDigestKey": {
|
||||
"type": "object",
|
||||
"description": "OK"
|
||||
}
|
||||
|
@ -642,7 +714,7 @@ var doc = `{
|
|||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"description": "internal server error\".",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -667,16 +739,35 @@ var doc = `{
|
|||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "limit entries for pagination",
|
||||
"name": "n",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "last tag value for pagination",
|
||||
"name": "last",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.ImageTags"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "bad request\".",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "not found",
|
||||
"schema": {
|
||||
|
@ -688,6 +779,9 @@ var doc = `{
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"api.ExtensionList": {
|
||||
"type": "object"
|
||||
},
|
||||
"api.ImageManifest": {
|
||||
"type": "object"
|
||||
},
|
||||
|
@ -729,7 +823,14 @@ type swaggerInfo struct {
|
|||
}
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = swaggerInfo{Schemes: []string{}}
|
||||
var SwaggerInfo = swaggerInfo{
|
||||
Version: "v0.1.0-dev",
|
||||
Host: "",
|
||||
BasePath: "",
|
||||
Schemes: []string{},
|
||||
Title: "Open Container Initiative Distribution Specification",
|
||||
Description: "APIs for Open Container Initiative Distribution Specification",
|
||||
}
|
||||
|
||||
type s struct{}
|
||||
|
||||
|
@ -737,7 +838,11 @@ func New() *s {
|
|||
return &s{}
|
||||
}
|
||||
|
||||
|
||||
func (s *s) ReadDoc() string {
|
||||
sInfo := SwaggerInfo
|
||||
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
|
||||
|
||||
t, err := template.New("swagger_info").Funcs(template.FuncMap{
|
||||
"marshal": func(v interface{}) string {
|
||||
a, _ := json.Marshal(v)
|
||||
|
@ -749,7 +854,7 @@ func (s *s) ReadDoc() string {
|
|||
}
|
||||
|
||||
var tpl bytes.Buffer
|
||||
if err := t.Execute(&tpl, SwaggerInfo); err != nil {
|
||||
if err := t.Execute(&tpl, sInfo); err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,62 @@
|
|||
},
|
||||
"version": "v0.1.0-dev"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/oras/artifacts/v1/{name": {
|
||||
"get": {
|
||||
"description": "Get references for an image given a digest and artifact type",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Get references for an image",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "repository name",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "image digest",
|
||||
"name": "digest",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "artifact type",
|
||||
"name": "artifactType",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "not found",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/": {
|
||||
"get": {
|
||||
"description": "Check if this API version is supported",
|
||||
|
@ -29,7 +82,7 @@
|
|||
"summary": "Check API support",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"description": "ok\".",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -51,7 +104,6 @@
|
|||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.RepositoryList"
|
||||
}
|
||||
},
|
||||
|
@ -64,6 +116,26 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v2/_oci/ext/discover": {
|
||||
"get": {
|
||||
"description": "List all extensions present on registry",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "List Registry level extensions",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/api.ExtensionList"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v2/{name}/blobs/uploads": {
|
||||
"post": {
|
||||
"description": "Create a new image blob/layer upload",
|
||||
|
@ -92,7 +164,7 @@
|
|||
"headers": {
|
||||
"Location": {
|
||||
"type": "string",
|
||||
"description": "/v2/{name}/blobs/uploads/{uuid}"
|
||||
"description": "/v2/{name}/blobs/uploads/{session_id}"
|
||||
},
|
||||
"Range": {
|
||||
"type": "string",
|
||||
|
@ -115,9 +187,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v2/{name}/blobs/uploads/{uuid}": {
|
||||
"/v2/{name}/blobs/uploads/{session_id}": {
|
||||
"get": {
|
||||
"description": "Get an image's blob/layer upload given a uuid",
|
||||
"description": "Get an image's blob/layer upload given a session_id",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -135,8 +207,8 @@
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "upload uuid",
|
||||
"name": "uuid",
|
||||
"description": "upload session_id",
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
|
@ -181,8 +253,8 @@
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "upload uuid",
|
||||
"name": "uuid",
|
||||
"description": "upload session_id",
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
|
@ -234,8 +306,8 @@
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "upload uuid",
|
||||
"name": "uuid",
|
||||
"description": "upload session_id",
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
|
@ -262,7 +334,7 @@
|
|||
}
|
||||
},
|
||||
"patch": {
|
||||
"description": "Resume an image's blob/layer upload given an uuid",
|
||||
"description": "Resume an image's blob/layer upload given an session_id",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -280,8 +352,8 @@
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "upload uuid",
|
||||
"name": "uuid",
|
||||
"description": "upload session_id",
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
|
@ -295,7 +367,7 @@
|
|||
"headers": {
|
||||
"Location": {
|
||||
"type": "string",
|
||||
"description": "/v2/{name}/blobs/uploads/{uuid}"
|
||||
"description": "/v2/{name}/blobs/uploads/{session_id}"
|
||||
},
|
||||
"Range": {
|
||||
"type": "string",
|
||||
|
@ -360,7 +432,6 @@
|
|||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.ImageManifest"
|
||||
}
|
||||
}
|
||||
|
@ -429,11 +500,10 @@
|
|||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.ImageManifest"
|
||||
},
|
||||
"headers": {
|
||||
"api.DistContentDigestKey": {
|
||||
"constants.DistContentDigestKey": {
|
||||
"type": "object",
|
||||
"description": "OK"
|
||||
}
|
||||
|
@ -472,11 +542,10 @@
|
|||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.ImageManifest"
|
||||
},
|
||||
"headers": {
|
||||
"api.DistContentDigestKey": {
|
||||
"constants.DistContentDigestKey": {
|
||||
"type": "object",
|
||||
"description": "OK"
|
||||
}
|
||||
|
@ -614,7 +683,7 @@
|
|||
"type": "string"
|
||||
},
|
||||
"headers": {
|
||||
"api.DistContentDigestKey": {
|
||||
"cosntants.DistContentDigestKey": {
|
||||
"type": "object",
|
||||
"description": "OK"
|
||||
}
|
||||
|
@ -627,7 +696,7 @@
|
|||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"description": "internal server error\".",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -652,16 +721,35 @@
|
|||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "limit entries for pagination",
|
||||
"name": "n",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "last tag value for pagination",
|
||||
"name": "last",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/api.ImageTags"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "bad request\".",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "not found",
|
||||
"schema": {
|
||||
|
@ -673,6 +761,9 @@
|
|||
}
|
||||
},
|
||||
"definitions": {
|
||||
"api.ExtensionList": {
|
||||
"type": "object"
|
||||
},
|
||||
"api.ImageManifest": {
|
||||
"type": "object"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
basePath: '{{.BasePath}}'
|
||||
definitions:
|
||||
api.ExtensionList:
|
||||
type: object
|
||||
api.ImageManifest:
|
||||
type: object
|
||||
api.ImageTags:
|
||||
|
@ -18,7 +19,6 @@ definitions:
|
|||
type: string
|
||||
type: array
|
||||
type: object
|
||||
host: '{{.Host}}'
|
||||
info:
|
||||
contact:
|
||||
email: support@swagger.io
|
||||
|
@ -31,6 +31,43 @@ info:
|
|||
title: Open Container Initiative Distribution Specification
|
||||
version: v0.1.0-dev
|
||||
paths:
|
||||
/oras/artifacts/v1/{name:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Get references for an image given a digest and artifact type
|
||||
parameters:
|
||||
- description: repository name
|
||||
in: path
|
||||
name: name
|
||||
required: true
|
||||
type: string
|
||||
- description: image digest
|
||||
in: path
|
||||
name: digest
|
||||
required: true
|
||||
type: string
|
||||
- description: artifact type
|
||||
in: query
|
||||
name: artifactType
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: ok
|
||||
schema:
|
||||
type: string
|
||||
"404":
|
||||
description: not found
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
type: string
|
||||
summary: Get references for an image
|
||||
/v2/:
|
||||
get:
|
||||
consumes:
|
||||
|
@ -40,7 +77,7 @@ paths:
|
|||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: ok
|
||||
description: ok".
|
||||
schema:
|
||||
type: string
|
||||
summary: Check API support
|
||||
|
@ -56,12 +93,24 @@ paths:
|
|||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/api.RepositoryList'
|
||||
type: object
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
type: string
|
||||
summary: List image repositories
|
||||
/v2/_oci/ext/discover:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: List all extensions present on registry
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/api.ExtensionList'
|
||||
summary: List Registry level extensions
|
||||
/v2/{name}/blobs/{digest}:
|
||||
delete:
|
||||
consumes:
|
||||
|
@ -108,7 +157,6 @@ paths:
|
|||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/api.ImageManifest'
|
||||
type: object
|
||||
summary: Get image blob/layer
|
||||
head:
|
||||
consumes:
|
||||
|
@ -131,12 +179,11 @@ paths:
|
|||
"200":
|
||||
description: OK
|
||||
headers:
|
||||
api.DistContentDigestKey:
|
||||
constants.DistContentDigestKey:
|
||||
description: OK
|
||||
type: object
|
||||
schema:
|
||||
$ref: '#/definitions/api.ImageManifest'
|
||||
type: object
|
||||
summary: Check image blob/layer
|
||||
/v2/{name}/blobs/uploads:
|
||||
post:
|
||||
|
@ -156,7 +203,7 @@ paths:
|
|||
description: accepted
|
||||
headers:
|
||||
Location:
|
||||
description: /v2/{name}/blobs/uploads/{uuid}
|
||||
description: /v2/{name}/blobs/uploads/{session_id}
|
||||
type: string
|
||||
Range:
|
||||
description: bytes=0-0
|
||||
|
@ -172,7 +219,7 @@ paths:
|
|||
schema:
|
||||
type: string
|
||||
summary: Create image blob/layer upload
|
||||
/v2/{name}/blobs/uploads/{uuid}:
|
||||
/v2/{name}/blobs/uploads/{session_id}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
|
@ -183,9 +230,9 @@ paths:
|
|||
name: name
|
||||
required: true
|
||||
type: string
|
||||
- description: upload uuid
|
||||
- description: upload session_id
|
||||
in: path
|
||||
name: uuid
|
||||
name: session_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
|
@ -207,16 +254,16 @@ paths:
|
|||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Get an image's blob/layer upload given a uuid
|
||||
description: Get an image's blob/layer upload given a session_id
|
||||
parameters:
|
||||
- description: repository name
|
||||
in: path
|
||||
name: name
|
||||
required: true
|
||||
type: string
|
||||
- description: upload uuid
|
||||
- description: upload session_id
|
||||
in: path
|
||||
name: uuid
|
||||
name: session_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
|
@ -238,16 +285,16 @@ paths:
|
|||
patch:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Resume an image's blob/layer upload given an uuid
|
||||
description: Resume an image's blob/layer upload given an session_id
|
||||
parameters:
|
||||
- description: repository name
|
||||
in: path
|
||||
name: name
|
||||
required: true
|
||||
type: string
|
||||
- description: upload uuid
|
||||
- description: upload session_id
|
||||
in: path
|
||||
name: uuid
|
||||
name: session_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
|
@ -257,7 +304,7 @@ paths:
|
|||
description: accepted
|
||||
headers:
|
||||
Location:
|
||||
description: /v2/{name}/blobs/uploads/{uuid}
|
||||
description: /v2/{name}/blobs/uploads/{session_id}
|
||||
type: string
|
||||
Range:
|
||||
description: bytes=0-128
|
||||
|
@ -291,9 +338,9 @@ paths:
|
|||
name: name
|
||||
required: true
|
||||
type: string
|
||||
- description: upload uuid
|
||||
- description: upload session_id
|
||||
in: path
|
||||
name: uuid
|
||||
name: session_id
|
||||
required: true
|
||||
type: string
|
||||
- description: blob/layer digest
|
||||
|
@ -362,12 +409,11 @@ paths:
|
|||
"200":
|
||||
description: OK
|
||||
headers:
|
||||
api.DistContentDigestKey:
|
||||
constants.DistContentDigestKey:
|
||||
description: OK
|
||||
type: object
|
||||
schema:
|
||||
$ref: '#/definitions/api.ImageManifest'
|
||||
type: object
|
||||
"404":
|
||||
description: not found
|
||||
schema:
|
||||
|
@ -398,7 +444,7 @@ paths:
|
|||
"200":
|
||||
description: ok
|
||||
headers:
|
||||
api.DistContentDigestKey:
|
||||
cosntants.DistContentDigestKey:
|
||||
description: OK
|
||||
type: object
|
||||
schema:
|
||||
|
@ -408,7 +454,7 @@ paths:
|
|||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: internal server error
|
||||
description: internal server error".
|
||||
schema:
|
||||
type: string
|
||||
summary: Check image manifest
|
||||
|
@ -458,6 +504,16 @@ paths:
|
|||
name: name
|
||||
required: true
|
||||
type: string
|
||||
- description: limit entries for pagination
|
||||
in: query
|
||||
name: "n"
|
||||
required: true
|
||||
type: integer
|
||||
- description: last tag value for pagination
|
||||
in: query
|
||||
name: last
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
|
@ -465,7 +521,10 @@ paths:
|
|||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/api.ImageTags'
|
||||
type: object
|
||||
"400":
|
||||
description: bad request".
|
||||
schema:
|
||||
type: string
|
||||
"404":
|
||||
description: not found
|
||||
schema:
|
||||
|
|
Loading…
Reference in a new issue