mirror of
https://github.com/project-zot/zot.git
synced 2024-12-30 22:34:13 -05:00
refactor(test): make sure cli tests are not internal unless they need to be (#1878)
As part of this change searchConfig needed to be exported, as it was passed as a parameter to exported functions At this moment most of the tests remaining internal depend on the mock service. The interface it implements has unexported methods. Signed-off-by: Andrei Aaron <aaaron@luxoft.com>
This commit is contained in:
parent
99e29c0f46
commit
ca1c3288cf
18 changed files with 3227 additions and 3118 deletions
|
@ -179,7 +179,7 @@ type httpJob struct {
|
||||||
password string
|
password string
|
||||||
imageName string
|
imageName string
|
||||||
tagName string
|
tagName string
|
||||||
config searchConfig
|
config SearchConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
const rateLimiterBuffer = 5000
|
const rateLimiterBuffer = 5000
|
||||||
|
@ -218,8 +218,8 @@ func (p *requestsPool) doJob(ctx context.Context, job *httpJob) {
|
||||||
defer p.wtgrp.Done()
|
defer p.wtgrp.Done()
|
||||||
|
|
||||||
// Check manifest media type
|
// Check manifest media type
|
||||||
header, err := makeHEADRequest(ctx, job.url, job.username, job.password, job.config.verifyTLS,
|
header, err := makeHEADRequest(ctx, job.url, job.username, job.password, job.config.VerifyTLS,
|
||||||
job.config.debug)
|
job.config.Debug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return
|
return
|
||||||
|
@ -227,7 +227,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *httpJob) {
|
||||||
p.outputCh <- stringResult{"", err}
|
p.outputCh <- stringResult{"", err}
|
||||||
}
|
}
|
||||||
|
|
||||||
verbose := job.config.verbose
|
verbose := job.config.Verbose
|
||||||
|
|
||||||
switch header.Get("Content-Type") {
|
switch header.Get("Content-Type") {
|
||||||
case ispec.MediaTypeImageManifest:
|
case ispec.MediaTypeImageManifest:
|
||||||
|
@ -242,7 +242,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *httpJob) {
|
||||||
}
|
}
|
||||||
platformStr := getPlatformStr(image.Manifests[0].Platform)
|
platformStr := getPlatformStr(image.Manifests[0].Platform)
|
||||||
|
|
||||||
str, err := image.string(job.config.outputFormat, len(job.imageName), len(job.tagName), len(platformStr), verbose)
|
str, err := image.string(job.config.OutputFormat, len(job.imageName), len(job.tagName), len(platformStr), verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return
|
return
|
||||||
|
@ -270,7 +270,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *httpJob) {
|
||||||
|
|
||||||
platformStr := getPlatformStr(image.Manifests[0].Platform)
|
platformStr := getPlatformStr(image.Manifests[0].Platform)
|
||||||
|
|
||||||
str, err := image.string(job.config.outputFormat, len(job.imageName), len(job.tagName), len(platformStr), verbose)
|
str, err := image.string(job.config.OutputFormat, len(job.imageName), len(job.tagName), len(platformStr), verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return
|
return
|
||||||
|
@ -294,7 +294,7 @@ func fetchImageIndexStruct(ctx context.Context, job *httpJob) (*imageStruct, err
|
||||||
var indexContent ispec.Index
|
var indexContent ispec.Index
|
||||||
|
|
||||||
header, err := makeGETRequest(ctx, job.url, job.username, job.password,
|
header, err := makeGETRequest(ctx, job.url, job.username, job.password,
|
||||||
job.config.verifyTLS, job.config.debug, &indexContent, job.config.resultWriter)
|
job.config.VerifyTLS, job.config.Debug, &indexContent, job.config.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return nil, context.Canceled
|
return nil, context.Canceled
|
||||||
|
@ -376,16 +376,16 @@ func fetchImageManifestStruct(ctx context.Context, job *httpJob) (*imageStruct,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchManifestStruct(ctx context.Context, repo, manifestReference string, searchConf searchConfig,
|
func fetchManifestStruct(ctx context.Context, repo, manifestReference string, searchConf SearchConfig,
|
||||||
username, password string,
|
username, password string,
|
||||||
) (common.ManifestSummary, error) {
|
) (common.ManifestSummary, error) {
|
||||||
manifestResp := ispec.Manifest{}
|
manifestResp := ispec.Manifest{}
|
||||||
|
|
||||||
URL := fmt.Sprintf("%s/v2/%s/manifests/%s",
|
URL := fmt.Sprintf("%s/v2/%s/manifests/%s",
|
||||||
searchConf.servURL, repo, manifestReference)
|
searchConf.ServURL, repo, manifestReference)
|
||||||
|
|
||||||
header, err := makeGETRequest(ctx, URL, username, password,
|
header, err := makeGETRequest(ctx, URL, username, password,
|
||||||
searchConf.verifyTLS, searchConf.debug, &manifestResp, searchConf.resultWriter)
|
searchConf.VerifyTLS, searchConf.Debug, &manifestResp, searchConf.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return common.ManifestSummary{}, context.Canceled
|
return common.ManifestSummary{}, context.Canceled
|
||||||
|
@ -465,16 +465,16 @@ func fetchManifestStruct(ctx context.Context, repo, manifestReference string, se
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchConfig(ctx context.Context, repo, configDigest string, searchConf searchConfig,
|
func fetchConfig(ctx context.Context, repo, configDigest string, searchConf SearchConfig,
|
||||||
username, password string,
|
username, password string,
|
||||||
) (ispec.Image, error) {
|
) (ispec.Image, error) {
|
||||||
configContent := ispec.Image{}
|
configContent := ispec.Image{}
|
||||||
|
|
||||||
URL := fmt.Sprintf("%s/v2/%s/blobs/%s",
|
URL := fmt.Sprintf("%s/v2/%s/blobs/%s",
|
||||||
searchConf.servURL, repo, configDigest)
|
searchConf.ServURL, repo, configDigest)
|
||||||
|
|
||||||
_, err := makeGETRequest(ctx, URL, username, password,
|
_, err := makeGETRequest(ctx, URL, username, password,
|
||||||
searchConf.verifyTLS, searchConf.debug, &configContent, searchConf.resultWriter)
|
searchConf.VerifyTLS, searchConf.Debug, &configContent, searchConf.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return ispec.Image{}, context.Canceled
|
return ispec.Image{}, context.Canceled
|
||||||
|
@ -486,16 +486,16 @@ func fetchConfig(ctx context.Context, repo, configDigest string, searchConf sear
|
||||||
return configContent, nil
|
return configContent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isNotationSigned(ctx context.Context, repo, digestStr string, searchConf searchConfig,
|
func isNotationSigned(ctx context.Context, repo, digestStr string, searchConf SearchConfig,
|
||||||
username, password string,
|
username, password string,
|
||||||
) bool {
|
) bool {
|
||||||
var referrers ispec.Index
|
var referrers ispec.Index
|
||||||
|
|
||||||
URL := fmt.Sprintf("%s/v2/%s/referrers/%s?artifactType=%s",
|
URL := fmt.Sprintf("%s/v2/%s/referrers/%s?artifactType=%s",
|
||||||
searchConf.servURL, repo, digestStr, common.ArtifactTypeNotation)
|
searchConf.ServURL, repo, digestStr, common.ArtifactTypeNotation)
|
||||||
|
|
||||||
_, err := makeGETRequest(ctx, URL, username, password,
|
_, err := makeGETRequest(ctx, URL, username, password,
|
||||||
searchConf.verifyTLS, searchConf.debug, &referrers, searchConf.resultWriter)
|
searchConf.VerifyTLS, searchConf.Debug, &referrers, searchConf.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -507,16 +507,16 @@ func isNotationSigned(ctx context.Context, repo, digestStr string, searchConf se
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isCosignSigned(ctx context.Context, repo, digestStr string, searchConf searchConfig,
|
func isCosignSigned(ctx context.Context, repo, digestStr string, searchConf SearchConfig,
|
||||||
username, password string,
|
username, password string,
|
||||||
) bool {
|
) bool {
|
||||||
var result interface{}
|
var result interface{}
|
||||||
cosignTag := strings.Replace(digestStr, ":", "-", 1) + "." + remote.SignatureTagSuffix
|
cosignTag := strings.Replace(digestStr, ":", "-", 1) + "." + remote.SignatureTagSuffix
|
||||||
|
|
||||||
URL := fmt.Sprintf("%s/v2/%s/manifests/%s", searchConf.servURL, repo, cosignTag)
|
URL := fmt.Sprintf("%s/v2/%s/manifests/%s", searchConf.ServURL, repo, cosignTag)
|
||||||
|
|
||||||
_, err := makeGETRequest(ctx, URL, username, password, searchConf.verifyTLS,
|
_, err := makeGETRequest(ctx, URL, username, password, searchConf.VerifyTLS,
|
||||||
searchConf.debug, &result, searchConf.resultWriter)
|
searchConf.Debug, &result, searchConf.ResultWriter)
|
||||||
|
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//go:build search
|
//go:build search
|
||||||
// +build search
|
// +build search
|
||||||
|
|
||||||
package client
|
package client_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -9,6 +9,7 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ import (
|
||||||
"zotregistry.io/zot/pkg/api"
|
"zotregistry.io/zot/pkg/api"
|
||||||
"zotregistry.io/zot/pkg/api/config"
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
"zotregistry.io/zot/pkg/api/constants"
|
"zotregistry.io/zot/pkg/api/constants"
|
||||||
|
"zotregistry.io/zot/pkg/cli/client"
|
||||||
extConf "zotregistry.io/zot/pkg/extensions/config"
|
extConf "zotregistry.io/zot/pkg/extensions/config"
|
||||||
test "zotregistry.io/zot/pkg/test/common"
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
)
|
)
|
||||||
|
@ -91,7 +93,7 @@ func TestTLSWithAuth(t *testing.T) {
|
||||||
defer os.RemoveAll(destCertsDir)
|
defer os.RemoveAll(destCertsDir)
|
||||||
|
|
||||||
args := []string{"name", "dummyImageName", "--url", HOST1}
|
args := []string{"name", "dummyImageName", "--url", HOST1}
|
||||||
imageCmd := NewImageCommand(new(searchService))
|
imageCmd := client.NewImageCommand(client.NewSearchService())
|
||||||
imageBuff := bytes.NewBufferString("")
|
imageBuff := bytes.NewBufferString("")
|
||||||
imageCmd.SetOut(imageBuff)
|
imageCmd.SetOut(imageBuff)
|
||||||
imageCmd.SetErr(imageBuff)
|
imageCmd.SetErr(imageBuff)
|
||||||
|
@ -105,7 +107,7 @@ func TestTLSWithAuth(t *testing.T) {
|
||||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
||||||
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
imageCmd = NewImageCommand(new(searchService))
|
imageCmd = client.NewImageCommand(client.NewSearchService())
|
||||||
imageBuff = bytes.NewBufferString("")
|
imageBuff = bytes.NewBufferString("")
|
||||||
imageCmd.SetOut(imageBuff)
|
imageCmd.SetOut(imageBuff)
|
||||||
imageCmd.SetErr(imageBuff)
|
imageCmd.SetErr(imageBuff)
|
||||||
|
@ -120,7 +122,7 @@ func TestTLSWithAuth(t *testing.T) {
|
||||||
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
|
||||||
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
imageCmd = NewImageCommand(new(searchService))
|
imageCmd = client.NewImageCommand(client.NewSearchService())
|
||||||
imageBuff = bytes.NewBufferString("")
|
imageBuff = bytes.NewBufferString("")
|
||||||
imageCmd.SetOut(imageBuff)
|
imageCmd.SetOut(imageBuff)
|
||||||
imageCmd.SetErr(imageBuff)
|
imageCmd.SetErr(imageBuff)
|
||||||
|
@ -174,7 +176,7 @@ func TestTLSWithoutAuth(t *testing.T) {
|
||||||
defer os.RemoveAll(destCertsDir)
|
defer os.RemoveAll(destCertsDir)
|
||||||
|
|
||||||
args := []string{"list", "--config", "imagetest"}
|
args := []string{"list", "--config", "imagetest"}
|
||||||
imageCmd := NewImageCommand(new(searchService))
|
imageCmd := client.NewImageCommand(client.NewSearchService())
|
||||||
imageBuff := bytes.NewBufferString("")
|
imageBuff := bytes.NewBufferString("")
|
||||||
imageCmd.SetOut(imageBuff)
|
imageCmd.SetOut(imageBuff)
|
||||||
imageCmd.SetErr(imageBuff)
|
imageCmd.SetErr(imageBuff)
|
||||||
|
@ -215,7 +217,7 @@ func TestTLSBadCerts(t *testing.T) {
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
args := []string{"list", "--config", "imagetest"}
|
args := []string{"list", "--config", "imagetest"}
|
||||||
imageCmd := NewImageCommand(new(searchService))
|
imageCmd := client.NewImageCommand(client.NewSearchService())
|
||||||
imageBuff := bytes.NewBufferString("")
|
imageBuff := bytes.NewBufferString("")
|
||||||
imageCmd.SetOut(imageBuff)
|
imageCmd.SetOut(imageBuff)
|
||||||
imageCmd.SetErr(imageBuff)
|
imageCmd.SetErr(imageBuff)
|
||||||
|
@ -226,3 +228,20 @@ func TestTLSBadCerts(t *testing.T) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeConfigFile(content string) string {
|
||||||
|
os.Setenv("HOME", os.TempDir())
|
||||||
|
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configPath := path.Join(home, "/.zot")
|
||||||
|
|
||||||
|
if err := os.WriteFile(configPath, []byte(content), 0o600); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return configPath
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
//go:build search
|
//go:build search
|
||||||
// +build search
|
// +build search
|
||||||
|
|
||||||
package client
|
package client_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -14,6 +14,7 @@ import (
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
|
||||||
zerr "zotregistry.io/zot/errors"
|
zerr "zotregistry.io/zot/errors"
|
||||||
|
"zotregistry.io/zot/pkg/cli/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigCmdBasics(t *testing.T) {
|
func TestConfigCmdBasics(t *testing.T) {
|
||||||
|
@ -21,7 +22,7 @@ func TestConfigCmdBasics(t *testing.T) {
|
||||||
args := []string{"--help"}
|
args := []string{"--help"}
|
||||||
configPath := makeConfigFile("showspinner = false")
|
configPath := makeConfigFile("showspinner = false")
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -33,7 +34,7 @@ func TestConfigCmdBasics(t *testing.T) {
|
||||||
args[0] = "-h"
|
args[0] = "-h"
|
||||||
configPath := makeConfigFile("showspinner = false")
|
configPath := makeConfigFile("showspinner = false")
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -48,7 +49,7 @@ func TestConfigCmdBasics(t *testing.T) {
|
||||||
args := []string{}
|
args := []string{}
|
||||||
configPath := makeConfigFile("showspinner = false")
|
configPath := makeConfigFile("showspinner = false")
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -64,7 +65,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"add", "configtest1", "https://test-url.com"}
|
args := []string{"add", "configtest1", "https://test-url.com"}
|
||||||
file := makeConfigFile("")
|
file := makeConfigFile("")
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -90,7 +91,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -118,7 +119,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewConfigAddCommand()
|
cmd := client.NewConfigAddCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -140,7 +141,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"--list"}
|
args := []string{"--list"}
|
||||||
configPath := makeConfigFile(`{"configs":{"_name":"configtest","url":"https://test-url.com","showspinner":false}}`)
|
configPath := makeConfigFile(`{"configs":{"_name":"configtest","url":"https://test-url.com","showspinner":false}}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -153,7 +154,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"add", "configtest1", "test..com"}
|
args := []string{"add", "configtest1", "test..com"}
|
||||||
file := makeConfigFile("")
|
file := makeConfigFile("")
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -167,7 +168,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"remove", "configtest"}
|
args := []string{"remove", "configtest"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -185,7 +186,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"remove", "configtest"}
|
args := []string{"remove", "configtest"}
|
||||||
configPath := makeConfigFile(`{"configs":[]`)
|
configPath := makeConfigFile(`{"configs":[]`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -199,7 +200,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"remove", "configtest"}
|
args := []string{"remove", "configtest"}
|
||||||
configPath := makeConfigFile(`{"asdf":[]`)
|
configPath := makeConfigFile(`{"asdf":[]`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -213,7 +214,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"remove", "configtest"}
|
args := []string{"remove", "configtest"}
|
||||||
configPath := makeConfigFile(`{"configs":[asdad]`)
|
configPath := makeConfigFile(`{"configs":[asdad]`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -232,7 +233,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
err := os.Chmod(configPath, 0o400) // Read-only, so we fail only on updating the file, not reading
|
err := os.Chmod(configPath, 0o400) // Read-only, so we fail only on updating the file, not reading
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -246,7 +247,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"--list"}
|
args := []string{"--list"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -259,7 +260,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"-l"}
|
args := []string{"-l"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -273,7 +274,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"-l"}
|
args := []string{"-l"}
|
||||||
configPath := makeConfigFile(``)
|
configPath := makeConfigFile(``)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -288,7 +289,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "--list"}
|
args := []string{"configtest", "--list"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -302,7 +303,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "-l"}
|
args := []string{"configtest", "-l"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -317,7 +318,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "-l"}
|
args := []string{"configtest", "-l"}
|
||||||
configPath := makeConfigFile(``)
|
configPath := makeConfigFile(``)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -332,7 +333,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "url"}
|
args := []string{"configtest", "url"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -345,7 +346,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "url"}
|
args := []string{"configtest", "url"}
|
||||||
configPath := makeConfigFile(``)
|
configPath := makeConfigFile(``)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -360,7 +361,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "showspinner", "false"}
|
args := []string{"configtest", "showspinner", "false"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com"}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com"}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -381,7 +382,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "showspinner", "false"}
|
args := []string{"configtest", "showspinner", "false"}
|
||||||
configPath := makeConfigFile(``)
|
configPath := makeConfigFile(``)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -396,7 +397,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "url", "https://new-url.com"}
|
args := []string{"configtest", "url", "https://new-url.com"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -419,7 +420,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "showspinner", "--reset"}
|
args := []string{"configtest", "showspinner", "--reset"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -441,7 +442,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"configtest", "url", "--reset"}
|
args := []string{"configtest", "url", "--reset"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -455,7 +456,7 @@ func TestConfigCmdMain(t *testing.T) {
|
||||||
args := []string{"add", "configtest", "https://test-url.com/new"}
|
args := []string{"add", "configtest", "https://test-url.com/new"}
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewConfigCommand()
|
cmd := client.NewConfigCommand()
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
|
@ -6,22 +6,14 @@ package client
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
regTypes "github.com/google/go-containerregistry/pkg/v1/types"
|
|
||||||
godigest "github.com/opencontainers/go-digest"
|
|
||||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
|
||||||
zerr "zotregistry.io/zot/errors"
|
zerr "zotregistry.io/zot/errors"
|
||||||
|
@ -29,18 +21,7 @@ import (
|
||||||
"zotregistry.io/zot/pkg/api/config"
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
zcommon "zotregistry.io/zot/pkg/common"
|
zcommon "zotregistry.io/zot/pkg/common"
|
||||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
|
||||||
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
|
|
||||||
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
|
|
||||||
"zotregistry.io/zot/pkg/log"
|
|
||||||
mTypes "zotregistry.io/zot/pkg/meta/types"
|
|
||||||
"zotregistry.io/zot/pkg/storage"
|
|
||||||
"zotregistry.io/zot/pkg/storage/local"
|
|
||||||
test "zotregistry.io/zot/pkg/test/common"
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
"zotregistry.io/zot/pkg/test/deprecated"
|
|
||||||
. "zotregistry.io/zot/pkg/test/image-utils"
|
|
||||||
"zotregistry.io/zot/pkg/test/mocks"
|
|
||||||
ociutils "zotregistry.io/zot/pkg/test/oci-utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSearchCVECmd(t *testing.T) {
|
func TestSearchCVECmd(t *testing.T) {
|
||||||
|
@ -397,659 +378,6 @@ func TestSearchCVECmd(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNegativeServerResponse(t *testing.T) {
|
|
||||||
Convey("Test from real server without search endpoint", t, func() {
|
|
||||||
port := test.GetFreePort()
|
|
||||||
url := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
|
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
|
|
||||||
err := WriteImageToFileSystem(CreateDefaultVulnerableImage(), "zot-cve-test", "0.0.1", srcStorageCtlr)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
conf.Storage.RootDirectory = dir
|
|
||||||
trivyConfig := &extconf.TrivyConfig{
|
|
||||||
DBRepository: "ghcr.io/project-zot/trivy-db",
|
|
||||||
}
|
|
||||||
cveConfig := &extconf.CVEConfig{
|
|
||||||
UpdateInterval: 2,
|
|
||||||
Trivy: trivyConfig,
|
|
||||||
}
|
|
||||||
defaultVal := false
|
|
||||||
searchConfig := &extconf.SearchConfig{
|
|
||||||
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
|
||||||
CVE: cveConfig,
|
|
||||||
}
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: searchConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
logFile, err := os.CreateTemp(t.TempDir(), "zot-log*.txt")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logPath := logFile.Name()
|
|
||||||
defer os.Remove(logPath)
|
|
||||||
|
|
||||||
writers := io.MultiWriter(os.Stdout, logFile)
|
|
||||||
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Log.Logger = ctlr.Log.Output(writers)
|
|
||||||
|
|
||||||
cm := test.NewControllerManager(ctlr)
|
|
||||||
cm.StartAndWait(conf.HTTP.Port)
|
|
||||||
defer cm.StopServer()
|
|
||||||
|
|
||||||
_, err = test.ReadLogFileAndSearchString(logPath, "CVE config not provided, skipping CVE update", 90*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
Convey("Status Code Not Found", func() {
|
|
||||||
args := []string{"list", "zot-cve-test:0.0.1", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
So(err.Error(), ShouldContainSubstring, zerr.ErrExtensionNotEnabled.Error())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test non-existing manifest blob", t, func() {
|
|
||||||
port := test.GetFreePort()
|
|
||||||
url := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
|
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
imageStore := local.NewImageStore(dir, false, false,
|
|
||||||
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), nil, nil)
|
|
||||||
|
|
||||||
storeController := storage.StoreController{
|
|
||||||
DefaultStore: imageStore,
|
|
||||||
}
|
|
||||||
|
|
||||||
num := 10
|
|
||||||
config, layers, manifest, err := deprecated.GetRandomImageComponents(num) //nolint:staticcheck
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = WriteImageToFileSystem(
|
|
||||||
Image{
|
|
||||||
Manifest: manifest,
|
|
||||||
Layers: layers,
|
|
||||||
Config: config,
|
|
||||||
}, "zot-cve-test", "0.0.1", storeController,
|
|
||||||
)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = os.RemoveAll(path.Join(dir, "zot-cve-test/blobs"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.Storage.RootDirectory = dir
|
|
||||||
trivyConfig := &extconf.TrivyConfig{
|
|
||||||
DBRepository: "ghcr.io/project-zot/trivy-db",
|
|
||||||
}
|
|
||||||
cveConfig := &extconf.CVEConfig{
|
|
||||||
UpdateInterval: 2,
|
|
||||||
Trivy: trivyConfig,
|
|
||||||
}
|
|
||||||
defaultVal := true
|
|
||||||
searchConfig := &extconf.SearchConfig{
|
|
||||||
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
|
||||||
CVE: cveConfig,
|
|
||||||
}
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: searchConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
logFile, err := os.CreateTemp(t.TempDir(), "zot-log*.txt")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logPath := logFile.Name()
|
|
||||||
defer os.Remove(logPath)
|
|
||||||
|
|
||||||
writers := io.MultiWriter(os.Stdout, logFile)
|
|
||||||
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Log.Logger = ctlr.Log.Output(writers)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
if err := ctlr.Init(ctx); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctlr.CveScanner = getMockCveScanner(ctlr.MetaDB)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := ctlr.Run(ctx); !errors.Is(err, http.ErrServerClosed) {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
defer ctlr.Shutdown()
|
|
||||||
|
|
||||||
test.WaitTillServerReady(url)
|
|
||||||
|
|
||||||
_, err = test.ReadLogFileAndSearchString(logPath, "DB update completed, next update scheduled", 90*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"fixed", "zot-cve-test", "CVE-2019-9923", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//nolint:dupl
|
|
||||||
func TestServerCVEResponse(t *testing.T) {
|
|
||||||
port := test.GetFreePort()
|
|
||||||
url := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
|
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
conf.Storage.RootDirectory = dir
|
|
||||||
trivyConfig := &extconf.TrivyConfig{
|
|
||||||
DBRepository: "ghcr.io/project-zot/trivy-db",
|
|
||||||
}
|
|
||||||
cveConfig := &extconf.CVEConfig{
|
|
||||||
UpdateInterval: 2,
|
|
||||||
Trivy: trivyConfig,
|
|
||||||
}
|
|
||||||
defaultVal := true
|
|
||||||
searchConfig := &extconf.SearchConfig{
|
|
||||||
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
|
||||||
CVE: cveConfig,
|
|
||||||
}
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: searchConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
logFile, err := os.CreateTemp(t.TempDir(), "zot-log*.txt")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logPath := logFile.Name()
|
|
||||||
defer os.Remove(logPath)
|
|
||||||
|
|
||||||
writers := io.MultiWriter(os.Stdout, logFile)
|
|
||||||
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Log.Logger = ctlr.Log.Output(writers)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
if err := ctlr.Init(ctx); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctlr.CveScanner = getMockCveScanner(ctlr.MetaDB)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := ctlr.Run(ctx); !errors.Is(err, http.ErrServerClosed) {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
defer ctlr.Shutdown()
|
|
||||||
|
|
||||||
test.WaitTillServerReady(url)
|
|
||||||
|
|
||||||
config, layers, manifest, err := deprecated.GetImageComponents(100) //nolint:staticcheck
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = UploadImage(Image{Manifest: manifest, Config: config, Layers: layers}, url, "zot-cve-test", "0.0.1")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = test.ReadLogFileAndSearchString(logPath, "DB update completed, next update scheduled", 90*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
Convey("Test CVE by image name - GQL - positive", t, func() {
|
|
||||||
args := []string{"list", "zot-cve-test:0.0.1", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(str, ShouldContainSubstring, "ID SEVERITY TITLE")
|
|
||||||
So(str, ShouldContainSubstring, "CVE")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by image name - GQL - search CVE by title in results", t, func() {
|
|
||||||
args := []string{"list", "zot-cve-test:0.0.1", "--cve-id", "CVE-C1", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(str, ShouldContainSubstring, "ID SEVERITY TITLE")
|
|
||||||
So(str, ShouldContainSubstring, "CVE-C1")
|
|
||||||
So(str, ShouldNotContainSubstring, "CVE-2")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by image name - GQL - search CVE by id in results", t, func() {
|
|
||||||
args := []string{"list", "zot-cve-test:0.0.1", "--cve-id", "CVE-2", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(str, ShouldContainSubstring, "ID SEVERITY TITLE")
|
|
||||||
So(str, ShouldContainSubstring, "CVE-2")
|
|
||||||
So(str, ShouldNotContainSubstring, "CVE-1")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by image name - GQL - search nonexistent CVE", t, func() {
|
|
||||||
args := []string{"list", "zot-cve-test:0.0.1", "--cve-id", "CVE-100", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(str, ShouldContainSubstring, "No CVEs found for image")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by image name - GQL - invalid image", t, func() {
|
|
||||||
args := []string{"list", "invalid:0.0.1", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by image name - GQL - invalid image name and tag", t, func() {
|
|
||||||
args := []string{"list", "invalid:", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by image name - GQL - invalid output format", t, func() {
|
|
||||||
args := []string{"list", "zot-cve-test:0.0.1", "-f", "random", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
So(buff.String(), ShouldContainSubstring, "invalid output format")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test images by CVE ID - GQL - positive", t, func() {
|
|
||||||
args := []string{"affected", "CVE-2019-9923", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err := cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(str, ShouldEqual, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 40d1f749 false 605B")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test images by CVE ID - GQL - invalid CVE ID", t, func() {
|
|
||||||
args := []string{"affected", "CVE-invalid", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err := cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(str, ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test images by CVE ID - GQL - invalid output format", t, func() {
|
|
||||||
args := []string{"affected", "CVE-2019-9923", "-f", "random", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
So(buff.String(), ShouldContainSubstring, "invalid output format")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test fixed tags by image name and CVE ID - GQL - positive", t, func() {
|
|
||||||
args := []string{"fixed", "zot-cve-test", "CVE-2019-9923", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err := cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(str, ShouldEqual, "")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test fixed tags by image name and CVE ID - GQL - random cve", t, func() {
|
|
||||||
args := []string{"fixed", "zot-cve-test", "random", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err := cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(strings.TrimSpace(str), ShouldContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test fixed tags by image name and CVE ID - GQL - random image", t, func() {
|
|
||||||
args := []string{"fixed", "zot-cv-test", "CVE-2019-20807", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err := cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test fixed tags by image name and CVE ID - GQL - invalid image", t, func() {
|
|
||||||
args := []string{"fixed", "zot-cv-test:tag", "CVE-2019-20807", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err := cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
str = strings.TrimSpace(str)
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by name and CVE ID - GQL - positive", t, func() {
|
|
||||||
args := []string{"affected", "CVE-2019-9923", "--repo", "zot-cve-test", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err := cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(strings.TrimSpace(str), ShouldEqual,
|
|
||||||
"REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 40d1f749 false 605B")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by name and CVE ID - GQL - invalid name and CVE ID", t, func() {
|
|
||||||
args := []string{"affected", "CVE-20807", "--repo", "test", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err := cveCmd.Execute()
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH SIGNED SIZE")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test CVE by name and CVE ID - GQL - invalid output format", t, func() {
|
|
||||||
args := []string{"affected", "CVE-2019-9923", "--repo", "zot-cve-test", "-f", "random", "--config", "cvetest"}
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
cveCmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cveCmd.SetOut(buff)
|
|
||||||
cveCmd.SetErr(buff)
|
|
||||||
cveCmd.SetArgs(args)
|
|
||||||
err = cveCmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
So(buff.String(), ShouldContainSubstring, "invalid output format")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCVESort(t *testing.T) {
|
|
||||||
rootDir := t.TempDir()
|
|
||||||
port := test.GetFreePort()
|
|
||||||
baseURL := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
|
|
||||||
defaultVal := true
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: &extconf.SearchConfig{
|
|
||||||
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
|
||||||
CVE: &extconf.CVEConfig{
|
|
||||||
UpdateInterval: 2,
|
|
||||||
Trivy: &extconf.TrivyConfig{
|
|
||||||
DBRepository: "ghcr.io/project-zot/trivy-db",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Config.Storage.RootDirectory = rootDir
|
|
||||||
|
|
||||||
image1 := CreateRandomImage()
|
|
||||||
|
|
||||||
storeController := ociutils.GetDefaultStoreController(rootDir, ctlr.Log)
|
|
||||||
|
|
||||||
err := WriteImageToFileSystem(image1, "repo", "tag", storeController)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
if err := ctlr.Init(ctx); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctlr.CveScanner = mocks.CveScannerMock{
|
|
||||||
ScanImageFn: func(image string) (map[string]cvemodel.CVE, error) {
|
|
||||||
return map[string]cvemodel.CVE{
|
|
||||||
"CVE-2023-1255": {
|
|
||||||
ID: "CVE-2023-1255",
|
|
||||||
Severity: "LOW",
|
|
||||||
Title: "Input buffer over-read in AES-XTS implementation and testing",
|
|
||||||
},
|
|
||||||
"CVE-2023-2650": {
|
|
||||||
ID: "CVE-2023-2650",
|
|
||||||
Severity: "MEDIUM",
|
|
||||||
Title: "Possible DoS translating ASN.1 object identifier and executer",
|
|
||||||
},
|
|
||||||
"CVE-2023-2975": {
|
|
||||||
ID: "CVE-2023-2975",
|
|
||||||
Severity: "HIGH",
|
|
||||||
Title: "AES-SIV cipher implementation contains a bug that can break",
|
|
||||||
},
|
|
||||||
"CVE-2023-3446": {
|
|
||||||
ID: "CVE-2023-3446",
|
|
||||||
Severity: "CRITICAL",
|
|
||||||
Title: "Excessive time spent checking DH keys and parenthesis",
|
|
||||||
},
|
|
||||||
"CVE-2023-3817": {
|
|
||||||
ID: "CVE-2023-3817",
|
|
||||||
Severity: "MEDIUM",
|
|
||||||
Title: "Excessive time spent checking DH q parameter and arguments",
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := ctlr.Run(ctx); !errors.Is(err, http.ErrServerClosed) {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
defer ctlr.Shutdown()
|
|
||||||
|
|
||||||
test.WaitTillServerReady(baseURL)
|
|
||||||
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
|
|
||||||
Convey("test sorting", t, func() {
|
|
||||||
args := []string{"list", "repo:tag", "--sort-by", "severity", "--url", baseURL}
|
|
||||||
cmd := NewCVECommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
str := space.ReplaceAllString(buff.String(), " ")
|
|
||||||
actual := strings.TrimSpace(str)
|
|
||||||
So(actual, ShouldResemble,
|
|
||||||
"ID SEVERITY TITLE "+
|
|
||||||
"CVE-2023-3446 CRITICAL Excessive time spent checking DH keys and par... "+
|
|
||||||
"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
|
|
||||||
"CVE-2023-2650 MEDIUM Possible DoS translating ASN.1 object identif... "+
|
|
||||||
"CVE-2023-3817 MEDIUM Excessive time spent checking DH q parameter ... "+
|
|
||||||
"CVE-2023-1255 LOW Input buffer over-read in AES-XTS implementat...")
|
|
||||||
|
|
||||||
args = []string{"list", "repo:tag", "--sort-by", "alpha-asc", "--url", baseURL}
|
|
||||||
cmd = NewCVECommand(new(searchService))
|
|
||||||
buff = bytes.NewBufferString("")
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
str = space.ReplaceAllString(buff.String(), " ")
|
|
||||||
actual = strings.TrimSpace(str)
|
|
||||||
So(actual, ShouldResemble,
|
|
||||||
"ID SEVERITY TITLE "+
|
|
||||||
"CVE-2023-1255 LOW Input buffer over-read in AES-XTS implementat... "+
|
|
||||||
"CVE-2023-2650 MEDIUM Possible DoS translating ASN.1 object identif... "+
|
|
||||||
"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
|
|
||||||
"CVE-2023-3446 CRITICAL Excessive time spent checking DH keys and par... "+
|
|
||||||
"CVE-2023-3817 MEDIUM Excessive time spent checking DH q parameter ...")
|
|
||||||
|
|
||||||
args = []string{"list", "repo:tag", "--sort-by", "alpha-dsc", "--url", baseURL}
|
|
||||||
cmd = NewCVECommand(new(searchService))
|
|
||||||
buff = bytes.NewBufferString("")
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
str = space.ReplaceAllString(buff.String(), " ")
|
|
||||||
actual = strings.TrimSpace(str)
|
|
||||||
So(actual, ShouldResemble,
|
|
||||||
"ID SEVERITY TITLE "+
|
|
||||||
"CVE-2023-3817 MEDIUM Excessive time spent checking DH q parameter ... "+
|
|
||||||
"CVE-2023-3446 CRITICAL Excessive time spent checking DH keys and par... "+
|
|
||||||
"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
|
|
||||||
"CVE-2023-2650 MEDIUM Possible DoS translating ASN.1 object identif... "+
|
|
||||||
"CVE-2023-1255 LOW Input buffer over-read in AES-XTS implementat...")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCVECommandGQL(t *testing.T) {
|
func TestCVECommandGQL(t *testing.T) {
|
||||||
port := test.GetFreePort()
|
port := test.GetFreePort()
|
||||||
baseURL := test.GetBaseURL(port)
|
baseURL := test.GetBaseURL(port)
|
||||||
|
@ -1096,7 +424,7 @@ func TestCVECommandGQL(t *testing.T) {
|
||||||
args := []string{"affected", "CVE-12345", "--config", "cvetest"}
|
args := []string{"affected", "CVE-12345", "--config", "cvetest"}
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewCVECommand(mockService{
|
cmd := NewCVECommand(mockService{
|
||||||
getTagsForCVEGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName, cveID string) (*zcommon.ImagesForCve, error,
|
imageName, cveID string) (*zcommon.ImagesForCve, error,
|
||||||
) {
|
) {
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
|
@ -1143,7 +471,7 @@ func TestCVECommandGQL(t *testing.T) {
|
||||||
args := []string{"fixed", "repo", "CVE-2222", "--config", "cvetest"}
|
args := []string{"fixed", "repo", "CVE-2222", "--config", "cvetest"}
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewCVECommand(mockService{
|
cmd := NewCVECommand(mockService{
|
||||||
getFixedTagsForCVEGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getFixedTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName, cveID string) (*zcommon.ImageListWithCVEFixedResponse, error,
|
imageName, cveID string) (*zcommon.ImageListWithCVEFixedResponse, error,
|
||||||
) {
|
) {
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
|
@ -1190,7 +518,7 @@ func TestCVECommandGQL(t *testing.T) {
|
||||||
args := []string{"list", "repo:vuln", "--config", "cvetest"}
|
args := []string{"list", "repo:vuln", "--config", "cvetest"}
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
cmd := NewCVECommand(mockService{
|
cmd := NewCVECommand(mockService{
|
||||||
getCveByImageGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getCveByImageGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName, searchedCVE string) (*cveResult, error,
|
imageName, searchedCVE string) (*cveResult, error,
|
||||||
) {
|
) {
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
|
@ -1371,115 +699,13 @@ func TestCVECommandErrors(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMockCveScanner(metaDB mTypes.MetaDB) cveinfo.Scanner {
|
|
||||||
// MetaDB loaded with initial data now mock the scanner
|
|
||||||
// Setup test CVE data in mock scanner
|
|
||||||
scanner := mocks.CveScannerMock{
|
|
||||||
ScanImageFn: func(image string) (map[string]cvemodel.CVE, error) {
|
|
||||||
if image == "zot-cve-test@sha256:40d1f74918aefed733c590f798d7eafde8fc0a7ec63bb8bc52eaae133cf92495" ||
|
|
||||||
image == "zot-cve-test:0.0.1" {
|
|
||||||
return map[string]cvemodel.CVE{
|
|
||||||
"CVE-1": {
|
|
||||||
ID: "CVE-1",
|
|
||||||
Severity: "CRITICAL",
|
|
||||||
Title: "Title for CVE-C1",
|
|
||||||
Description: "Description of CVE-1",
|
|
||||||
},
|
|
||||||
"CVE-2019-9923": {
|
|
||||||
ID: "CVE-2019-9923",
|
|
||||||
Severity: "HIGH",
|
|
||||||
Title: "Title for CVE-2",
|
|
||||||
Description: "Description of CVE-2",
|
|
||||||
},
|
|
||||||
"CVE-3": {
|
|
||||||
ID: "CVE-3",
|
|
||||||
Severity: "MEDIUM",
|
|
||||||
Title: "Title for CVE-3",
|
|
||||||
Description: "Description of CVE-3",
|
|
||||||
},
|
|
||||||
"CVE-4": {
|
|
||||||
ID: "CVE-4",
|
|
||||||
Severity: "LOW",
|
|
||||||
Title: "Title for CVE-4",
|
|
||||||
Description: "Description of CVE-4",
|
|
||||||
},
|
|
||||||
"CVE-5": {
|
|
||||||
ID: "CVE-5",
|
|
||||||
Severity: "UNKNOWN",
|
|
||||||
Title: "Title for CVE-5",
|
|
||||||
Description: "Description of CVE-5",
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default the image has no vulnerabilities
|
|
||||||
return map[string]cvemodel.CVE{}, nil
|
|
||||||
},
|
|
||||||
IsImageFormatScannableFn: func(repo string, reference string) (bool, error) {
|
|
||||||
// Almost same logic compared to actual Trivy specific implementation
|
|
||||||
imageDir := repo
|
|
||||||
inputTag := reference
|
|
||||||
|
|
||||||
repoMeta, err := metaDB.GetRepoMeta(imageDir)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
manifestDigestStr := reference
|
|
||||||
|
|
||||||
if zcommon.IsTag(reference) {
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
descriptor, ok := repoMeta.Tags[inputTag]
|
|
||||||
if !ok {
|
|
||||||
return false, zerr.ErrTagMetaNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
manifestDigestStr = descriptor.Digest
|
|
||||||
}
|
|
||||||
|
|
||||||
manifestDigest, err := godigest.Parse(manifestDigestStr)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
manifestData, err := metaDB.GetManifestData(manifestDigest)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var manifestContent ispec.Manifest
|
|
||||||
|
|
||||||
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
|
|
||||||
if err != nil {
|
|
||||||
return false, zerr.ErrScanNotSupported
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, imageLayer := range manifestContent.Layers {
|
|
||||||
switch imageLayer.MediaType {
|
|
||||||
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
default:
|
|
||||||
|
|
||||||
return false, zerr.ErrScanNotSupported
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &scanner
|
|
||||||
}
|
|
||||||
|
|
||||||
type mockServiceForRetry struct {
|
type mockServiceForRetry struct {
|
||||||
mockService
|
mockService
|
||||||
retryCounter int
|
retryCounter int
|
||||||
succeedOn int
|
succeedOn int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service *mockServiceForRetry) getTagsForCVEGQL(ctx context.Context, config searchConfig, username, password, repo,
|
func (service *mockServiceForRetry) getTagsForCVEGQL(ctx context.Context, config SearchConfig, username, password, repo,
|
||||||
cveID string,
|
cveID string,
|
||||||
) (*zcommon.ImagesForCve, error) {
|
) (*zcommon.ImagesForCve, error) {
|
||||||
service.retryCounter += 1
|
service.retryCounter += 1
|
||||||
|
|
787
pkg/cli/client/cve_cmd_test.go
Normal file
787
pkg/cli/client/cve_cmd_test.go
Normal file
|
@ -0,0 +1,787 @@
|
||||||
|
//go:build search
|
||||||
|
// +build search
|
||||||
|
|
||||||
|
package client_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
regTypes "github.com/google/go-containerregistry/pkg/v1/types"
|
||||||
|
godigest "github.com/opencontainers/go-digest"
|
||||||
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
|
||||||
|
zerr "zotregistry.io/zot/errors"
|
||||||
|
"zotregistry.io/zot/pkg/api"
|
||||||
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
|
"zotregistry.io/zot/pkg/cli/client"
|
||||||
|
zcommon "zotregistry.io/zot/pkg/common"
|
||||||
|
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||||
|
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||||
|
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
|
||||||
|
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
|
||||||
|
"zotregistry.io/zot/pkg/log"
|
||||||
|
mTypes "zotregistry.io/zot/pkg/meta/types"
|
||||||
|
"zotregistry.io/zot/pkg/storage"
|
||||||
|
"zotregistry.io/zot/pkg/storage/local"
|
||||||
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
|
. "zotregistry.io/zot/pkg/test/image-utils"
|
||||||
|
"zotregistry.io/zot/pkg/test/mocks"
|
||||||
|
ociutils "zotregistry.io/zot/pkg/test/oci-utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNegativeServerResponse(t *testing.T) {
|
||||||
|
Convey("Test from real server without search endpoint", t, func() {
|
||||||
|
port := test.GetFreePort()
|
||||||
|
url := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
|
||||||
|
err := WriteImageToFileSystem(CreateDefaultVulnerableImage(), "zot-cve-test", "0.0.1", srcStorageCtlr)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
conf.Storage.RootDirectory = dir
|
||||||
|
trivyConfig := &extconf.TrivyConfig{
|
||||||
|
DBRepository: "ghcr.io/project-zot/trivy-db",
|
||||||
|
}
|
||||||
|
cveConfig := &extconf.CVEConfig{
|
||||||
|
UpdateInterval: 2,
|
||||||
|
Trivy: trivyConfig,
|
||||||
|
}
|
||||||
|
defaultVal := false
|
||||||
|
searchConfig := &extconf.SearchConfig{
|
||||||
|
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
||||||
|
CVE: cveConfig,
|
||||||
|
}
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: searchConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
logFile, err := os.CreateTemp(t.TempDir(), "zot-log*.txt")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logPath := logFile.Name()
|
||||||
|
defer os.Remove(logPath)
|
||||||
|
|
||||||
|
writers := io.MultiWriter(os.Stdout, logFile)
|
||||||
|
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Log.Logger = ctlr.Log.Output(writers)
|
||||||
|
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
cm.StartAndWait(conf.HTTP.Port)
|
||||||
|
defer cm.StopServer()
|
||||||
|
|
||||||
|
_, err = test.ReadLogFileAndSearchString(logPath, "CVE config not provided, skipping CVE update", 90*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey("Status Code Not Found", func() {
|
||||||
|
args := []string{"list", "zot-cve-test:0.0.1", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(err.Error(), ShouldContainSubstring, zerr.ErrExtensionNotEnabled.Error())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test non-existing manifest blob", t, func() {
|
||||||
|
port := test.GetFreePort()
|
||||||
|
url := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
imageStore := local.NewImageStore(dir, false, false,
|
||||||
|
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), nil, nil)
|
||||||
|
|
||||||
|
storeController := storage.StoreController{
|
||||||
|
DefaultStore: imageStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
image := CreateRandomImage()
|
||||||
|
|
||||||
|
err := WriteImageToFileSystem(image, "zot-cve-test", "0.0.1", storeController)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = os.RemoveAll(path.Join(dir, "zot-cve-test/blobs"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.Storage.RootDirectory = dir
|
||||||
|
trivyConfig := &extconf.TrivyConfig{
|
||||||
|
DBRepository: "ghcr.io/project-zot/trivy-db",
|
||||||
|
}
|
||||||
|
cveConfig := &extconf.CVEConfig{
|
||||||
|
UpdateInterval: 2,
|
||||||
|
Trivy: trivyConfig,
|
||||||
|
}
|
||||||
|
defaultVal := true
|
||||||
|
searchConfig := &extconf.SearchConfig{
|
||||||
|
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
||||||
|
CVE: cveConfig,
|
||||||
|
}
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: searchConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
logFile, err := os.CreateTemp(t.TempDir(), "zot-log*.txt")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logPath := logFile.Name()
|
||||||
|
defer os.Remove(logPath)
|
||||||
|
|
||||||
|
writers := io.MultiWriter(os.Stdout, logFile)
|
||||||
|
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Log.Logger = ctlr.Log.Output(writers)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if err := ctlr.Init(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctlr.CveScanner = getMockCveScanner(ctlr.MetaDB)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := ctlr.Run(ctx); !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer ctlr.Shutdown()
|
||||||
|
|
||||||
|
test.WaitTillServerReady(url)
|
||||||
|
|
||||||
|
_, err = test.ReadLogFileAndSearchString(logPath, "DB update completed, next update scheduled", 90*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{"fixed", "zot-cve-test", "CVE-2019-9923", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:dupl
|
||||||
|
func TestServerCVEResponse(t *testing.T) {
|
||||||
|
port := test.GetFreePort()
|
||||||
|
url := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
conf.Storage.RootDirectory = dir
|
||||||
|
trivyConfig := &extconf.TrivyConfig{
|
||||||
|
DBRepository: "ghcr.io/project-zot/trivy-db",
|
||||||
|
}
|
||||||
|
cveConfig := &extconf.CVEConfig{
|
||||||
|
UpdateInterval: 2,
|
||||||
|
Trivy: trivyConfig,
|
||||||
|
}
|
||||||
|
defaultVal := true
|
||||||
|
searchConfig := &extconf.SearchConfig{
|
||||||
|
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
||||||
|
CVE: cveConfig,
|
||||||
|
}
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: searchConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
logFile, err := os.CreateTemp(t.TempDir(), "zot-log*.txt")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logPath := logFile.Name()
|
||||||
|
defer os.Remove(logPath)
|
||||||
|
|
||||||
|
writers := io.MultiWriter(os.Stdout, logFile)
|
||||||
|
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Log.Logger = ctlr.Log.Output(writers)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if err := ctlr.Init(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctlr.CveScanner = getMockCveScanner(ctlr.MetaDB)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := ctlr.Run(ctx); !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer ctlr.Shutdown()
|
||||||
|
|
||||||
|
test.WaitTillServerReady(url)
|
||||||
|
|
||||||
|
image := CreateDefaultImage()
|
||||||
|
|
||||||
|
err = UploadImage(image, url, "zot-cve-test", "0.0.1")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = test.ReadLogFileAndSearchString(logPath, "DB update completed, next update scheduled", 90*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey("Test CVE by image name - GQL - positive", t, func() {
|
||||||
|
args := []string{"list", "zot-cve-test:0.0.1", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(str, ShouldContainSubstring, "ID SEVERITY TITLE")
|
||||||
|
So(str, ShouldContainSubstring, "CVE")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by image name - GQL - search CVE by title in results", t, func() {
|
||||||
|
args := []string{"list", "zot-cve-test:0.0.1", "--cve-id", "CVE-C1", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(str, ShouldContainSubstring, "ID SEVERITY TITLE")
|
||||||
|
So(str, ShouldContainSubstring, "CVE-C1")
|
||||||
|
So(str, ShouldNotContainSubstring, "CVE-2")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by image name - GQL - search CVE by id in results", t, func() {
|
||||||
|
args := []string{"list", "zot-cve-test:0.0.1", "--cve-id", "CVE-2", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(str, ShouldContainSubstring, "ID SEVERITY TITLE")
|
||||||
|
So(str, ShouldContainSubstring, "CVE-2")
|
||||||
|
So(str, ShouldNotContainSubstring, "CVE-1")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by image name - GQL - search nonexistent CVE", t, func() {
|
||||||
|
args := []string{"list", "zot-cve-test:0.0.1", "--cve-id", "CVE-100", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(str, ShouldContainSubstring, "No CVEs found for image")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by image name - GQL - invalid image", t, func() {
|
||||||
|
args := []string{"list", "invalid:0.0.1", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by image name - GQL - invalid image name and tag", t, func() {
|
||||||
|
args := []string{"list", "invalid:", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by image name - GQL - invalid output format", t, func() {
|
||||||
|
args := []string{"list", "zot-cve-test:0.0.1", "-f", "random", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(buff.String(), ShouldContainSubstring, "invalid output format")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test images by CVE ID - GQL - positive", t, func() {
|
||||||
|
args := []string{"affected", "CVE-2019-9923", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err := cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(str, ShouldEqual, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 db573b01 false 854B")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test images by CVE ID - GQL - invalid CVE ID", t, func() {
|
||||||
|
args := []string{"affected", "CVE-invalid", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err := cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(str, ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test images by CVE ID - GQL - invalid output format", t, func() {
|
||||||
|
args := []string{"affected", "CVE-2019-9923", "-f", "random", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(buff.String(), ShouldContainSubstring, "invalid output format")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test fixed tags by image name and CVE ID - GQL - positive", t, func() {
|
||||||
|
args := []string{"fixed", "zot-cve-test", "CVE-2019-9923", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err := cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(str, ShouldEqual, "")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test fixed tags by image name and CVE ID - GQL - random cve", t, func() {
|
||||||
|
args := []string{"fixed", "zot-cve-test", "random", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err := cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(strings.TrimSpace(str), ShouldContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test fixed tags by image name and CVE ID - GQL - random image", t, func() {
|
||||||
|
args := []string{"fixed", "zot-cv-test", "CVE-2019-20807", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err := cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(strings.TrimSpace(str), ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test fixed tags by image name and CVE ID - GQL - invalid image", t, func() {
|
||||||
|
args := []string{"fixed", "zot-cv-test:tag", "CVE-2019-20807", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err := cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(strings.TrimSpace(str), ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by name and CVE ID - GQL - positive", t, func() {
|
||||||
|
args := []string{"affected", "CVE-2019-9923", "--repo", "zot-cve-test", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err := cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(strings.TrimSpace(str), ShouldEqual,
|
||||||
|
"REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 db573b01 false 854B")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by name and CVE ID - GQL - invalid name and CVE ID", t, func() {
|
||||||
|
args := []string{"affected", "CVE-20807", "--repo", "test", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err := cveCmd.Execute()
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(strings.TrimSpace(str), ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH SIGNED SIZE")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test CVE by name and CVE ID - GQL - invalid output format", t, func() {
|
||||||
|
args := []string{"affected", "CVE-2019-9923", "--repo", "zot-cve-test", "-f", "random", "--config", "cvetest"}
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cveCmd.SetOut(buff)
|
||||||
|
cveCmd.SetErr(buff)
|
||||||
|
cveCmd.SetArgs(args)
|
||||||
|
err = cveCmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(buff.String(), ShouldContainSubstring, "invalid output format")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCVESort(t *testing.T) {
|
||||||
|
rootDir := t.TempDir()
|
||||||
|
port := test.GetFreePort()
|
||||||
|
baseURL := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
|
||||||
|
defaultVal := true
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: &extconf.SearchConfig{
|
||||||
|
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
||||||
|
CVE: &extconf.CVEConfig{
|
||||||
|
UpdateInterval: 2,
|
||||||
|
Trivy: &extconf.TrivyConfig{
|
||||||
|
DBRepository: "ghcr.io/project-zot/trivy-db",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Config.Storage.RootDirectory = rootDir
|
||||||
|
|
||||||
|
image1 := CreateRandomImage()
|
||||||
|
|
||||||
|
storeController := ociutils.GetDefaultStoreController(rootDir, ctlr.Log)
|
||||||
|
|
||||||
|
err := WriteImageToFileSystem(image1, "repo", "tag", storeController)
|
||||||
|
if err != nil {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
if err := ctlr.Init(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctlr.CveScanner = mocks.CveScannerMock{
|
||||||
|
ScanImageFn: func(image string) (map[string]cvemodel.CVE, error) {
|
||||||
|
return map[string]cvemodel.CVE{
|
||||||
|
"CVE-2023-1255": {
|
||||||
|
ID: "CVE-2023-1255",
|
||||||
|
Severity: "LOW",
|
||||||
|
Title: "Input buffer over-read in AES-XTS implementation and testing",
|
||||||
|
},
|
||||||
|
"CVE-2023-2650": {
|
||||||
|
ID: "CVE-2023-2650",
|
||||||
|
Severity: "MEDIUM",
|
||||||
|
Title: "Possible DoS translating ASN.1 object identifier and executer",
|
||||||
|
},
|
||||||
|
"CVE-2023-2975": {
|
||||||
|
ID: "CVE-2023-2975",
|
||||||
|
Severity: "HIGH",
|
||||||
|
Title: "AES-SIV cipher implementation contains a bug that can break",
|
||||||
|
},
|
||||||
|
"CVE-2023-3446": {
|
||||||
|
ID: "CVE-2023-3446",
|
||||||
|
Severity: "CRITICAL",
|
||||||
|
Title: "Excessive time spent checking DH keys and parenthesis",
|
||||||
|
},
|
||||||
|
"CVE-2023-3817": {
|
||||||
|
ID: "CVE-2023-3817",
|
||||||
|
Severity: "MEDIUM",
|
||||||
|
Title: "Excessive time spent checking DH q parameter and arguments",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := ctlr.Run(ctx); !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer ctlr.Shutdown()
|
||||||
|
|
||||||
|
test.WaitTillServerReady(baseURL)
|
||||||
|
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
|
||||||
|
Convey("test sorting", t, func() {
|
||||||
|
args := []string{"list", "repo:tag", "--sort-by", "severity", "--url", baseURL}
|
||||||
|
cmd := client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
str := space.ReplaceAllString(buff.String(), " ")
|
||||||
|
actual := strings.TrimSpace(str)
|
||||||
|
So(actual, ShouldResemble,
|
||||||
|
"ID SEVERITY TITLE "+
|
||||||
|
"CVE-2023-3446 CRITICAL Excessive time spent checking DH keys and par... "+
|
||||||
|
"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
|
||||||
|
"CVE-2023-2650 MEDIUM Possible DoS translating ASN.1 object identif... "+
|
||||||
|
"CVE-2023-3817 MEDIUM Excessive time spent checking DH q parameter ... "+
|
||||||
|
"CVE-2023-1255 LOW Input buffer over-read in AES-XTS implementat...")
|
||||||
|
|
||||||
|
args = []string{"list", "repo:tag", "--sort-by", "alpha-asc", "--url", baseURL}
|
||||||
|
cmd = client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff = bytes.NewBufferString("")
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
str = space.ReplaceAllString(buff.String(), " ")
|
||||||
|
actual = strings.TrimSpace(str)
|
||||||
|
So(actual, ShouldResemble,
|
||||||
|
"ID SEVERITY TITLE "+
|
||||||
|
"CVE-2023-1255 LOW Input buffer over-read in AES-XTS implementat... "+
|
||||||
|
"CVE-2023-2650 MEDIUM Possible DoS translating ASN.1 object identif... "+
|
||||||
|
"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
|
||||||
|
"CVE-2023-3446 CRITICAL Excessive time spent checking DH keys and par... "+
|
||||||
|
"CVE-2023-3817 MEDIUM Excessive time spent checking DH q parameter ...")
|
||||||
|
|
||||||
|
args = []string{"list", "repo:tag", "--sort-by", "alpha-dsc", "--url", baseURL}
|
||||||
|
cmd = client.NewCVECommand(client.NewSearchService())
|
||||||
|
buff = bytes.NewBufferString("")
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
str = space.ReplaceAllString(buff.String(), " ")
|
||||||
|
actual = strings.TrimSpace(str)
|
||||||
|
So(actual, ShouldResemble,
|
||||||
|
"ID SEVERITY TITLE "+
|
||||||
|
"CVE-2023-3817 MEDIUM Excessive time spent checking DH q parameter ... "+
|
||||||
|
"CVE-2023-3446 CRITICAL Excessive time spent checking DH keys and par... "+
|
||||||
|
"CVE-2023-2975 HIGH AES-SIV cipher implementation contains a bug ... "+
|
||||||
|
"CVE-2023-2650 MEDIUM Possible DoS translating ASN.1 object identif... "+
|
||||||
|
"CVE-2023-1255 LOW Input buffer over-read in AES-XTS implementat...")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMockCveScanner(metaDB mTypes.MetaDB) cveinfo.Scanner {
|
||||||
|
// MetaDB loaded with initial data now mock the scanner
|
||||||
|
// Setup test CVE data in mock scanner
|
||||||
|
scanner := mocks.CveScannerMock{
|
||||||
|
ScanImageFn: func(image string) (map[string]cvemodel.CVE, error) {
|
||||||
|
if strings.Contains(image, "zot-cve-test@sha256:db573b01") ||
|
||||||
|
image == "zot-cve-test:0.0.1" {
|
||||||
|
return map[string]cvemodel.CVE{
|
||||||
|
"CVE-1": {
|
||||||
|
ID: "CVE-1",
|
||||||
|
Severity: "CRITICAL",
|
||||||
|
Title: "Title for CVE-C1",
|
||||||
|
Description: "Description of CVE-1",
|
||||||
|
},
|
||||||
|
"CVE-2019-9923": {
|
||||||
|
ID: "CVE-2019-9923",
|
||||||
|
Severity: "HIGH",
|
||||||
|
Title: "Title for CVE-2",
|
||||||
|
Description: "Description of CVE-2",
|
||||||
|
},
|
||||||
|
"CVE-3": {
|
||||||
|
ID: "CVE-3",
|
||||||
|
Severity: "MEDIUM",
|
||||||
|
Title: "Title for CVE-3",
|
||||||
|
Description: "Description of CVE-3",
|
||||||
|
},
|
||||||
|
"CVE-4": {
|
||||||
|
ID: "CVE-4",
|
||||||
|
Severity: "LOW",
|
||||||
|
Title: "Title for CVE-4",
|
||||||
|
Description: "Description of CVE-4",
|
||||||
|
},
|
||||||
|
"CVE-5": {
|
||||||
|
ID: "CVE-5",
|
||||||
|
Severity: "UNKNOWN",
|
||||||
|
Title: "Title for CVE-5",
|
||||||
|
Description: "Description of CVE-5",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default the image has no vulnerabilities
|
||||||
|
return map[string]cvemodel.CVE{}, nil
|
||||||
|
},
|
||||||
|
IsImageFormatScannableFn: func(repo string, reference string) (bool, error) {
|
||||||
|
// Almost same logic compared to actual Trivy specific implementation
|
||||||
|
imageDir := repo
|
||||||
|
inputTag := reference
|
||||||
|
|
||||||
|
repoMeta, err := metaDB.GetRepoMeta(imageDir)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestDigestStr := reference
|
||||||
|
|
||||||
|
if zcommon.IsTag(reference) {
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
descriptor, ok := repoMeta.Tags[inputTag]
|
||||||
|
if !ok {
|
||||||
|
return false, zerr.ErrTagMetaNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestDigestStr = descriptor.Digest
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestDigest, err := godigest.Parse(manifestDigestStr)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
manifestData, err := metaDB.GetManifestData(manifestDigest)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var manifestContent ispec.Manifest
|
||||||
|
|
||||||
|
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
|
||||||
|
if err != nil {
|
||||||
|
return false, zerr.ErrScanNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, imageLayer := range manifestContent.Layers {
|
||||||
|
switch imageLayer.MediaType {
|
||||||
|
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
default:
|
||||||
|
|
||||||
|
return false, zerr.ErrScanNotSupported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &scanner
|
||||||
|
}
|
|
@ -90,11 +90,11 @@ func haveSameArgs(query field, reqQuery GQLQuery) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckExtEndPointQuery(config searchConfig, requiredQueries ...GQLQuery) error {
|
func CheckExtEndPointQuery(config SearchConfig, requiredQueries ...GQLQuery) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
discoverEndPoint, err := combineServerAndEndpointURL(config.servURL, fmt.Sprintf("%s%s",
|
discoverEndPoint, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("%s%s",
|
||||||
constants.RoutePrefix, constants.ExtOciDiscoverPrefix))
|
constants.RoutePrefix, constants.ExtOciDiscoverPrefix))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -102,8 +102,8 @@ func CheckExtEndPointQuery(config searchConfig, requiredQueries ...GQLQuery) err
|
||||||
|
|
||||||
discoverResponse := &distext.ExtensionList{}
|
discoverResponse := &distext.ExtensionList{}
|
||||||
|
|
||||||
_, err = makeGETRequest(ctx, discoverEndPoint, username, password, config.verifyTLS,
|
_, err = makeGETRequest(ctx, discoverEndPoint, username, password, config.VerifyTLS,
|
||||||
config.debug, &discoverResponse, config.resultWriter)
|
config.Debug, &discoverResponse, config.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ func CheckExtEndPointQuery(config searchConfig, requiredQueries ...GQLQuery) err
|
||||||
return fmt.Errorf("%w: search extension gql endpoints not found", zerr.ErrExtensionNotEnabled)
|
return fmt.Errorf("%w: search extension gql endpoints not found", zerr.ErrExtensionNotEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
searchEndPoint, _ := combineServerAndEndpointURL(config.servURL, constants.FullSearchPrefix)
|
searchEndPoint, _ := combineServerAndEndpointURL(config.ServURL, constants.FullSearchPrefix)
|
||||||
|
|
||||||
schemaQuery := `
|
schemaQuery := `
|
||||||
{
|
{
|
||||||
|
@ -153,8 +153,8 @@ func CheckExtEndPointQuery(config searchConfig, requiredQueries ...GQLQuery) err
|
||||||
|
|
||||||
queryResponse := &schemaList{}
|
queryResponse := &schemaList{}
|
||||||
|
|
||||||
err = makeGraphQLRequest(ctx, searchEndPoint, schemaQuery, username, password, config.verifyTLS,
|
err = makeGraphQLRequest(ctx, searchEndPoint, schemaQuery, username, password, config.VerifyTLS,
|
||||||
config.debug, queryResponse, config.resultWriter)
|
config.Debug, queryResponse, config.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("gql query failed: %w", err)
|
return fmt.Errorf("gql query failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//go:build search && needprivileges
|
//go:build search && needprivileges
|
||||||
// +build search,needprivileges
|
// +build search,needprivileges
|
||||||
|
|
||||||
package client
|
package client_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -19,6 +19,7 @@ import (
|
||||||
"zotregistry.io/zot/pkg/api"
|
"zotregistry.io/zot/pkg/api"
|
||||||
"zotregistry.io/zot/pkg/api/config"
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
"zotregistry.io/zot/pkg/api/constants"
|
"zotregistry.io/zot/pkg/api/constants"
|
||||||
|
"zotregistry.io/zot/pkg/cli/client"
|
||||||
test "zotregistry.io/zot/pkg/test/common"
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ func TestElevatedPrivilegesTLSNewControllerPrivilegedCert(t *testing.T) {
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
args := []string{"list", "--config", "imagetest"}
|
args := []string{"list", "--config", "imagetest"}
|
||||||
imageCmd := NewImageCommand(new(searchService))
|
imageCmd := client.NewImageCommand(client.NewSearchService())
|
||||||
imageBuff := bytes.NewBufferString("")
|
imageBuff := bytes.NewBufferString("")
|
||||||
imageCmd.SetOut(imageBuff)
|
imageCmd.SetOut(imageBuff)
|
||||||
imageCmd.SetErr(imageBuff)
|
imageCmd.SetErr(imageBuff)
|
|
@ -1,7 +1,7 @@
|
||||||
//go:build search
|
//go:build search
|
||||||
// +build search
|
// +build search
|
||||||
|
|
||||||
package client
|
package client_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"zotregistry.io/zot/pkg/api"
|
"zotregistry.io/zot/pkg/api"
|
||||||
"zotregistry.io/zot/pkg/api/config"
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
|
"zotregistry.io/zot/pkg/cli/client"
|
||||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||||
test "zotregistry.io/zot/pkg/test/common"
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
)
|
)
|
||||||
|
@ -36,57 +37,57 @@ func TestGQLQueries(t *testing.T) {
|
||||||
|
|
||||||
defer cm.StopServer()
|
defer cm.StopServer()
|
||||||
|
|
||||||
searchConfig := searchConfig{
|
searchConfig := client.SearchConfig{
|
||||||
servURL: baseURL,
|
ServURL: baseURL,
|
||||||
user: "",
|
User: "",
|
||||||
verifyTLS: false,
|
VerifyTLS: false,
|
||||||
debug: false,
|
Debug: false,
|
||||||
resultWriter: io.Discard,
|
ResultWriter: io.Discard,
|
||||||
}
|
}
|
||||||
|
|
||||||
Convey("Make sure the current CLI used the right queries in case they change", t, func() {
|
Convey("Make sure the current CLI used the right queries in case they change", t, func() {
|
||||||
Convey("ImageList", func() {
|
Convey("ImageList", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, ImageListQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.ImageListQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("ImageListForDigest", func() {
|
Convey("ImageListForDigest", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, ImageListForDigestQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.ImageListForDigestQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("BaseImageList", func() {
|
Convey("BaseImageList", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, BaseImageListQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.BaseImageListQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("DerivedImageList", func() {
|
Convey("DerivedImageList", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, DerivedImageListQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.DerivedImageListQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("CVEListForImage", func() {
|
Convey("CVEListForImage", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, CVEListForImageQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.CVEListForImageQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("ImageListForCVE", func() {
|
Convey("ImageListForCVE", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, ImageListForCVEQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.ImageListForCVEQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("ImageListWithCVEFixed", func() {
|
Convey("ImageListWithCVEFixed", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, ImageListWithCVEFixedQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.ImageListWithCVEFixedQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Referrers", func() {
|
Convey("Referrers", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, ReferrersQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.ReferrersQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("GlobalSearch", func() {
|
Convey("GlobalSearch", func() {
|
||||||
err := CheckExtEndPointQuery(searchConfig, GlobalSearchQuery())
|
err := client.CheckExtEndPointQuery(searchConfig, client.GlobalSearchQuery())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
})
|
})
|
File diff suppressed because it is too large
Load diff
1260
pkg/cli/client/image_cmd_test.go
Normal file
1260
pkg/cli/client/image_cmd_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
||||||
//go:build search
|
//go:build search
|
||||||
// +build search
|
// +build search
|
||||||
|
|
||||||
package client
|
package client_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -15,6 +15,7 @@ import (
|
||||||
|
|
||||||
"zotregistry.io/zot/pkg/api"
|
"zotregistry.io/zot/pkg/api"
|
||||||
"zotregistry.io/zot/pkg/api/config"
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
|
"zotregistry.io/zot/pkg/cli/client"
|
||||||
test "zotregistry.io/zot/pkg/test/common"
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
. "zotregistry.io/zot/pkg/test/image-utils"
|
. "zotregistry.io/zot/pkg/test/image-utils"
|
||||||
)
|
)
|
||||||
|
@ -43,7 +44,7 @@ func TestReposCommand(t *testing.T) {
|
||||||
defer os.Remove(configPath)
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
args := []string{"list", "--config", "repostest"}
|
args := []string{"list", "--config", "repostest"}
|
||||||
cmd := NewRepoCommand(mockService{})
|
cmd := client.NewRepoCommand(client.NewSearchService())
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -57,7 +58,7 @@ func TestReposCommand(t *testing.T) {
|
||||||
So(actual, ShouldContainSubstring, "repo2")
|
So(actual, ShouldContainSubstring, "repo2")
|
||||||
|
|
||||||
args = []string{"list", "--sort-by", "alpha-dsc", "--config", "repostest"}
|
args = []string{"list", "--sort-by", "alpha-dsc", "--config", "repostest"}
|
||||||
cmd = NewRepoCommand(new(searchService))
|
cmd = client.NewRepoCommand(client.NewSearchService())
|
||||||
buff = bytes.NewBufferString("")
|
buff = bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -72,7 +73,7 @@ func TestReposCommand(t *testing.T) {
|
||||||
So(strings.Index(actual, "repo2"), ShouldBeLessThan, strings.Index(actual, "repo1"))
|
So(strings.Index(actual, "repo2"), ShouldBeLessThan, strings.Index(actual, "repo1"))
|
||||||
|
|
||||||
args = []string{"list", "--sort-by", "alpha-asc", "--config", "repostest"}
|
args = []string{"list", "--sort-by", "alpha-asc", "--config", "repostest"}
|
||||||
cmd = NewRepoCommand(new(searchService))
|
cmd = client.NewRepoCommand(client.NewSearchService())
|
||||||
buff = bytes.NewBufferString("")
|
buff = bytes.NewBufferString("")
|
||||||
cmd.SetOut(buff)
|
cmd.SetOut(buff)
|
||||||
cmd.SetErr(buff)
|
cmd.SetErr(buff)
|
||||||
|
@ -91,11 +92,13 @@ func TestReposCommand(t *testing.T) {
|
||||||
func TestSuggestions(t *testing.T) {
|
func TestSuggestions(t *testing.T) {
|
||||||
Convey("Suggestions", t, func() {
|
Convey("Suggestions", t, func() {
|
||||||
space := regexp.MustCompile(`\s+`)
|
space := regexp.MustCompile(`\s+`)
|
||||||
suggestion := ShowSuggestionsIfUnknownCommand(NewRepoCommand(mockService{}), []string{"bad-command"})
|
suggestion := client.ShowSuggestionsIfUnknownCommand(
|
||||||
|
client.NewRepoCommand(client.NewSearchService()), []string{"bad-command"})
|
||||||
str := space.ReplaceAllString(suggestion.Error(), " ")
|
str := space.ReplaceAllString(suggestion.Error(), " ")
|
||||||
So(str, ShouldContainSubstring, "unknown subcommand")
|
So(str, ShouldContainSubstring, "unknown subcommand")
|
||||||
|
|
||||||
suggestion = ShowSuggestionsIfUnknownCommand(NewRepoCommand(mockService{}), []string{"listt"})
|
suggestion = client.ShowSuggestionsIfUnknownCommand(
|
||||||
|
client.NewRepoCommand(client.NewSearchService()), []string{"listt"})
|
||||||
str = space.ReplaceAllString(suggestion.Error(), " ")
|
str = space.ReplaceAllString(suggestion.Error(), " ")
|
||||||
So(str, ShouldContainSubstring, "Did you mean this? list")
|
So(str, ShouldContainSubstring, "Did you mean this? list")
|
||||||
})
|
})
|
|
@ -10,9 +10,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
|
||||||
"zotregistry.io/zot/pkg/api"
|
"zotregistry.io/zot/pkg/api"
|
||||||
|
@ -20,713 +18,8 @@ import (
|
||||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||||
test "zotregistry.io/zot/pkg/test/common"
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
. "zotregistry.io/zot/pkg/test/image-utils"
|
. "zotregistry.io/zot/pkg/test/image-utils"
|
||||||
ociutils "zotregistry.io/zot/pkg/test/oci-utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
customArtTypeV1 = "application/custom.art.type.v1"
|
|
||||||
customArtTypeV2 = "application/custom.art.type.v2"
|
|
||||||
repoName = "repo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestReferrerCLI(t *testing.T) {
|
|
||||||
Convey("Test GQL", t, func() {
|
|
||||||
rootDir := t.TempDir()
|
|
||||||
|
|
||||||
port := test.GetFreePort()
|
|
||||||
baseURL := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
conf.Storage.GC = false
|
|
||||||
defaultVal := true
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
||||||
}
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Config.Storage.RootDirectory = rootDir
|
|
||||||
cm := test.NewControllerManager(ctlr)
|
|
||||||
cm.StartAndWait(conf.HTTP.Port)
|
|
||||||
defer cm.StopServer()
|
|
||||||
|
|
||||||
repo := repoName
|
|
||||||
image := CreateRandomImage()
|
|
||||||
|
|
||||||
err := UploadImage(image, baseURL, repo, "tag")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
ref1 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
RandomConfig().
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
ref2 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
ArtifactConfig(customArtTypeV1).
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
ref3 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
RandomConfig().
|
|
||||||
ArtifactType(customArtTypeV2).
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
args := []string{"subject", repo + "@" + image.DigestStr(), "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
||||||
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
|
||||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
|
||||||
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
|
||||||
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
|
||||||
|
|
||||||
fmt.Println(buff.String())
|
|
||||||
|
|
||||||
os.Remove(configPath)
|
|
||||||
|
|
||||||
args = []string{"subject", repo + ":" + "tag", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
cmd = NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
buff = &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
||||||
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
|
||||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
|
||||||
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
|
||||||
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
|
||||||
|
|
||||||
fmt.Println(buff.String())
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Test REST", t, func() {
|
|
||||||
rootDir := t.TempDir()
|
|
||||||
|
|
||||||
port := test.GetFreePort()
|
|
||||||
baseURL := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
conf.Storage.GC = false
|
|
||||||
defaultVal := false
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
||||||
}
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Config.Storage.RootDirectory = rootDir
|
|
||||||
cm := test.NewControllerManager(ctlr)
|
|
||||||
cm.StartAndWait(conf.HTTP.Port)
|
|
||||||
defer cm.StopServer()
|
|
||||||
|
|
||||||
repo := repoName
|
|
||||||
image := CreateRandomImage()
|
|
||||||
|
|
||||||
err := UploadImage(image, baseURL, repo, "tag")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
ref1 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
RandomConfig().
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
ref2 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
ArtifactConfig(customArtTypeV1).
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
ref3 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
RandomConfig().
|
|
||||||
ArtifactType(customArtTypeV2).
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
// get referrers by digest
|
|
||||||
args := []string{"subject", repo + "@" + image.DigestStr(), "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
||||||
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
|
||||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
|
||||||
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
|
||||||
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
|
||||||
fmt.Println(buff.String())
|
|
||||||
|
|
||||||
os.Remove(configPath)
|
|
||||||
|
|
||||||
args = []string{"subject", repo + ":" + "tag", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff = &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
||||||
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
|
||||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
|
||||||
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
|
||||||
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
|
||||||
fmt.Println(buff.String())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatsReferrersCLI(t *testing.T) {
|
|
||||||
Convey("Create server", t, func() {
|
|
||||||
rootDir := t.TempDir()
|
|
||||||
|
|
||||||
port := test.GetFreePort()
|
|
||||||
baseURL := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
conf.Storage.GC = false
|
|
||||||
defaultVal := false
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
||||||
}
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Config.Storage.RootDirectory = rootDir
|
|
||||||
cm := test.NewControllerManager(ctlr)
|
|
||||||
cm.StartAndWait(conf.HTTP.Port)
|
|
||||||
defer cm.StopServer()
|
|
||||||
|
|
||||||
repo := repoName
|
|
||||||
image := CreateRandomImage()
|
|
||||||
|
|
||||||
err := UploadImage(image, baseURL, repo, "tag")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
// add referrers
|
|
||||||
ref1 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
RandomConfig().
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
ref2 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
ArtifactConfig(customArtTypeV1).
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
ref3 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
RandomConfig().
|
|
||||||
ArtifactType(customArtTypeV2).
|
|
||||||
Subject(image.DescriptorRef()).Build()
|
|
||||||
|
|
||||||
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
Convey("JSON format", func() {
|
|
||||||
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "json", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
fmt.Println(buff.String())
|
|
||||||
})
|
|
||||||
Convey("YAML format", func() {
|
|
||||||
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "yaml", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
fmt.Println(buff.String())
|
|
||||||
})
|
|
||||||
Convey("Invalid format", func() {
|
|
||||||
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "invalid_format", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReferrersCLIErrors(t *testing.T) {
|
|
||||||
Convey("Errors", t, func() {
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
Convey("no url provided", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"reftest","showspinner":false}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("getConfigValue", func() {
|
|
||||||
args := []string{"subject", "repo/alpine", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(`bad-json`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("bad showspinnerConfig ", func() {
|
|
||||||
args := []string{"query", "repo", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":"bad"}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("bad verifyTLSConfig ", func() {
|
|
||||||
args := []string{"query", "repo", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(
|
|
||||||
`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":false, "verify-tls": "bad"}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("url from config is empty", func() {
|
|
||||||
args := []string{"subject", "repo/alpine", "--config", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"", "showspinner":false}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("bad params combination", func() {
|
|
||||||
args := []string{"query", "repo", "reftest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":false}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchCLI(t *testing.T) {
|
|
||||||
Convey("Test GQL", t, func() {
|
|
||||||
rootDir := t.TempDir()
|
|
||||||
|
|
||||||
port := test.GetFreePort()
|
|
||||||
baseURL := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
conf.Storage.GC = false
|
|
||||||
defaultVal := true
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
||||||
}
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Config.Storage.RootDirectory = rootDir
|
|
||||||
cm := test.NewControllerManager(ctlr)
|
|
||||||
cm.StartAndWait(conf.HTTP.Port)
|
|
||||||
defer cm.StopServer()
|
|
||||||
|
|
||||||
const (
|
|
||||||
repo1 = "repo"
|
|
||||||
r1tag1 = "repo1tag1"
|
|
||||||
r1tag2 = "repo1tag2"
|
|
||||||
|
|
||||||
repo2 = "repo/alpine"
|
|
||||||
r2tag1 = "repo2tag1"
|
|
||||||
r2tag2 = "repo2tag2"
|
|
||||||
|
|
||||||
repo3 = "repo/test/alpine"
|
|
||||||
r3tag1 = "repo3tag1"
|
|
||||||
r3tag2 = "repo3tag2"
|
|
||||||
)
|
|
||||||
|
|
||||||
image1 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
ImageConfig(ispec.Image{
|
|
||||||
Created: DefaultTimeRef(),
|
|
||||||
Platform: ispec.Platform{OS: "Os", Architecture: "Arch"},
|
|
||||||
}).
|
|
||||||
Build()
|
|
||||||
formatterDigest1 := image1.Digest().Encoded()[:8]
|
|
||||||
|
|
||||||
image2 := CreateImageWith().
|
|
||||||
RandomLayers(1, 10).
|
|
||||||
DefaultConfig().
|
|
||||||
Build()
|
|
||||||
formatterDigest2 := image2.Digest().Encoded()[:8]
|
|
||||||
|
|
||||||
err := UploadImage(image1, baseURL, repo1, r1tag1)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
err = UploadImage(image2, baseURL, repo1, r1tag2)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(image1, baseURL, repo2, r2tag1)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
err = UploadImage(image2, baseURL, repo2, r2tag2)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(image1, baseURL, repo3, r3tag1)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
err = UploadImage(image2, baseURL, repo3, r3tag2)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
// search by repos
|
|
||||||
|
|
||||||
args := []string{"query", "test/alpin", "--verbose", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
space := regexp.MustCompile(`\s+`)
|
|
||||||
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
||||||
So(str, ShouldContainSubstring, "NAME SIZE LAST UPDATED DOWNLOADS STARS PLATFORMS")
|
|
||||||
So(str, ShouldContainSubstring, "repo/test/alpine 1.1kB 2010-01-01 01:01:01 +0000 UTC 0 0")
|
|
||||||
So(str, ShouldContainSubstring, "Os/Arch")
|
|
||||||
So(str, ShouldContainSubstring, "linux/amd64")
|
|
||||||
|
|
||||||
fmt.Println("\n", buff.String())
|
|
||||||
|
|
||||||
os.Remove(configPath)
|
|
||||||
|
|
||||||
cmd = NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
args = []string{"query", "repo/alpine:", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff = &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
|
||||||
So(str, ShouldContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
|
||||||
So(str, ShouldContainSubstring, "repo/alpine repo2tag1 Os/Arch "+formatterDigest1+" false 525B")
|
|
||||||
So(str, ShouldContainSubstring, "repo/alpine repo2tag2 linux/amd64 "+formatterDigest2+" false 552B")
|
|
||||||
|
|
||||||
fmt.Println("\n", buff.String())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatsSearchCLI(t *testing.T) {
|
|
||||||
Convey("", t, func() {
|
|
||||||
rootDir := t.TempDir()
|
|
||||||
|
|
||||||
port := test.GetFreePort()
|
|
||||||
baseURL := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
conf.Storage.GC = false
|
|
||||||
defaultVal := true
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
|
||||||
}
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Config.Storage.RootDirectory = rootDir
|
|
||||||
cm := test.NewControllerManager(ctlr)
|
|
||||||
cm.StartAndWait(conf.HTTP.Port)
|
|
||||||
defer cm.StopServer()
|
|
||||||
|
|
||||||
const (
|
|
||||||
repo1 = "repo"
|
|
||||||
r1tag1 = "repo1tag1"
|
|
||||||
r1tag2 = "repo1tag2"
|
|
||||||
|
|
||||||
repo2 = "repo/alpine"
|
|
||||||
r2tag1 = "repo2tag1"
|
|
||||||
r2tag2 = "repo2tag2"
|
|
||||||
|
|
||||||
repo3 = "repo/test/alpine"
|
|
||||||
r3tag1 = "repo3tag1"
|
|
||||||
r3tag2 = "repo3tag2"
|
|
||||||
)
|
|
||||||
|
|
||||||
image1 := CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build()
|
|
||||||
image2 := CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build()
|
|
||||||
|
|
||||||
err := UploadImage(image1, baseURL, repo1, r1tag1)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
err = UploadImage(image2, baseURL, repo1, r1tag2)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(image1, baseURL, repo2, r2tag1)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
err = UploadImage(image2, baseURL, repo2, r2tag2)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = UploadImage(image1, baseURL, repo3, r3tag1)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
err = UploadImage(image2, baseURL, repo3, r3tag2)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
Convey("JSON format", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--format", "json", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
fmt.Println(buff.String())
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("YAML format", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--format", "yaml", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
fmt.Println(buff.String())
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Invalid format", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
|
||||||
baseURL))
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchCLIErrors(t *testing.T) {
|
|
||||||
Convey("Errors", t, func() {
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
|
|
||||||
Convey("no url provided", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"searchtest","showspinner":false}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("getConfigValue", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(`bad-json`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("bad showspinnerConfig ", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(
|
|
||||||
`{"configs":[{"_name":"searchtest", "url":"http://127.0.0.1:8080", "showspinner":"bad"}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("bad verifyTLSConfig ", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(
|
|
||||||
`{"configs":[{"_name":"searchtest", "url":"http://127.0.0.1:8080", "showspinner":false, "verify-tls": "bad"}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("url from config is empty", func() {
|
|
||||||
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
|
||||||
|
|
||||||
configPath := makeConfigFile(`{"configs":[{"_name":"searchtest", "url":"", "showspinner":false}]}`)
|
|
||||||
|
|
||||||
defer os.Remove(configPath)
|
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldNotBeNil)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchCommandGQL(t *testing.T) {
|
func TestSearchCommandGQL(t *testing.T) {
|
||||||
port := test.GetFreePort()
|
port := test.GetFreePort()
|
||||||
baseURL := test.GetBaseURL(port)
|
baseURL := test.GetBaseURL(port)
|
||||||
|
@ -865,70 +158,3 @@ func TestSearchCommandREST(t *testing.T) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSearchSort(t *testing.T) {
|
|
||||||
rootDir := t.TempDir()
|
|
||||||
port := test.GetFreePort()
|
|
||||||
baseURL := test.GetBaseURL(port)
|
|
||||||
conf := config.New()
|
|
||||||
conf.HTTP.Port = port
|
|
||||||
|
|
||||||
defaultVal := true
|
|
||||||
conf.Extensions = &extconf.ExtensionConfig{
|
|
||||||
Search: &extconf.SearchConfig{
|
|
||||||
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
|
||||||
CVE: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ctlr := api.NewController(conf)
|
|
||||||
ctlr.Config.Storage.RootDirectory = rootDir
|
|
||||||
|
|
||||||
image1 := CreateImageWith().DefaultLayers().
|
|
||||||
ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 1, 1, 1, 0, time.UTC)}).
|
|
||||||
Build()
|
|
||||||
|
|
||||||
image2 := CreateImageWith().DefaultLayers().
|
|
||||||
ImageConfig(ispec.Image{Created: DateRef(2020, 1, 1, 1, 1, 1, 0, time.UTC)}).
|
|
||||||
Build()
|
|
||||||
|
|
||||||
storeController := ociutils.GetDefaultStoreController(rootDir, ctlr.Log)
|
|
||||||
|
|
||||||
err := WriteImageToFileSystem(image1, "b-repo", "tag2", storeController)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = WriteImageToFileSystem(image2, "a-test-repo", "tag2", storeController)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
cm := test.NewControllerManager(ctlr)
|
|
||||||
cm.StartAndWait(conf.HTTP.Port)
|
|
||||||
|
|
||||||
defer cm.StopServer()
|
|
||||||
|
|
||||||
Convey("test sorting", t, func() {
|
|
||||||
args := []string{"query", "repo", "--sort-by", "relevance", "--url", baseURL}
|
|
||||||
cmd := NewSearchCommand(new(searchService))
|
|
||||||
buff := bytes.NewBufferString("")
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err := cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
str := buff.String()
|
|
||||||
So(strings.Index(str, "b-repo"), ShouldBeLessThan, strings.Index(str, "a-test-repo"))
|
|
||||||
|
|
||||||
args = []string{"query", "repo", "--sort-by", "alpha-asc", "--url", baseURL}
|
|
||||||
cmd = NewSearchCommand(new(searchService))
|
|
||||||
buff = bytes.NewBufferString("")
|
|
||||||
cmd.SetOut(buff)
|
|
||||||
cmd.SetErr(buff)
|
|
||||||
cmd.SetArgs(args)
|
|
||||||
err = cmd.Execute()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
str = buff.String()
|
|
||||||
So(strings.Index(str, "a-test-repo"), ShouldBeLessThan, strings.Index(str, "b-repo"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
796
pkg/cli/client/search_cmd_test.go
Normal file
796
pkg/cli/client/search_cmd_test.go
Normal file
|
@ -0,0 +1,796 @@
|
||||||
|
//go:build search
|
||||||
|
// +build search
|
||||||
|
|
||||||
|
package client_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
|
||||||
|
"zotregistry.io/zot/pkg/api"
|
||||||
|
"zotregistry.io/zot/pkg/api/config"
|
||||||
|
"zotregistry.io/zot/pkg/cli/client"
|
||||||
|
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||||
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
|
. "zotregistry.io/zot/pkg/test/image-utils"
|
||||||
|
ociutils "zotregistry.io/zot/pkg/test/oci-utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
customArtTypeV1 = "application/custom.art.type.v1"
|
||||||
|
customArtTypeV2 = "application/custom.art.type.v2"
|
||||||
|
repoName = "repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReferrerCLI(t *testing.T) {
|
||||||
|
Convey("Test GQL", t, func() {
|
||||||
|
rootDir := t.TempDir()
|
||||||
|
|
||||||
|
port := test.GetFreePort()
|
||||||
|
baseURL := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
conf.Storage.GC = false
|
||||||
|
defaultVal := true
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||||
|
}
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Config.Storage.RootDirectory = rootDir
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
cm.StartAndWait(conf.HTTP.Port)
|
||||||
|
defer cm.StopServer()
|
||||||
|
|
||||||
|
repo := repoName
|
||||||
|
image := CreateRandomImage()
|
||||||
|
|
||||||
|
err := UploadImage(image, baseURL, repo, "tag")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
ref1 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
RandomConfig().
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
ref2 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
ArtifactConfig(customArtTypeV1).
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
ref3 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
RandomConfig().
|
||||||
|
ArtifactType(customArtTypeV2).
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||||
|
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
||||||
|
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
||||||
|
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
||||||
|
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
||||||
|
|
||||||
|
fmt.Println(buff.String())
|
||||||
|
|
||||||
|
os.Remove(configPath)
|
||||||
|
|
||||||
|
args = []string{"subject", repo + ":" + "tag", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
cmd = client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
buff = &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||||
|
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
||||||
|
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
||||||
|
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
||||||
|
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
||||||
|
|
||||||
|
fmt.Println(buff.String())
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Test REST", t, func() {
|
||||||
|
rootDir := t.TempDir()
|
||||||
|
|
||||||
|
port := test.GetFreePort()
|
||||||
|
baseURL := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
conf.Storage.GC = false
|
||||||
|
defaultVal := false
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||||
|
}
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Config.Storage.RootDirectory = rootDir
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
cm.StartAndWait(conf.HTTP.Port)
|
||||||
|
defer cm.StopServer()
|
||||||
|
|
||||||
|
repo := repoName
|
||||||
|
image := CreateRandomImage()
|
||||||
|
|
||||||
|
err := UploadImage(image, baseURL, repo, "tag")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
ref1 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
RandomConfig().
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
ref2 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
ArtifactConfig(customArtTypeV1).
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
ref3 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
RandomConfig().
|
||||||
|
ArtifactType(customArtTypeV2).
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
// get referrers by digest
|
||||||
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||||
|
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
||||||
|
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
||||||
|
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
||||||
|
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
||||||
|
fmt.Println(buff.String())
|
||||||
|
|
||||||
|
os.Remove(configPath)
|
||||||
|
|
||||||
|
args = []string{"subject", repo + ":" + "tag", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff = &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||||
|
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
||||||
|
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
||||||
|
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
||||||
|
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
||||||
|
fmt.Println(buff.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatsReferrersCLI(t *testing.T) {
|
||||||
|
Convey("Create server", t, func() {
|
||||||
|
rootDir := t.TempDir()
|
||||||
|
|
||||||
|
port := test.GetFreePort()
|
||||||
|
baseURL := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
conf.Storage.GC = false
|
||||||
|
defaultVal := false
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||||
|
}
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Config.Storage.RootDirectory = rootDir
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
cm.StartAndWait(conf.HTTP.Port)
|
||||||
|
defer cm.StopServer()
|
||||||
|
|
||||||
|
repo := repoName
|
||||||
|
image := CreateRandomImage()
|
||||||
|
|
||||||
|
err := UploadImage(image, baseURL, repo, "tag")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
// add referrers
|
||||||
|
ref1 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
RandomConfig().
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
ref2 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
ArtifactConfig(customArtTypeV1).
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
ref3 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
RandomConfig().
|
||||||
|
ArtifactType(customArtTypeV2).
|
||||||
|
Subject(image.DescriptorRef()).Build()
|
||||||
|
|
||||||
|
err = UploadImage(ref1, baseURL, repo, ref1.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(ref2, baseURL, repo, ref2.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(ref3, baseURL, repo, ref3.DigestStr())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
Convey("JSON format", func() {
|
||||||
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "json", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
fmt.Println(buff.String())
|
||||||
|
})
|
||||||
|
Convey("YAML format", func() {
|
||||||
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "yaml", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
fmt.Println(buff.String())
|
||||||
|
})
|
||||||
|
Convey("Invalid format", func() {
|
||||||
|
args := []string{"subject", repo + "@" + image.DigestStr(), "--format", "invalid_format", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReferrersCLIErrors(t *testing.T) {
|
||||||
|
Convey("Errors", t, func() {
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
Convey("no url provided", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(`{"configs":[{"_name":"reftest","showspinner":false}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("getConfigValue", func() {
|
||||||
|
args := []string{"subject", "repo/alpine", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(`bad-json`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("bad showspinnerConfig ", func() {
|
||||||
|
args := []string{"query", "repo", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":"bad"}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("bad verifyTLSConfig ", func() {
|
||||||
|
args := []string{"query", "repo", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(
|
||||||
|
`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":false, "verify-tls": "bad"}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("url from config is empty", func() {
|
||||||
|
args := []string{"subject", "repo/alpine", "--config", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"", "showspinner":false}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("bad params combination", func() {
|
||||||
|
args := []string{"query", "repo", "reftest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(`{"configs":[{"_name":"reftest", "url":"http://127.0.0.1:8080", "showspinner":false}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchCLI(t *testing.T) {
|
||||||
|
Convey("Test GQL", t, func() {
|
||||||
|
rootDir := t.TempDir()
|
||||||
|
|
||||||
|
port := test.GetFreePort()
|
||||||
|
baseURL := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
conf.Storage.GC = false
|
||||||
|
defaultVal := true
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||||
|
}
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Config.Storage.RootDirectory = rootDir
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
cm.StartAndWait(conf.HTTP.Port)
|
||||||
|
defer cm.StopServer()
|
||||||
|
|
||||||
|
const (
|
||||||
|
repo1 = "repo"
|
||||||
|
r1tag1 = "repo1tag1"
|
||||||
|
r1tag2 = "repo1tag2"
|
||||||
|
|
||||||
|
repo2 = "repo/alpine"
|
||||||
|
r2tag1 = "repo2tag1"
|
||||||
|
r2tag2 = "repo2tag2"
|
||||||
|
|
||||||
|
repo3 = "repo/test/alpine"
|
||||||
|
r3tag1 = "repo3tag1"
|
||||||
|
r3tag2 = "repo3tag2"
|
||||||
|
)
|
||||||
|
|
||||||
|
image1 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
ImageConfig(ispec.Image{
|
||||||
|
Created: DefaultTimeRef(),
|
||||||
|
Platform: ispec.Platform{OS: "Os", Architecture: "Arch"},
|
||||||
|
}).
|
||||||
|
Build()
|
||||||
|
formatterDigest1 := image1.Digest().Encoded()[:8]
|
||||||
|
|
||||||
|
image2 := CreateImageWith().
|
||||||
|
RandomLayers(1, 10).
|
||||||
|
DefaultConfig().
|
||||||
|
Build()
|
||||||
|
formatterDigest2 := image2.Digest().Encoded()[:8]
|
||||||
|
|
||||||
|
err := UploadImage(image1, baseURL, repo1, r1tag1)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = UploadImage(image2, baseURL, repo1, r1tag2)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(image1, baseURL, repo2, r2tag1)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = UploadImage(image2, baseURL, repo2, r2tag2)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(image1, baseURL, repo3, r3tag1)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = UploadImage(image2, baseURL, repo3, r3tag2)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
// search by repos
|
||||||
|
|
||||||
|
args := []string{"query", "test/alpin", "--verbose", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
space := regexp.MustCompile(`\s+`)
|
||||||
|
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||||
|
So(str, ShouldContainSubstring, "NAME SIZE LAST UPDATED DOWNLOADS STARS PLATFORMS")
|
||||||
|
So(str, ShouldContainSubstring, "repo/test/alpine 1.1kB 2010-01-01 01:01:01 +0000 UTC 0 0")
|
||||||
|
So(str, ShouldContainSubstring, "Os/Arch")
|
||||||
|
So(str, ShouldContainSubstring, "linux/amd64")
|
||||||
|
|
||||||
|
fmt.Println("\n", buff.String())
|
||||||
|
|
||||||
|
os.Remove(configPath)
|
||||||
|
|
||||||
|
cmd = client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
args = []string{"query", "repo/alpine:", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath = makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff = &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||||
|
So(str, ShouldContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||||
|
So(str, ShouldContainSubstring, "repo/alpine repo2tag1 Os/Arch "+formatterDigest1+" false 525B")
|
||||||
|
So(str, ShouldContainSubstring, "repo/alpine repo2tag2 linux/amd64 "+formatterDigest2+" false 552B")
|
||||||
|
|
||||||
|
fmt.Println("\n", buff.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatsSearchCLI(t *testing.T) {
|
||||||
|
Convey("", t, func() {
|
||||||
|
rootDir := t.TempDir()
|
||||||
|
|
||||||
|
port := test.GetFreePort()
|
||||||
|
baseURL := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
conf.Storage.GC = false
|
||||||
|
defaultVal := true
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||||
|
}
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Config.Storage.RootDirectory = rootDir
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
cm.StartAndWait(conf.HTTP.Port)
|
||||||
|
defer cm.StopServer()
|
||||||
|
|
||||||
|
const (
|
||||||
|
repo1 = "repo"
|
||||||
|
r1tag1 = "repo1tag1"
|
||||||
|
r1tag2 = "repo1tag2"
|
||||||
|
|
||||||
|
repo2 = "repo/alpine"
|
||||||
|
r2tag1 = "repo2tag1"
|
||||||
|
r2tag2 = "repo2tag2"
|
||||||
|
|
||||||
|
repo3 = "repo/test/alpine"
|
||||||
|
r3tag1 = "repo3tag1"
|
||||||
|
r3tag2 = "repo3tag2"
|
||||||
|
)
|
||||||
|
|
||||||
|
image1 := CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build()
|
||||||
|
image2 := CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build()
|
||||||
|
|
||||||
|
err := UploadImage(image1, baseURL, repo1, r1tag1)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = UploadImage(image2, baseURL, repo1, r1tag2)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(image1, baseURL, repo2, r2tag1)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = UploadImage(image2, baseURL, repo2, r2tag2)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = UploadImage(image1, baseURL, repo3, r3tag1)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = UploadImage(image2, baseURL, repo3, r3tag2)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
Convey("JSON format", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--format", "json", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
fmt.Println(buff.String())
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("YAML format", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--format", "yaml", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
fmt.Println(buff.String())
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Invalid format", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"searchtest","url":"%s","showspinner":false}]}`,
|
||||||
|
baseURL))
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchCLIErrors(t *testing.T) {
|
||||||
|
Convey("Errors", t, func() {
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
|
||||||
|
Convey("no url provided", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(`{"configs":[{"_name":"searchtest","showspinner":false}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("getConfigValue", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(`bad-json`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("bad showspinnerConfig ", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(
|
||||||
|
`{"configs":[{"_name":"searchtest", "url":"http://127.0.0.1:8080", "showspinner":"bad"}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("bad verifyTLSConfig ", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(
|
||||||
|
`{"configs":[{"_name":"searchtest", "url":"http://127.0.0.1:8080", "showspinner":false, "verify-tls": "bad"}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("url from config is empty", func() {
|
||||||
|
args := []string{"query", "repo/alpine", "--format", "invalid", "--config", "searchtest"}
|
||||||
|
|
||||||
|
configPath := makeConfigFile(`{"configs":[{"_name":"searchtest", "url":"", "showspinner":false}]}`)
|
||||||
|
|
||||||
|
defer os.Remove(configPath)
|
||||||
|
|
||||||
|
buff := &bytes.Buffer{}
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSearchSort(t *testing.T) {
|
||||||
|
rootDir := t.TempDir()
|
||||||
|
port := test.GetFreePort()
|
||||||
|
baseURL := test.GetBaseURL(port)
|
||||||
|
conf := config.New()
|
||||||
|
conf.HTTP.Port = port
|
||||||
|
|
||||||
|
defaultVal := true
|
||||||
|
conf.Extensions = &extconf.ExtensionConfig{
|
||||||
|
Search: &extconf.SearchConfig{
|
||||||
|
BaseConfig: extconf.BaseConfig{Enable: &defaultVal},
|
||||||
|
CVE: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctlr := api.NewController(conf)
|
||||||
|
ctlr.Config.Storage.RootDirectory = rootDir
|
||||||
|
|
||||||
|
image1 := CreateImageWith().DefaultLayers().
|
||||||
|
ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 1, 1, 1, 0, time.UTC)}).
|
||||||
|
Build()
|
||||||
|
|
||||||
|
image2 := CreateImageWith().DefaultLayers().
|
||||||
|
ImageConfig(ispec.Image{Created: DateRef(2020, 1, 1, 1, 1, 1, 0, time.UTC)}).
|
||||||
|
Build()
|
||||||
|
|
||||||
|
storeController := ociutils.GetDefaultStoreController(rootDir, ctlr.Log)
|
||||||
|
|
||||||
|
err := WriteImageToFileSystem(image1, "b-repo", "tag2", storeController)
|
||||||
|
if err != nil {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = WriteImageToFileSystem(image2, "a-test-repo", "tag2", storeController)
|
||||||
|
if err != nil {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
cm.StartAndWait(conf.HTTP.Port)
|
||||||
|
|
||||||
|
defer cm.StopServer()
|
||||||
|
|
||||||
|
Convey("test sorting", t, func() {
|
||||||
|
args := []string{"query", "repo", "--sort-by", "relevance", "--url", baseURL}
|
||||||
|
cmd := client.NewSearchCommand(client.NewSearchService())
|
||||||
|
buff := bytes.NewBufferString("")
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err := cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
str := buff.String()
|
||||||
|
So(strings.Index(str, "b-repo"), ShouldBeLessThan, strings.Index(str, "a-test-repo"))
|
||||||
|
|
||||||
|
args = []string{"query", "repo", "--sort-by", "alpha-asc", "--url", baseURL}
|
||||||
|
cmd = client.NewSearchCommand(client.NewSearchService())
|
||||||
|
buff = bytes.NewBufferString("")
|
||||||
|
cmd.SetOut(buff)
|
||||||
|
cmd.SetErr(buff)
|
||||||
|
cmd.SetArgs(args)
|
||||||
|
err = cmd.Execute()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
str = buff.String()
|
||||||
|
So(strings.Index(str, "a-test-repo"), ShouldBeLessThan, strings.Index(str, "b-repo"))
|
||||||
|
})
|
||||||
|
}
|
|
@ -17,8 +17,8 @@ import (
|
||||||
|
|
||||||
const CveDBRetryInterval = 3
|
const CveDBRetryInterval = 3
|
||||||
|
|
||||||
func SearchAllImages(config searchConfig) error {
|
func SearchAllImages(config SearchConfig) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
imageErr := make(chan stringResult)
|
imageErr := make(chan stringResult)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ func SearchAllImages(config searchConfig) error {
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
go config.searchService.getAllImages(ctx, config, username, password, imageErr, &wg)
|
go config.SearchService.getAllImages(ctx, config, username, password, imageErr, &wg)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
|
@ -41,13 +41,13 @@ func SearchAllImages(config searchConfig) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchAllImagesGQL(config searchConfig) error {
|
func SearchAllImagesGQL(config SearchConfig) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
imageList, err := config.searchService.getImagesGQL(ctx, config, username, password, "")
|
imageList, err := config.SearchService.getImagesGQL(ctx, config, username, password, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,8 @@ func SearchAllImagesGQL(config searchConfig) error {
|
||||||
return printImageResult(config, imageListData)
|
return printImageResult(config, imageListData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchImageByName(config searchConfig, image string) error {
|
func SearchImageByName(config SearchConfig, image string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
imageErr := make(chan stringResult)
|
imageErr := make(chan stringResult)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ func SearchImageByName(config searchConfig, image string) error {
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
go config.searchService.getImageByName(ctx, config, username, password,
|
go config.SearchService.getImageByName(ctx, config, username, password,
|
||||||
image, imageErr, &wg)
|
image, imageErr, &wg)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
|
@ -91,15 +91,15 @@ func SearchImageByName(config searchConfig, image string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchImageByNameGQL(config searchConfig, imageName string) error {
|
func SearchImageByNameGQL(config SearchConfig, imageName string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
repo, tag := zcommon.GetImageDirAndTag(imageName)
|
repo, tag := zcommon.GetImageDirAndTag(imageName)
|
||||||
|
|
||||||
imageList, err := config.searchService.getImagesGQL(ctx, config, username, password, repo)
|
imageList, err := config.SearchService.getImagesGQL(ctx, config, username, password, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -115,8 +115,8 @@ func SearchImageByNameGQL(config searchConfig, imageName string) error {
|
||||||
return printImageResult(config, imageListData)
|
return printImageResult(config, imageListData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchImagesByDigest(config searchConfig, digest string) error {
|
func SearchImagesByDigest(config SearchConfig, digest string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
imageErr := make(chan stringResult)
|
imageErr := make(chan stringResult)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ func SearchImagesByDigest(config searchConfig, digest string) error {
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
go config.searchService.getImagesByDigest(ctx, config, username, password,
|
go config.SearchService.getImagesByDigest(ctx, config, username, password,
|
||||||
digest, imageErr, &wg)
|
digest, imageErr, &wg)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
|
@ -141,13 +141,13 @@ func SearchImagesByDigest(config searchConfig, digest string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchDerivedImageListGQL(config searchConfig, derivedImage string) error {
|
func SearchDerivedImageListGQL(config SearchConfig, derivedImage string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
imageList, err := config.searchService.getDerivedImageListGQL(ctx, config, username,
|
imageList, err := config.SearchService.getDerivedImageListGQL(ctx, config, username,
|
||||||
password, derivedImage)
|
password, derivedImage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -162,13 +162,13 @@ func SearchDerivedImageListGQL(config searchConfig, derivedImage string) error {
|
||||||
return printImageResult(config, imageListData)
|
return printImageResult(config, imageListData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchBaseImageListGQL(config searchConfig, baseImage string) error {
|
func SearchBaseImageListGQL(config SearchConfig, baseImage string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
imageList, err := config.searchService.getBaseImageListGQL(ctx, config, username,
|
imageList, err := config.SearchService.getBaseImageListGQL(ctx, config, username,
|
||||||
password, baseImage)
|
password, baseImage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -183,13 +183,13 @@ func SearchBaseImageListGQL(config searchConfig, baseImage string) error {
|
||||||
return printImageResult(config, imageListData)
|
return printImageResult(config, imageListData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchImagesForDigestGQL(config searchConfig, digest string) error {
|
func SearchImagesForDigestGQL(config SearchConfig, digest string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
imageList, err := config.searchService.getImagesForDigestGQL(ctx, config, username, password, digest)
|
imageList, err := config.SearchService.getImagesForDigestGQL(ctx, config, username, password, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -207,8 +207,8 @@ func SearchImagesForDigestGQL(config searchConfig, digest string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchCVEForImageGQL(config searchConfig, image, searchedCveID string) error {
|
func SearchCVEForImageGQL(config SearchConfig, image, searchedCveID string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -218,7 +218,7 @@ func SearchCVEForImageGQL(config searchConfig, image, searchedCveID string) erro
|
||||||
err := zcommon.RetryWithContext(ctx, func(attempt int, retryIn time.Duration) error {
|
err := zcommon.RetryWithContext(ctx, func(attempt int, retryIn time.Duration) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
cveList, err = config.searchService.getCveByImageGQL(ctx, config, username, password, image, searchedCveID)
|
cveList, err = config.SearchService.getCveByImageGQL(ctx, config, username, password, image, searchedCveID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
|
if !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
|
||||||
cancel()
|
cancel()
|
||||||
|
@ -226,7 +226,7 @@ func SearchCVEForImageGQL(config searchConfig, image, searchedCveID string) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(config.resultWriter,
|
fmt.Fprintf(config.ResultWriter,
|
||||||
"[warning] CVE DB is not ready [%d] - retry in %d seconds\n", attempt, int(retryIn.Seconds()))
|
"[warning] CVE DB is not ready [%d] - retry in %d seconds\n", attempt, int(retryIn.Seconds()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,30 +237,30 @@ func SearchCVEForImageGQL(config searchConfig, image, searchedCveID string) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cveList.Data.CVEListForImage.CVEList) == 0 {
|
if len(cveList.Data.CVEListForImage.CVEList) == 0 {
|
||||||
fmt.Fprint(config.resultWriter, "No CVEs found for image\n")
|
fmt.Fprint(config.ResultWriter, "No CVEs found for image\n")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|
||||||
if config.outputFormat == defaultOutputFormat || config.outputFormat == "" {
|
if config.OutputFormat == defaultOutputFormat || config.OutputFormat == "" {
|
||||||
printCVETableHeader(&builder)
|
printCVETableHeader(&builder)
|
||||||
fmt.Fprint(config.resultWriter, builder.String())
|
fmt.Fprint(config.ResultWriter, builder.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := cveList.string(config.outputFormat)
|
out, err := cveList.string(config.OutputFormat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprint(config.resultWriter, out)
|
fmt.Fprint(config.ResultWriter, out)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchImagesByCVEIDGQL(config searchConfig, repo, cveid string) error {
|
func SearchImagesByCVEIDGQL(config SearchConfig, repo, cveid string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -270,7 +270,7 @@ func SearchImagesByCVEIDGQL(config searchConfig, repo, cveid string) error {
|
||||||
err := zcommon.RetryWithContext(ctx, func(attempt int, retryIn time.Duration) error {
|
err := zcommon.RetryWithContext(ctx, func(attempt int, retryIn time.Duration) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
imageList, err = config.searchService.getTagsForCVEGQL(ctx, config, username, password,
|
imageList, err = config.SearchService.getTagsForCVEGQL(ctx, config, username, password,
|
||||||
repo, cveid)
|
repo, cveid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
|
if !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
|
||||||
|
@ -279,7 +279,7 @@ func SearchImagesByCVEIDGQL(config searchConfig, repo, cveid string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(config.resultWriter,
|
fmt.Fprintf(config.ResultWriter,
|
||||||
"[warning] CVE DB is not ready [%d] - retry in %d seconds\n", attempt, int(retryIn.Seconds()))
|
"[warning] CVE DB is not ready [%d] - retry in %d seconds\n", attempt, int(retryIn.Seconds()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,8 +298,8 @@ func SearchImagesByCVEIDGQL(config searchConfig, repo, cveid string) error {
|
||||||
return printImageResult(config, imageListData)
|
return printImageResult(config, imageListData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchFixedTagsGQL(config searchConfig, repo, cveid string) error {
|
func SearchFixedTagsGQL(config SearchConfig, repo, cveid string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -309,7 +309,7 @@ func SearchFixedTagsGQL(config searchConfig, repo, cveid string) error {
|
||||||
err := zcommon.RetryWithContext(ctx, func(attempt int, retryIn time.Duration) error {
|
err := zcommon.RetryWithContext(ctx, func(attempt int, retryIn time.Duration) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
fixedTags, err = config.searchService.getFixedTagsForCVEGQL(ctx, config, username, password,
|
fixedTags, err = config.SearchService.getFixedTagsForCVEGQL(ctx, config, username, password,
|
||||||
repo, cveid)
|
repo, cveid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
|
if !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
|
||||||
|
@ -318,7 +318,7 @@ func SearchFixedTagsGQL(config searchConfig, repo, cveid string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(config.resultWriter,
|
fmt.Fprintf(config.ResultWriter,
|
||||||
"[warning] CVE DB is not ready [%d] - retry in %d seconds\n", attempt, int(retryIn.Seconds()))
|
"[warning] CVE DB is not ready [%d] - retry in %d seconds\n", attempt, int(retryIn.Seconds()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,13 +337,13 @@ func SearchFixedTagsGQL(config searchConfig, repo, cveid string) error {
|
||||||
return printImageResult(config, imageList)
|
return printImageResult(config, imageList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GlobalSearchGQL(config searchConfig, query string) error {
|
func GlobalSearchGQL(config SearchConfig, query string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
globalSearchResult, err := config.searchService.globalSearchGQL(ctx, config, username, password, query)
|
globalSearchResult, err := config.SearchService.globalSearchGQL(ctx, config, username, password, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -367,8 +367,8 @@ func GlobalSearchGQL(config searchConfig, query string) error {
|
||||||
return printRepoResults(config, reposList)
|
return printRepoResults(config, reposList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchReferrersGQL(config searchConfig, subject string) error {
|
func SearchReferrersGQL(config SearchConfig, subject string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
|
|
||||||
repo, ref, refIsTag, err := zcommon.GetRepoReference(subject)
|
repo, ref, refIsTag, err := zcommon.GetRepoReference(subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -384,7 +384,7 @@ func SearchReferrersGQL(config searchConfig, subject string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := config.searchService.getReferrersGQL(context.Background(), config, username, password, repo, digest)
|
response, err := config.SearchService.getReferrersGQL(context.Background(), config, username, password, repo, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -399,13 +399,13 @@ func SearchReferrersGQL(config searchConfig, subject string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printReferrersTableHeader(config, config.resultWriter, maxArtifactTypeLen)
|
printReferrersTableHeader(config, config.ResultWriter, maxArtifactTypeLen)
|
||||||
|
|
||||||
return printReferrersResult(config, referrersList, maxArtifactTypeLen)
|
return printReferrersResult(config, referrersList, maxArtifactTypeLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchReferrers(config searchConfig, subject string) error {
|
func SearchReferrers(config SearchConfig, subject string) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
|
|
||||||
repo, ref, refIsTag, err := zcommon.GetRepoReference(subject)
|
repo, ref, refIsTag, err := zcommon.GetRepoReference(subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -421,7 +421,7 @@ func SearchReferrers(config searchConfig, subject string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
referrersList, err := config.searchService.getReferrers(context.Background(), config, username, password,
|
referrersList, err := config.SearchService.getReferrers(context.Background(), config, username, password,
|
||||||
repo, digest)
|
repo, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -435,13 +435,13 @@ func SearchReferrers(config searchConfig, subject string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printReferrersTableHeader(config, config.resultWriter, maxArtifactTypeLen)
|
printReferrersTableHeader(config, config.ResultWriter, maxArtifactTypeLen)
|
||||||
|
|
||||||
return printReferrersResult(config, referrersList, maxArtifactTypeLen)
|
return printReferrersResult(config, referrersList, maxArtifactTypeLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchRepos(config searchConfig) error {
|
func SearchRepos(config SearchConfig) error {
|
||||||
username, password := getUsernameAndPassword(config.user)
|
username, password := getUsernameAndPassword(config.User)
|
||||||
repoErr := make(chan stringResult)
|
repoErr := make(chan stringResult)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
@ -449,7 +449,7 @@ func SearchRepos(config searchConfig) error {
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
go config.searchService.getRepos(ctx, config, username, password, repoErr, &wg)
|
go config.SearchService.getRepos(ctx, config, username, password, repoErr, &wg)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
|
|
|
@ -29,7 +29,7 @@ func TestSearchAllImages(t *testing.T) {
|
||||||
Convey("SearchAllImages", t, func() {
|
Convey("SearchAllImages", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getAllImagesFn: func(ctx context.Context, config searchConfig, username, password string,
|
getAllImagesFn: func(ctx context.Context, config SearchConfig, username, password string,
|
||||||
channel chan stringResult, wtgrp *sync.WaitGroup,
|
channel chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
||||||
|
@ -51,7 +51,7 @@ func TestSearchAllImagesGQL(t *testing.T) {
|
||||||
Convey("SearchAllImagesGQL", t, func() {
|
Convey("SearchAllImagesGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImagesGQLFn: func(ctx context.Context, config searchConfig, username, password, imageName string,
|
getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
|
||||||
) (*common.ImageListResponse, error) {
|
) (*common.ImageListResponse, error) {
|
||||||
return &common.ImageListResponse{ImageList: common.ImageList{
|
return &common.ImageListResponse{ImageList: common.ImageList{
|
||||||
PaginatedImagesResult: common.PaginatedImagesResult{
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
||||||
|
@ -72,7 +72,7 @@ func TestSearchAllImagesGQL(t *testing.T) {
|
||||||
Convey("SearchAllImagesGQL error", t, func() {
|
Convey("SearchAllImagesGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImagesGQLFn: func(ctx context.Context, config searchConfig, username, password, imageName string,
|
getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
|
||||||
) (*common.ImageListResponse, error) {
|
) (*common.ImageListResponse, error) {
|
||||||
return &common.ImageListResponse{ImageList: common.ImageList{
|
return &common.ImageListResponse{ImageList: common.ImageList{
|
||||||
PaginatedImagesResult: common.PaginatedImagesResult{
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
||||||
|
@ -91,7 +91,7 @@ func TestSearchImageByName(t *testing.T) {
|
||||||
Convey("SearchImageByName", t, func() {
|
Convey("SearchImageByName", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImageByNameFn: func(ctx context.Context, config searchConfig, username string, password string, imageName string,
|
getImageByNameFn: func(ctx context.Context, config SearchConfig, username string, password string, imageName string,
|
||||||
channel chan stringResult, wtgrp *sync.WaitGroup,
|
channel chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
||||||
|
@ -111,7 +111,7 @@ func TestSearchImageByName(t *testing.T) {
|
||||||
Convey("SearchImageByName error", t, func() {
|
Convey("SearchImageByName error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImageByNameFn: func(ctx context.Context, config searchConfig, username string, password string, imageName string,
|
getImageByNameFn: func(ctx context.Context, config SearchConfig, username string, password string, imageName string,
|
||||||
channel chan stringResult, wtgrp *sync.WaitGroup,
|
channel chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
channel <- stringResult{StrValue: "", Err: zerr.ErrInjected}
|
channel <- stringResult{StrValue: "", Err: zerr.ErrInjected}
|
||||||
|
@ -127,7 +127,7 @@ func TestSearchImageByNameGQL(t *testing.T) {
|
||||||
Convey("SearchImageByNameGQL", t, func() {
|
Convey("SearchImageByNameGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImagesGQLFn: func(ctx context.Context, config searchConfig, username, password, imageName string,
|
getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
|
||||||
) (*common.ImageListResponse, error) {
|
) (*common.ImageListResponse, error) {
|
||||||
return &common.ImageListResponse{ImageList: common.ImageList{
|
return &common.ImageListResponse{ImageList: common.ImageList{
|
||||||
PaginatedImagesResult: common.PaginatedImagesResult{
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
||||||
|
@ -148,7 +148,7 @@ func TestSearchImageByNameGQL(t *testing.T) {
|
||||||
Convey("SearchImageByNameGQL error", t, func() {
|
Convey("SearchImageByNameGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImagesGQLFn: func(ctx context.Context, config searchConfig, username, password, imageName string,
|
getImagesGQLFn: func(ctx context.Context, config SearchConfig, username, password, imageName string,
|
||||||
) (*common.ImageListResponse, error) {
|
) (*common.ImageListResponse, error) {
|
||||||
return &common.ImageListResponse{ImageList: common.ImageList{
|
return &common.ImageListResponse{ImageList: common.ImageList{
|
||||||
PaginatedImagesResult: common.PaginatedImagesResult{
|
PaginatedImagesResult: common.PaginatedImagesResult{
|
||||||
|
@ -167,7 +167,7 @@ func TestSearchImagesByDigest(t *testing.T) {
|
||||||
Convey("SearchImagesByDigest", t, func() {
|
Convey("SearchImagesByDigest", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImagesByDigestFn: func(ctx context.Context, config searchConfig, username string, password string, digest string,
|
getImagesByDigestFn: func(ctx context.Context, config SearchConfig, username string, password string, digest string,
|
||||||
rch chan stringResult, wtgrp *sync.WaitGroup,
|
rch chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
|
||||||
|
@ -187,7 +187,7 @@ func TestSearchImagesByDigest(t *testing.T) {
|
||||||
Convey("SearchImagesByDigest error", t, func() {
|
Convey("SearchImagesByDigest error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImagesByDigestFn: func(ctx context.Context, config searchConfig, username string, password string, digest string,
|
getImagesByDigestFn: func(ctx context.Context, config SearchConfig, username string, password string, digest string,
|
||||||
rch chan stringResult, wtgrp *sync.WaitGroup,
|
rch chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
rch <- stringResult{StrValue: "", Err: zerr.ErrInjected}
|
rch <- stringResult{StrValue: "", Err: zerr.ErrInjected}
|
||||||
|
@ -203,7 +203,7 @@ func TestSearchDerivedImageListGQL(t *testing.T) {
|
||||||
Convey("SearchDerivedImageListGQL", t, func() {
|
Convey("SearchDerivedImageListGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getDerivedImageListGQLFn: func(ctx context.Context, config searchConfig, username string, password string,
|
getDerivedImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
||||||
derivedImage string) (*common.DerivedImageListResponse, error,
|
derivedImage string) (*common.DerivedImageListResponse, error,
|
||||||
) {
|
) {
|
||||||
return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
|
return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
|
||||||
|
@ -227,7 +227,7 @@ func TestSearchDerivedImageListGQL(t *testing.T) {
|
||||||
Convey("SearchDerivedImageListGQL error", t, func() {
|
Convey("SearchDerivedImageListGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getDerivedImageListGQLFn: func(ctx context.Context, config searchConfig, username string, password string,
|
getDerivedImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
||||||
derivedImage string) (*common.DerivedImageListResponse, error,
|
derivedImage string) (*common.DerivedImageListResponse, error,
|
||||||
) {
|
) {
|
||||||
return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
|
return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
|
||||||
|
@ -245,7 +245,7 @@ func TestSearchBaseImageListGQL(t *testing.T) {
|
||||||
Convey("SearchBaseImageListGQL", t, func() {
|
Convey("SearchBaseImageListGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getBaseImageListGQLFn: func(ctx context.Context, config searchConfig, username string, password string,
|
getBaseImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
||||||
derivedImage string) (*common.BaseImageListResponse, error,
|
derivedImage string) (*common.BaseImageListResponse, error,
|
||||||
) {
|
) {
|
||||||
return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
|
return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
|
||||||
|
@ -267,7 +267,7 @@ func TestSearchBaseImageListGQL(t *testing.T) {
|
||||||
Convey("SearchBaseImageListGQL error", t, func() {
|
Convey("SearchBaseImageListGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getBaseImageListGQLFn: func(ctx context.Context, config searchConfig, username string, password string,
|
getBaseImageListGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
||||||
derivedImage string) (*common.BaseImageListResponse, error,
|
derivedImage string) (*common.BaseImageListResponse, error,
|
||||||
) {
|
) {
|
||||||
return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
|
return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
|
||||||
|
@ -285,7 +285,7 @@ func TestSearchImagesForDigestGQL(t *testing.T) {
|
||||||
Convey("SearchImagesForDigestGQL", t, func() {
|
Convey("SearchImagesForDigestGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImagesForDigestGQLFn: func(ctx context.Context, config searchConfig, username string,
|
getImagesForDigestGQLFn: func(ctx context.Context, config SearchConfig, username string,
|
||||||
password string, digest string) (*common.ImagesForDigest, error,
|
password string, digest string) (*common.ImagesForDigest, error,
|
||||||
) {
|
) {
|
||||||
return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
|
return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
|
||||||
|
@ -307,7 +307,7 @@ func TestSearchImagesForDigestGQL(t *testing.T) {
|
||||||
Convey("SearchImagesForDigestGQL error", t, func() {
|
Convey("SearchImagesForDigestGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getImagesForDigestGQLFn: func(ctx context.Context, config searchConfig, username string,
|
getImagesForDigestGQLFn: func(ctx context.Context, config SearchConfig, username string,
|
||||||
password string, digest string) (*common.ImagesForDigest, error,
|
password string, digest string) (*common.ImagesForDigest, error,
|
||||||
) {
|
) {
|
||||||
return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
|
return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
|
||||||
|
@ -325,7 +325,7 @@ func TestSearchCVEForImageGQL(t *testing.T) {
|
||||||
Convey("SearchCVEForImageGQL", t, func() {
|
Convey("SearchCVEForImageGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getCveByImageGQLFn: func(ctx context.Context, config searchConfig, username string, password string,
|
getCveByImageGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
||||||
imageName string, searchedCVE string) (*cveResult, error,
|
imageName string, searchedCVE string) (*cveResult, error,
|
||||||
) {
|
) {
|
||||||
return &cveResult{
|
return &cveResult{
|
||||||
|
@ -363,7 +363,7 @@ func TestSearchCVEForImageGQL(t *testing.T) {
|
||||||
Convey("SearchCVEForImageGQL", t, func() {
|
Convey("SearchCVEForImageGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getCveByImageGQLFn: func(ctx context.Context, config searchConfig, username string, password string,
|
getCveByImageGQLFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
||||||
imageName string, searchedCVE string) (*cveResult, error,
|
imageName string, searchedCVE string) (*cveResult, error,
|
||||||
) {
|
) {
|
||||||
return &cveResult{}, zerr.ErrInjected
|
return &cveResult{}, zerr.ErrInjected
|
||||||
|
@ -379,7 +379,7 @@ func TestSearchImagesByCVEIDGQL(t *testing.T) {
|
||||||
Convey("SearchImagesByCVEIDGQL", t, func() {
|
Convey("SearchImagesByCVEIDGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getTagsForCVEGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName, cveID string) (*common.ImagesForCve, error,
|
imageName, cveID string) (*common.ImagesForCve, error,
|
||||||
) {
|
) {
|
||||||
return &common.ImagesForCve{
|
return &common.ImagesForCve{
|
||||||
|
@ -405,7 +405,7 @@ func TestSearchImagesByCVEIDGQL(t *testing.T) {
|
||||||
Convey("SearchImagesByCVEIDGQL error", t, func() {
|
Convey("SearchImagesByCVEIDGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getTagsForCVEGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName, cveID string) (*common.ImagesForCve, error,
|
imageName, cveID string) (*common.ImagesForCve, error,
|
||||||
) {
|
) {
|
||||||
return &common.ImagesForCve{
|
return &common.ImagesForCve{
|
||||||
|
@ -425,7 +425,7 @@ func TestSearchFixedTagsGQL(t *testing.T) {
|
||||||
Convey("SearchFixedTagsGQL", t, func() {
|
Convey("SearchFixedTagsGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getFixedTagsForCVEGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getFixedTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName, cveID string) (*common.ImageListWithCVEFixedResponse, error,
|
imageName, cveID string) (*common.ImageListWithCVEFixedResponse, error,
|
||||||
) {
|
) {
|
||||||
return &common.ImageListWithCVEFixedResponse{
|
return &common.ImageListWithCVEFixedResponse{
|
||||||
|
@ -449,7 +449,7 @@ func TestSearchFixedTagsGQL(t *testing.T) {
|
||||||
Convey("SearchFixedTagsGQL error", t, func() {
|
Convey("SearchFixedTagsGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getFixedTagsForCVEGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getFixedTagsForCVEGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName, cveID string) (*common.ImageListWithCVEFixedResponse, error,
|
imageName, cveID string) (*common.ImageListWithCVEFixedResponse, error,
|
||||||
) {
|
) {
|
||||||
return &common.ImageListWithCVEFixedResponse{
|
return &common.ImageListWithCVEFixedResponse{
|
||||||
|
@ -469,7 +469,7 @@ func TestSearchReferrersGQL(t *testing.T) {
|
||||||
Convey("SearchReferrersGQL", t, func() {
|
Convey("SearchReferrersGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getReferrersGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getReferrersGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
repo, digest string) (*common.ReferrersResp, error,
|
repo, digest string) (*common.ReferrersResp, error,
|
||||||
) {
|
) {
|
||||||
return &common.ReferrersResp{
|
return &common.ReferrersResp{
|
||||||
|
@ -497,7 +497,7 @@ func TestSearchReferrersGQL(t *testing.T) {
|
||||||
Convey("SearchReferrersGQL error", t, func() {
|
Convey("SearchReferrersGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getReferrersGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
getReferrersGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
repo, digest string) (*common.ReferrersResp, error,
|
repo, digest string) (*common.ReferrersResp, error,
|
||||||
) {
|
) {
|
||||||
return &common.ReferrersResp{}, zerr.ErrInjected
|
return &common.ReferrersResp{}, zerr.ErrInjected
|
||||||
|
@ -513,7 +513,7 @@ func TestGlobalSearchGQL(t *testing.T) {
|
||||||
Convey("GlobalSearchGQL", t, func() {
|
Convey("GlobalSearchGQL", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
globalSearchGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
globalSearchGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
query string) (*common.GlobalSearch, error,
|
query string) (*common.GlobalSearch, error,
|
||||||
) {
|
) {
|
||||||
return &common.GlobalSearch{
|
return &common.GlobalSearch{
|
||||||
|
@ -538,7 +538,7 @@ func TestGlobalSearchGQL(t *testing.T) {
|
||||||
Convey("GlobalSearchGQL error", t, func() {
|
Convey("GlobalSearchGQL error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
globalSearchGQLFn: func(ctx context.Context, config searchConfig, username, password,
|
globalSearchGQLFn: func(ctx context.Context, config SearchConfig, username, password,
|
||||||
query string) (*common.GlobalSearch, error,
|
query string) (*common.GlobalSearch, error,
|
||||||
) {
|
) {
|
||||||
return &common.GlobalSearch{}, zerr.ErrInjected
|
return &common.GlobalSearch{}, zerr.ErrInjected
|
||||||
|
@ -554,7 +554,7 @@ func TestSearchReferrers(t *testing.T) {
|
||||||
Convey("SearchReferrers", t, func() {
|
Convey("SearchReferrers", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getReferrersFn: func(ctx context.Context, config searchConfig, username string, password string,
|
getReferrersFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
||||||
repo string, digest string) (referrersResult, error,
|
repo string, digest string) (referrersResult, error,
|
||||||
) {
|
) {
|
||||||
return referrersResult([]common.Referrer{
|
return referrersResult([]common.Referrer{
|
||||||
|
@ -580,7 +580,7 @@ func TestSearchReferrers(t *testing.T) {
|
||||||
Convey("SearchReferrers error", t, func() {
|
Convey("SearchReferrers error", t, func() {
|
||||||
buff := bytes.NewBufferString("")
|
buff := bytes.NewBufferString("")
|
||||||
searchConfig := getMockSearchConfig(buff, mockService{
|
searchConfig := getMockSearchConfig(buff, mockService{
|
||||||
getReferrersFn: func(ctx context.Context, config searchConfig, username string, password string,
|
getReferrersFn: func(ctx context.Context, config SearchConfig, username string, password string,
|
||||||
repo string, digest string) (referrersResult, error,
|
repo string, digest string) (referrersResult, error,
|
||||||
) {
|
) {
|
||||||
return referrersResult{}, zerr.ErrInjected
|
return referrersResult{}, zerr.ErrInjected
|
||||||
|
@ -607,17 +607,17 @@ func TestSearchRepos(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMockSearchConfig(buff *bytes.Buffer, mockService mockService) searchConfig {
|
func getMockSearchConfig(buff *bytes.Buffer, mockService mockService) SearchConfig {
|
||||||
return searchConfig{
|
return SearchConfig{
|
||||||
resultWriter: buff,
|
ResultWriter: buff,
|
||||||
user: "",
|
User: "",
|
||||||
searchService: mockService,
|
SearchService: mockService,
|
||||||
servURL: "http://127.0.0.1:8000",
|
ServURL: "http://127.0.0.1:8000",
|
||||||
outputFormat: "",
|
OutputFormat: "",
|
||||||
verifyTLS: false,
|
VerifyTLS: false,
|
||||||
fixedFlag: false,
|
FixedFlag: false,
|
||||||
verbose: false,
|
Verbose: false,
|
||||||
debug: false,
|
Debug: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,19 +744,19 @@ func TestUtils(t *testing.T) {
|
||||||
|
|
||||||
Convey("CheckExtEndPointQuery", t, func() {
|
Convey("CheckExtEndPointQuery", t, func() {
|
||||||
// invalid url
|
// invalid url
|
||||||
err := CheckExtEndPointQuery(searchConfig{
|
err := CheckExtEndPointQuery(SearchConfig{
|
||||||
user: "",
|
User: "",
|
||||||
servURL: "bad-url",
|
ServURL: "bad-url",
|
||||||
})
|
})
|
||||||
So(err, ShouldNotBeNil)
|
So(err, ShouldNotBeNil)
|
||||||
|
|
||||||
// good url but no connection
|
// good url but no connection
|
||||||
err = CheckExtEndPointQuery(searchConfig{
|
err = CheckExtEndPointQuery(SearchConfig{
|
||||||
user: "",
|
User: "",
|
||||||
servURL: "http://127.0.0.1:5000",
|
ServURL: "http://127.0.0.1:5000",
|
||||||
verifyTLS: false,
|
VerifyTLS: false,
|
||||||
debug: false,
|
Debug: false,
|
||||||
resultWriter: io.Discard,
|
ResultWriter: io.Discard,
|
||||||
})
|
})
|
||||||
So(err, ShouldNotBeNil)
|
So(err, ShouldNotBeNil)
|
||||||
})
|
})
|
||||||
|
|
|
@ -32,49 +32,49 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type SearchService interface { //nolint:interfacebloat
|
type SearchService interface { //nolint:interfacebloat
|
||||||
getImagesGQL(ctx context.Context, config searchConfig, username, password string,
|
getImagesGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
imageName string) (*common.ImageListResponse, error)
|
imageName string) (*common.ImageListResponse, error)
|
||||||
getImagesForDigestGQL(ctx context.Context, config searchConfig, username, password string,
|
getImagesForDigestGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
digest string) (*common.ImagesForDigest, error)
|
digest string) (*common.ImagesForDigest, error)
|
||||||
getCveByImageGQL(ctx context.Context, config searchConfig, username, password,
|
getCveByImageGQL(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName string, searchedCVE string) (*cveResult, error)
|
imageName string, searchedCVE string) (*cveResult, error)
|
||||||
getTagsForCVEGQL(ctx context.Context, config searchConfig, username, password, repo,
|
getTagsForCVEGQL(ctx context.Context, config SearchConfig, username, password, repo,
|
||||||
cveID string) (*common.ImagesForCve, error)
|
cveID string) (*common.ImagesForCve, error)
|
||||||
getFixedTagsForCVEGQL(ctx context.Context, config searchConfig, username, password, imageName,
|
getFixedTagsForCVEGQL(ctx context.Context, config SearchConfig, username, password, imageName,
|
||||||
cveID string) (*common.ImageListWithCVEFixedResponse, error)
|
cveID string) (*common.ImageListWithCVEFixedResponse, error)
|
||||||
getDerivedImageListGQL(ctx context.Context, config searchConfig, username, password string,
|
getDerivedImageListGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
derivedImage string) (*common.DerivedImageListResponse, error)
|
derivedImage string) (*common.DerivedImageListResponse, error)
|
||||||
getBaseImageListGQL(ctx context.Context, config searchConfig, username, password string,
|
getBaseImageListGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
baseImage string) (*common.BaseImageListResponse, error)
|
baseImage string) (*common.BaseImageListResponse, error)
|
||||||
getReferrersGQL(ctx context.Context, config searchConfig, username, password string,
|
getReferrersGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
repo, digest string) (*common.ReferrersResp, error)
|
repo, digest string) (*common.ReferrersResp, error)
|
||||||
globalSearchGQL(ctx context.Context, config searchConfig, username, password string,
|
globalSearchGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
query string) (*common.GlobalSearch, error)
|
query string) (*common.GlobalSearch, error)
|
||||||
|
|
||||||
getAllImages(ctx context.Context, config searchConfig, username, password string,
|
getAllImages(ctx context.Context, config SearchConfig, username, password string,
|
||||||
channel chan stringResult, wtgrp *sync.WaitGroup)
|
channel chan stringResult, wtgrp *sync.WaitGroup)
|
||||||
getImagesByDigest(ctx context.Context, config searchConfig, username, password, digest string,
|
getImagesByDigest(ctx context.Context, config SearchConfig, username, password, digest string,
|
||||||
channel chan stringResult, wtgrp *sync.WaitGroup)
|
channel chan stringResult, wtgrp *sync.WaitGroup)
|
||||||
getRepos(ctx context.Context, config searchConfig, username, password string,
|
getRepos(ctx context.Context, config SearchConfig, username, password string,
|
||||||
channel chan stringResult, wtgrp *sync.WaitGroup)
|
channel chan stringResult, wtgrp *sync.WaitGroup)
|
||||||
getImageByName(ctx context.Context, config searchConfig, username, password, imageName string,
|
getImageByName(ctx context.Context, config SearchConfig, username, password, imageName string,
|
||||||
channel chan stringResult, wtgrp *sync.WaitGroup)
|
channel chan stringResult, wtgrp *sync.WaitGroup)
|
||||||
getReferrers(ctx context.Context, config searchConfig, username, password string, repo, digest string,
|
getReferrers(ctx context.Context, config SearchConfig, username, password string, repo, digest string,
|
||||||
) (referrersResult, error)
|
) (referrersResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type searchConfig struct {
|
type SearchConfig struct {
|
||||||
searchService SearchService
|
SearchService SearchService
|
||||||
servURL string
|
ServURL string
|
||||||
user string
|
User string
|
||||||
outputFormat string
|
OutputFormat string
|
||||||
sortBy string
|
SortBy string
|
||||||
verifyTLS bool
|
VerifyTLS bool
|
||||||
fixedFlag bool
|
FixedFlag bool
|
||||||
verbose bool
|
Verbose bool
|
||||||
debug bool
|
Debug bool
|
||||||
resultWriter io.Writer
|
ResultWriter io.Writer
|
||||||
spinner spinnerState
|
Spinner spinnerState
|
||||||
}
|
}
|
||||||
|
|
||||||
type searchService struct{}
|
type searchService struct{}
|
||||||
|
@ -83,7 +83,7 @@ func NewSearchService() SearchService {
|
||||||
return searchService{}
|
return searchService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getDerivedImageListGQL(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) getDerivedImageListGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
derivedImage string,
|
derivedImage string,
|
||||||
) (*common.DerivedImageListResponse, error) {
|
) (*common.DerivedImageListResponse, error) {
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
|
@ -107,7 +107,7 @@ func (service searchService) getDerivedImageListGQL(ctx context.Context, config
|
||||||
IsSigned
|
IsSigned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`, derivedImage, Flag2SortCriteria(config.sortBy))
|
}`, derivedImage, Flag2SortCriteria(config.SortBy))
|
||||||
|
|
||||||
result := &common.DerivedImageListResponse{}
|
result := &common.DerivedImageListResponse{}
|
||||||
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
||||||
|
@ -119,7 +119,7 @@ func (service searchService) getDerivedImageListGQL(ctx context.Context, config
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getReferrersGQL(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) getReferrersGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
repo, digest string,
|
repo, digest string,
|
||||||
) (*common.ReferrersResp, error) {
|
) (*common.ReferrersResp, error) {
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
|
@ -146,7 +146,7 @@ func (service searchService) getReferrersGQL(ctx context.Context, config searchC
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) globalSearchGQL(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) globalSearchGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
query string,
|
query string,
|
||||||
) (*common.GlobalSearch, error) {
|
) (*common.GlobalSearch, error) {
|
||||||
GQLQuery := fmt.Sprintf(`
|
GQLQuery := fmt.Sprintf(`
|
||||||
|
@ -179,7 +179,7 @@ func (service searchService) globalSearchGQL(ctx context.Context, config searchC
|
||||||
StarCount
|
StarCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`, query, Flag2SortCriteria(config.sortBy))
|
}`, query, Flag2SortCriteria(config.SortBy))
|
||||||
|
|
||||||
result := &common.GlobalSearchResultResp{}
|
result := &common.GlobalSearchResultResp{}
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ func (service searchService) globalSearchGQL(ctx context.Context, config searchC
|
||||||
return &result.GlobalSearch, nil
|
return &result.GlobalSearch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getBaseImageListGQL(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) getBaseImageListGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
baseImage string,
|
baseImage string,
|
||||||
) (*common.BaseImageListResponse, error) {
|
) (*common.BaseImageListResponse, error) {
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
|
@ -215,7 +215,7 @@ func (service searchService) getBaseImageListGQL(ctx context.Context, config sea
|
||||||
IsSigned
|
IsSigned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`, baseImage, Flag2SortCriteria(config.sortBy))
|
}`, baseImage, Flag2SortCriteria(config.SortBy))
|
||||||
|
|
||||||
result := &common.BaseImageListResponse{}
|
result := &common.BaseImageListResponse{}
|
||||||
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
||||||
|
@ -227,7 +227,7 @@ func (service searchService) getBaseImageListGQL(ctx context.Context, config sea
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getImagesGQL(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) getImagesGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
imageName string,
|
imageName string,
|
||||||
) (*common.ImageListResponse, error) {
|
) (*common.ImageListResponse, error) {
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
|
@ -251,7 +251,7 @@ func (service searchService) getImagesGQL(ctx context.Context, config searchConf
|
||||||
IsSigned
|
IsSigned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`, imageName, Flag2SortCriteria(config.sortBy))
|
}`, imageName, Flag2SortCriteria(config.SortBy))
|
||||||
result := &common.ImageListResponse{}
|
result := &common.ImageListResponse{}
|
||||||
|
|
||||||
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
||||||
|
@ -263,7 +263,7 @@ func (service searchService) getImagesGQL(ctx context.Context, config searchConf
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getImagesForDigestGQL(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) getImagesForDigestGQL(ctx context.Context, config SearchConfig, username, password string,
|
||||||
digest string,
|
digest string,
|
||||||
) (*common.ImagesForDigest, error) {
|
) (*common.ImagesForDigest, error) {
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
|
@ -287,7 +287,7 @@ func (service searchService) getImagesForDigestGQL(ctx context.Context, config s
|
||||||
IsSigned
|
IsSigned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`, digest, Flag2SortCriteria(config.sortBy))
|
}`, digest, Flag2SortCriteria(config.SortBy))
|
||||||
result := &common.ImagesForDigest{}
|
result := &common.ImagesForDigest{}
|
||||||
|
|
||||||
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
||||||
|
@ -299,7 +299,7 @@ func (service searchService) getImagesForDigestGQL(ctx context.Context, config s
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getCveByImageGQL(ctx context.Context, config searchConfig, username, password,
|
func (service searchService) getCveByImageGQL(ctx context.Context, config SearchConfig, username, password,
|
||||||
imageName, searchedCVE string,
|
imageName, searchedCVE string,
|
||||||
) (*cveResult, error) {
|
) (*cveResult, error) {
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
|
@ -310,7 +310,7 @@ func (service searchService) getCveByImageGQL(ctx context.Context, config search
|
||||||
PackageList {Name InstalledVersion FixedVersion}
|
PackageList {Name InstalledVersion FixedVersion}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`, imageName, searchedCVE, Flag2SortCriteria(config.sortBy))
|
}`, imageName, searchedCVE, Flag2SortCriteria(config.SortBy))
|
||||||
result := &cveResult{}
|
result := &cveResult{}
|
||||||
|
|
||||||
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
||||||
|
@ -322,7 +322,7 @@ func (service searchService) getCveByImageGQL(ctx context.Context, config search
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getTagsForCVEGQL(ctx context.Context, config searchConfig,
|
func (service searchService) getTagsForCVEGQL(ctx context.Context, config SearchConfig,
|
||||||
username, password, repo, cveID string,
|
username, password, repo, cveID string,
|
||||||
) (*common.ImagesForCve, error) {
|
) (*common.ImagesForCve, error) {
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
|
@ -347,7 +347,7 @@ func (service searchService) getTagsForCVEGQL(ctx context.Context, config search
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
cveID, Flag2SortCriteria(config.sortBy))
|
cveID, Flag2SortCriteria(config.SortBy))
|
||||||
result := &common.ImagesForCve{}
|
result := &common.ImagesForCve{}
|
||||||
|
|
||||||
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
|
||||||
|
@ -371,7 +371,7 @@ func (service searchService) getTagsForCVEGQL(ctx context.Context, config search
|
||||||
return filteredResults, nil
|
return filteredResults, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config searchConfig,
|
func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config SearchConfig,
|
||||||
username, password, imageName, cveID string,
|
username, password, imageName, cveID string,
|
||||||
) (*common.ImageListWithCVEFixedResponse, error) {
|
) (*common.ImageListWithCVEFixedResponse, error) {
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
|
@ -409,10 +409,10 @@ func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config s
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getReferrers(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) getReferrers(ctx context.Context, config SearchConfig, username, password string,
|
||||||
repo, digest string,
|
repo, digest string,
|
||||||
) (referrersResult, error) {
|
) (referrersResult, error) {
|
||||||
referrersEndpoint, err := combineServerAndEndpointURL(config.servURL,
|
referrersEndpoint, err := combineServerAndEndpointURL(config.ServURL,
|
||||||
fmt.Sprintf("/v2/%s/referrers/%s", repo, digest))
|
fmt.Sprintf("/v2/%s/referrers/%s", repo, digest))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
|
@ -423,8 +423,8 @@ func (service searchService) getReferrers(ctx context.Context, config searchConf
|
||||||
}
|
}
|
||||||
|
|
||||||
referrerResp := &ispec.Index{}
|
referrerResp := &ispec.Index{}
|
||||||
_, err = makeGETRequest(ctx, referrersEndpoint, username, password, config.verifyTLS,
|
_, err = makeGETRequest(ctx, referrersEndpoint, username, password, config.VerifyTLS,
|
||||||
config.debug, &referrerResp, config.resultWriter)
|
config.Debug, &referrerResp, config.ResultWriter)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
|
@ -447,7 +447,7 @@ func (service searchService) getReferrers(ctx context.Context, config searchConf
|
||||||
return referrersList, nil
|
return referrersList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getImageByName(ctx context.Context, config searchConfig,
|
func (service searchService) getImageByName(ctx context.Context, config SearchConfig,
|
||||||
username, password, imageName string, rch chan stringResult, wtgrp *sync.WaitGroup,
|
username, password, imageName string, rch chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
defer wtgrp.Done()
|
defer wtgrp.Done()
|
||||||
|
@ -466,7 +466,7 @@ func (service searchService) getImageByName(ctx context.Context, config searchCo
|
||||||
localWg.Wait()
|
localWg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getAllImages(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) getAllImages(ctx context.Context, config SearchConfig, username, password string,
|
||||||
rch chan stringResult, wtgrp *sync.WaitGroup,
|
rch chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
defer wtgrp.Done()
|
defer wtgrp.Done()
|
||||||
|
@ -474,7 +474,7 @@ func (service searchService) getAllImages(ctx context.Context, config searchConf
|
||||||
|
|
||||||
catalog := &catalogResponse{}
|
catalog := &catalogResponse{}
|
||||||
|
|
||||||
catalogEndPoint, err := combineServerAndEndpointURL(config.servURL, fmt.Sprintf("%s%s",
|
catalogEndPoint, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("%s%s",
|
||||||
constants.RoutePrefix, constants.ExtCatalogPrefix))
|
constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
|
@ -485,8 +485,8 @@ func (service searchService) getAllImages(ctx context.Context, config searchConf
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = makeGETRequest(ctx, catalogEndPoint, username, password, config.verifyTLS,
|
_, err = makeGETRequest(ctx, catalogEndPoint, username, password, config.VerifyTLS,
|
||||||
config.debug, catalog, config.resultWriter)
|
config.Debug, catalog, config.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return
|
return
|
||||||
|
@ -513,14 +513,14 @@ func (service searchService) getAllImages(ctx context.Context, config searchConf
|
||||||
localWg.Wait()
|
localWg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getImage(ctx context.Context, config searchConfig, username, password, imageName string,
|
func getImage(ctx context.Context, config SearchConfig, username, password, imageName string,
|
||||||
rch chan stringResult, wtgrp *sync.WaitGroup, pool *requestsPool,
|
rch chan stringResult, wtgrp *sync.WaitGroup, pool *requestsPool,
|
||||||
) {
|
) {
|
||||||
defer wtgrp.Done()
|
defer wtgrp.Done()
|
||||||
|
|
||||||
repo, imageTag := common.GetImageDirAndTag(imageName)
|
repo, imageTag := common.GetImageDirAndTag(imageName)
|
||||||
|
|
||||||
tagListEndpoint, err := combineServerAndEndpointURL(config.servURL, fmt.Sprintf("/v2/%s/tags/list", repo))
|
tagListEndpoint, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("/v2/%s/tags/list", repo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return
|
return
|
||||||
|
@ -531,8 +531,8 @@ func getImage(ctx context.Context, config searchConfig, username, password, imag
|
||||||
}
|
}
|
||||||
|
|
||||||
tagList := &tagListResp{}
|
tagList := &tagListResp{}
|
||||||
_, err = makeGETRequest(ctx, tagListEndpoint, username, password, config.verifyTLS,
|
_, err = makeGETRequest(ctx, tagListEndpoint, username, password, config.VerifyTLS,
|
||||||
config.debug, &tagList, config.resultWriter)
|
config.Debug, &tagList, config.ResultWriter)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
|
@ -567,7 +567,7 @@ func getImage(ctx context.Context, config searchConfig, username, password, imag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getImagesByDigest(ctx context.Context, config searchConfig, username,
|
func (service searchService) getImagesByDigest(ctx context.Context, config SearchConfig, username,
|
||||||
password string, digest string, rch chan stringResult, wtgrp *sync.WaitGroup,
|
password string, digest string, rch chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
defer wtgrp.Done()
|
defer wtgrp.Done()
|
||||||
|
@ -652,16 +652,16 @@ func isContextDone(ctx context.Context) bool {
|
||||||
// Query using GQL, the query string is passed as a parameter
|
// Query using GQL, the query string is passed as a parameter
|
||||||
// errors are returned in the stringResult channel, the unmarshalled payload is in resultPtr.
|
// errors are returned in the stringResult channel, the unmarshalled payload is in resultPtr.
|
||||||
func (service searchService) makeGraphQLQuery(ctx context.Context,
|
func (service searchService) makeGraphQLQuery(ctx context.Context,
|
||||||
config searchConfig, username, password, query string,
|
config SearchConfig, username, password, query string,
|
||||||
resultPtr interface{},
|
resultPtr interface{},
|
||||||
) error {
|
) error {
|
||||||
endPoint, err := combineServerAndEndpointURL(config.servURL, constants.FullSearchPrefix)
|
endPoint, err := combineServerAndEndpointURL(config.ServURL, constants.FullSearchPrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = makeGraphQLRequest(ctx, endPoint, query, username, password, config.verifyTLS,
|
err = makeGraphQLRequest(ctx, endPoint, query, username, password, config.VerifyTLS,
|
||||||
config.debug, resultPtr, config.resultWriter)
|
config.Debug, resultPtr, config.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -697,12 +697,12 @@ func checkResultGraphQLQuery(ctx context.Context, err error, resultErrors []comm
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addManifestCallToPool(ctx context.Context, config searchConfig, pool *requestsPool,
|
func addManifestCallToPool(ctx context.Context, config SearchConfig, pool *requestsPool,
|
||||||
username, password, imageName, tagName string, rch chan stringResult, wtgrp *sync.WaitGroup,
|
username, password, imageName, tagName string, rch chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
defer wtgrp.Done()
|
defer wtgrp.Done()
|
||||||
|
|
||||||
manifestEndpoint, err := combineServerAndEndpointURL(config.servURL,
|
manifestEndpoint, err := combineServerAndEndpointURL(config.ServURL,
|
||||||
fmt.Sprintf("/v2/%s/manifests/%s", imageName, tagName))
|
fmt.Sprintf("/v2/%s/manifests/%s", imageName, tagName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
|
@ -1304,7 +1304,7 @@ func getRepoTableWriter(writer io.Writer) *tablewriter.Table {
|
||||||
return table
|
return table
|
||||||
}
|
}
|
||||||
|
|
||||||
func (service searchService) getRepos(ctx context.Context, config searchConfig, username, password string,
|
func (service searchService) getRepos(ctx context.Context, config SearchConfig, username, password string,
|
||||||
rch chan stringResult, wtgrp *sync.WaitGroup,
|
rch chan stringResult, wtgrp *sync.WaitGroup,
|
||||||
) {
|
) {
|
||||||
defer wtgrp.Done()
|
defer wtgrp.Done()
|
||||||
|
@ -1312,7 +1312,7 @@ func (service searchService) getRepos(ctx context.Context, config searchConfig,
|
||||||
|
|
||||||
catalog := &catalogResponse{}
|
catalog := &catalogResponse{}
|
||||||
|
|
||||||
catalogEndPoint, err := combineServerAndEndpointURL(config.servURL, fmt.Sprintf("%s%s",
|
catalogEndPoint, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("%s%s",
|
||||||
constants.RoutePrefix, constants.ExtCatalogPrefix))
|
constants.RoutePrefix, constants.ExtCatalogPrefix))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
|
@ -1323,8 +1323,8 @@ func (service searchService) getRepos(ctx context.Context, config searchConfig,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = makeGETRequest(ctx, catalogEndPoint, username, password, config.verifyTLS,
|
_, err = makeGETRequest(ctx, catalogEndPoint, username, password, config.VerifyTLS,
|
||||||
config.debug, catalog, config.resultWriter)
|
config.Debug, catalog, config.ResultWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isContextDone(ctx) {
|
if isContextDone(ctx) {
|
||||||
return
|
return
|
||||||
|
@ -1334,15 +1334,15 @@ func (service searchService) getRepos(ctx context.Context, config searchConfig,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(config.resultWriter, "\nREPOSITORY NAME")
|
fmt.Fprintln(config.ResultWriter, "\nREPOSITORY NAME")
|
||||||
|
|
||||||
if config.sortBy == SortByAlphabeticAsc {
|
if config.SortBy == SortByAlphabeticAsc {
|
||||||
for i := 0; i < len(catalog.Repositories); i++ {
|
for i := 0; i < len(catalog.Repositories); i++ {
|
||||||
fmt.Fprintln(config.resultWriter, catalog.Repositories[i])
|
fmt.Fprintln(config.ResultWriter, catalog.Repositories[i])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := len(catalog.Repositories) - 1; i >= 0; i-- {
|
for i := len(catalog.Repositories) - 1; i >= 0; i-- {
|
||||||
fmt.Fprintln(config.resultWriter, catalog.Repositories[i])
|
fmt.Fprintln(config.ResultWriter, catalog.Repositories[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,31 +30,31 @@ func ref[T any](input T) *T {
|
||||||
return &ref
|
return &ref
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchImageDigest(repo, ref, username, password string, config searchConfig) (string, error) {
|
func fetchImageDigest(repo, ref, username, password string, config SearchConfig) (string, error) {
|
||||||
url, err := combineServerAndEndpointURL(config.servURL, fmt.Sprintf("/v2/%s/manifests/%s", repo, ref))
|
url, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("/v2/%s/manifests/%s", repo, ref))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := makeHEADRequest(context.Background(), url, username, password, config.verifyTLS, false)
|
res, err := makeHEADRequest(context.Background(), url, username, password, config.VerifyTLS, false)
|
||||||
|
|
||||||
digestStr := res.Get(constants.DistContentDigestKey)
|
digestStr := res.Get(constants.DistContentDigestKey)
|
||||||
|
|
||||||
return digestStr, err
|
return digestStr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectResults(config searchConfig, wg *sync.WaitGroup, imageErr chan stringResult,
|
func collectResults(config SearchConfig, wg *sync.WaitGroup, imageErr chan stringResult,
|
||||||
cancel context.CancelFunc, printHeader printHeader, errCh chan error,
|
cancel context.CancelFunc, printHeader printHeader, errCh chan error,
|
||||||
) {
|
) {
|
||||||
var foundResult bool
|
var foundResult bool
|
||||||
|
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
config.spinner.startSpinner()
|
config.Spinner.startSpinner()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case result, ok := <-imageErr:
|
case result, ok := <-imageErr:
|
||||||
config.spinner.stopSpinner()
|
config.Spinner.stopSpinner()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
cancel()
|
cancel()
|
||||||
|
@ -69,18 +69,18 @@ func collectResults(config searchConfig, wg *sync.WaitGroup, imageErr chan strin
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !foundResult && (config.outputFormat == defaultOutputFormat || config.outputFormat == "") {
|
if !foundResult && (config.OutputFormat == defaultOutputFormat || config.OutputFormat == "") {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|
||||||
printHeader(&builder, config.verbose, 0, 0, 0)
|
printHeader(&builder, config.Verbose, 0, 0, 0)
|
||||||
fmt.Fprint(config.resultWriter, builder.String())
|
fmt.Fprint(config.ResultWriter, builder.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
foundResult = true
|
foundResult = true
|
||||||
|
|
||||||
fmt.Fprint(config.resultWriter, result.StrValue)
|
fmt.Fprint(config.ResultWriter, result.StrValue)
|
||||||
case <-time.After(waitTimeout):
|
case <-time.After(waitTimeout):
|
||||||
config.spinner.stopSpinner()
|
config.Spinner.stopSpinner()
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
errCh <- zerr.ErrCLITimeout
|
errCh <- zerr.ErrCLITimeout
|
||||||
|
@ -193,8 +193,8 @@ func printCVETableHeader(writer io.Writer) {
|
||||||
table.Render()
|
table.Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
func printReferrersTableHeader(config searchConfig, writer io.Writer, maxArtifactTypeLen int) {
|
func printReferrersTableHeader(config SearchConfig, writer io.Writer, maxArtifactTypeLen int) {
|
||||||
if config.outputFormat != "" && config.outputFormat != defaultOutputFormat {
|
if config.OutputFormat != "" && config.OutputFormat != defaultOutputFormat {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,18 +269,18 @@ func printRepoTableHeader(writer io.Writer, repoMaxLen, maxTimeLen int, verbose
|
||||||
table.Render()
|
table.Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
func printReferrersResult(config searchConfig, referrersList referrersResult, maxArtifactTypeLen int) error {
|
func printReferrersResult(config SearchConfig, referrersList referrersResult, maxArtifactTypeLen int) error {
|
||||||
out, err := referrersList.string(config.outputFormat, maxArtifactTypeLen)
|
out, err := referrersList.string(config.OutputFormat, maxArtifactTypeLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprint(config.resultWriter, out)
|
fmt.Fprint(config.ResultWriter, out)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func printImageResult(config searchConfig, imageList []imageStruct) error {
|
func printImageResult(config SearchConfig, imageList []imageStruct) error {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
maxImgNameLen := 0
|
maxImgNameLen := 0
|
||||||
maxTagLen := 0
|
maxTagLen := 0
|
||||||
|
@ -305,29 +305,29 @@ func printImageResult(config searchConfig, imageList []imageStruct) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.outputFormat == defaultOutputFormat || config.outputFormat == "" {
|
if config.OutputFormat == defaultOutputFormat || config.OutputFormat == "" {
|
||||||
printImageTableHeader(&builder, config.verbose, maxImgNameLen, maxTagLen, maxPlatformLen)
|
printImageTableHeader(&builder, config.Verbose, maxImgNameLen, maxTagLen, maxPlatformLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprint(config.resultWriter, builder.String())
|
fmt.Fprint(config.ResultWriter, builder.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range imageList {
|
for i := range imageList {
|
||||||
img := imageList[i]
|
img := imageList[i]
|
||||||
verbose := config.verbose
|
verbose := config.Verbose
|
||||||
|
|
||||||
out, err := img.string(config.outputFormat, maxImgNameLen, maxTagLen, maxPlatformLen, verbose)
|
out, err := img.string(config.OutputFormat, maxImgNameLen, maxTagLen, maxPlatformLen, verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprint(config.resultWriter, out)
|
fmt.Fprint(config.ResultWriter, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func printRepoResults(config searchConfig, repoList []repoStruct) error {
|
func printRepoResults(config SearchConfig, repoList []repoStruct) error {
|
||||||
maxRepoNameLen := 0
|
maxRepoNameLen := 0
|
||||||
maxTimeLen := 0
|
maxTimeLen := 0
|
||||||
|
|
||||||
|
@ -341,31 +341,31 @@ func printRepoResults(config searchConfig, repoList []repoStruct) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(repoList) > 0 && (config.outputFormat == defaultOutputFormat || config.outputFormat == "") {
|
if len(repoList) > 0 && (config.OutputFormat == defaultOutputFormat || config.OutputFormat == "") {
|
||||||
printRepoTableHeader(config.resultWriter, maxRepoNameLen, maxTimeLen, config.verbose)
|
printRepoTableHeader(config.ResultWriter, maxRepoNameLen, maxTimeLen, config.Verbose)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, repo := range repoList {
|
for _, repo := range repoList {
|
||||||
out, err := repo.string(config.outputFormat, maxRepoNameLen, maxTimeLen, config.verbose)
|
out, err := repo.string(config.OutputFormat, maxRepoNameLen, maxTimeLen, config.Verbose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprint(config.resultWriter, out)
|
fmt.Fprint(config.ResultWriter, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSearchConfigFromFlags(cmd *cobra.Command, searchService SearchService) (searchConfig, error) {
|
func GetSearchConfigFromFlags(cmd *cobra.Command, searchService SearchService) (SearchConfig, error) {
|
||||||
serverURL, err := GetServerURLFromFlags(cmd)
|
serverURL, err := GetServerURLFromFlags(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return searchConfig{}, err
|
return SearchConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
isSpinner, verifyTLS, err := GetCliConfigOptions(cmd)
|
isSpinner, verifyTLS, err := GetCliConfigOptions(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return searchConfig{}, err
|
return SearchConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
|
@ -379,18 +379,18 @@ func GetSearchConfigFromFlags(cmd *cobra.Command, searchService SearchService) (
|
||||||
spin := spinner.New(spinner.CharSets[39], spinnerDuration, spinner.WithWriter(cmd.ErrOrStderr()))
|
spin := spinner.New(spinner.CharSets[39], spinnerDuration, spinner.WithWriter(cmd.ErrOrStderr()))
|
||||||
spin.Prefix = prefix
|
spin.Prefix = prefix
|
||||||
|
|
||||||
return searchConfig{
|
return SearchConfig{
|
||||||
searchService: searchService,
|
SearchService: searchService,
|
||||||
servURL: serverURL,
|
ServURL: serverURL,
|
||||||
user: user,
|
User: user,
|
||||||
outputFormat: outputFormat,
|
OutputFormat: outputFormat,
|
||||||
verifyTLS: verifyTLS,
|
VerifyTLS: verifyTLS,
|
||||||
fixedFlag: fixed,
|
FixedFlag: fixed,
|
||||||
verbose: verbose,
|
Verbose: verbose,
|
||||||
debug: debug,
|
Debug: debug,
|
||||||
sortBy: sortBy,
|
SortBy: sortBy,
|
||||||
spinner: spinnerState{spin, isSpinner},
|
Spinner: spinnerState{spin, isSpinner},
|
||||||
resultWriter: cmd.OutOrStdout(),
|
ResultWriter: cmd.OutOrStdout(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,19 +20,19 @@ import (
|
||||||
test "zotregistry.io/zot/pkg/test/common"
|
test "zotregistry.io/zot/pkg/test/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getDefaultSearchConf(baseURL string) searchConfig {
|
func getDefaultSearchConf(baseURL string) SearchConfig {
|
||||||
verifyTLS := false
|
verifyTLS := false
|
||||||
debug := false
|
debug := false
|
||||||
verbose := true
|
verbose := true
|
||||||
outputFormat := "text"
|
outputFormat := "text"
|
||||||
|
|
||||||
return searchConfig{
|
return SearchConfig{
|
||||||
servURL: baseURL,
|
ServURL: baseURL,
|
||||||
resultWriter: io.Discard,
|
ResultWriter: io.Discard,
|
||||||
verifyTLS: verifyTLS,
|
VerifyTLS: verifyTLS,
|
||||||
debug: debug,
|
Debug: debug,
|
||||||
verbose: verbose,
|
Verbose: verbose,
|
||||||
outputFormat: outputFormat,
|
OutputFormat: outputFormat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue