0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-16 21:56:37 -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:
Andrei Aaron 2023-10-03 21:15:39 +03:00 committed by GitHub
parent 99e29c0f46
commit ca1c3288cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 3227 additions and 3118 deletions

View file

@ -179,7 +179,7 @@ type httpJob struct {
password string
imageName string
tagName string
config searchConfig
config SearchConfig
}
const rateLimiterBuffer = 5000
@ -218,8 +218,8 @@ func (p *requestsPool) doJob(ctx context.Context, job *httpJob) {
defer p.wtgrp.Done()
// Check manifest media type
header, err := makeHEADRequest(ctx, job.url, job.username, job.password, job.config.verifyTLS,
job.config.debug)
header, err := makeHEADRequest(ctx, job.url, job.username, job.password, job.config.VerifyTLS,
job.config.Debug)
if err != nil {
if isContextDone(ctx) {
return
@ -227,7 +227,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *httpJob) {
p.outputCh <- stringResult{"", err}
}
verbose := job.config.verbose
verbose := job.config.Verbose
switch header.Get("Content-Type") {
case ispec.MediaTypeImageManifest:
@ -242,7 +242,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *httpJob) {
}
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 isContextDone(ctx) {
return
@ -270,7 +270,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *httpJob) {
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 isContextDone(ctx) {
return
@ -294,7 +294,7 @@ func fetchImageIndexStruct(ctx context.Context, job *httpJob) (*imageStruct, err
var indexContent ispec.Index
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 isContextDone(ctx) {
return nil, context.Canceled
@ -376,16 +376,16 @@ func fetchImageManifestStruct(ctx context.Context, job *httpJob) (*imageStruct,
}, nil
}
func fetchManifestStruct(ctx context.Context, repo, manifestReference string, searchConf searchConfig,
func fetchManifestStruct(ctx context.Context, repo, manifestReference string, searchConf SearchConfig,
username, password string,
) (common.ManifestSummary, error) {
manifestResp := ispec.Manifest{}
URL := fmt.Sprintf("%s/v2/%s/manifests/%s",
searchConf.servURL, repo, manifestReference)
searchConf.ServURL, repo, manifestReference)
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 isContextDone(ctx) {
return common.ManifestSummary{}, context.Canceled
@ -465,16 +465,16 @@ func fetchManifestStruct(ctx context.Context, repo, manifestReference string, se
}, nil
}
func fetchConfig(ctx context.Context, repo, configDigest string, searchConf searchConfig,
func fetchConfig(ctx context.Context, repo, configDigest string, searchConf SearchConfig,
username, password string,
) (ispec.Image, error) {
configContent := ispec.Image{}
URL := fmt.Sprintf("%s/v2/%s/blobs/%s",
searchConf.servURL, repo, configDigest)
searchConf.ServURL, repo, configDigest)
_, err := makeGETRequest(ctx, URL, username, password,
searchConf.verifyTLS, searchConf.debug, &configContent, searchConf.resultWriter)
searchConf.VerifyTLS, searchConf.Debug, &configContent, searchConf.ResultWriter)
if err != nil {
if isContextDone(ctx) {
return ispec.Image{}, context.Canceled
@ -486,16 +486,16 @@ func fetchConfig(ctx context.Context, repo, configDigest string, searchConf sear
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,
) bool {
var referrers ispec.Index
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,
searchConf.verifyTLS, searchConf.debug, &referrers, searchConf.resultWriter)
searchConf.VerifyTLS, searchConf.Debug, &referrers, searchConf.ResultWriter)
if err != nil {
return false
}
@ -507,16 +507,16 @@ func isNotationSigned(ctx context.Context, repo, digestStr string, searchConf se
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,
) bool {
var result interface{}
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,
searchConf.debug, &result, searchConf.resultWriter)
_, err := makeGETRequest(ctx, URL, username, password, searchConf.VerifyTLS,
searchConf.Debug, &result, searchConf.ResultWriter)
return err == nil
}

View file

@ -1,7 +1,7 @@
//go:build search
// +build search
package client
package client_test
import (
"bytes"
@ -9,6 +9,7 @@ import (
"crypto/x509"
"fmt"
"os"
"path"
"path/filepath"
"testing"
@ -18,6 +19,7 @@ import (
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/api/constants"
"zotregistry.io/zot/pkg/cli/client"
extConf "zotregistry.io/zot/pkg/extensions/config"
test "zotregistry.io/zot/pkg/test/common"
)
@ -91,7 +93,7 @@ func TestTLSWithAuth(t *testing.T) {
defer os.RemoveAll(destCertsDir)
args := []string{"name", "dummyImageName", "--url", HOST1}
imageCmd := NewImageCommand(new(searchService))
imageCmd := client.NewImageCommand(client.NewSearchService())
imageBuff := bytes.NewBufferString("")
imageCmd.SetOut(imageBuff)
imageCmd.SetErr(imageBuff)
@ -105,7 +107,7 @@ func TestTLSWithAuth(t *testing.T) {
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
defer os.Remove(configPath)
imageCmd = NewImageCommand(new(searchService))
imageCmd = client.NewImageCommand(client.NewSearchService())
imageBuff = bytes.NewBufferString("")
imageCmd.SetOut(imageBuff)
imageCmd.SetErr(imageBuff)
@ -120,7 +122,7 @@ func TestTLSWithAuth(t *testing.T) {
fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
defer os.Remove(configPath)
imageCmd = NewImageCommand(new(searchService))
imageCmd = client.NewImageCommand(client.NewSearchService())
imageBuff = bytes.NewBufferString("")
imageCmd.SetOut(imageBuff)
imageCmd.SetErr(imageBuff)
@ -174,7 +176,7 @@ func TestTLSWithoutAuth(t *testing.T) {
defer os.RemoveAll(destCertsDir)
args := []string{"list", "--config", "imagetest"}
imageCmd := NewImageCommand(new(searchService))
imageCmd := client.NewImageCommand(client.NewSearchService())
imageBuff := bytes.NewBufferString("")
imageCmd.SetOut(imageBuff)
imageCmd.SetErr(imageBuff)
@ -215,7 +217,7 @@ func TestTLSBadCerts(t *testing.T) {
defer os.Remove(configPath)
args := []string{"list", "--config", "imagetest"}
imageCmd := NewImageCommand(new(searchService))
imageCmd := client.NewImageCommand(client.NewSearchService())
imageBuff := bytes.NewBufferString("")
imageCmd.SetOut(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
}

View file

@ -1,7 +1,7 @@
//go:build search
// +build search
package client
package client_test
import (
"bytes"
@ -14,6 +14,7 @@ import (
. "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/cli/client"
)
func TestConfigCmdBasics(t *testing.T) {
@ -21,7 +22,7 @@ func TestConfigCmdBasics(t *testing.T) {
args := []string{"--help"}
configPath := makeConfigFile("showspinner = false")
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -33,7 +34,7 @@ func TestConfigCmdBasics(t *testing.T) {
args[0] = "-h"
configPath := makeConfigFile("showspinner = false")
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -48,7 +49,7 @@ func TestConfigCmdBasics(t *testing.T) {
args := []string{}
configPath := makeConfigFile("showspinner = false")
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -64,7 +65,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"add", "configtest1", "https://test-url.com"}
file := makeConfigFile("")
defer os.Remove(file)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -90,7 +91,7 @@ func TestConfigCmdMain(t *testing.T) {
panic(err)
}
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -118,7 +119,7 @@ func TestConfigCmdMain(t *testing.T) {
panic(err)
}
cmd := NewConfigAddCommand()
cmd := client.NewConfigAddCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -140,7 +141,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"--list"}
configPath := makeConfigFile(`{"configs":{"_name":"configtest","url":"https://test-url.com","showspinner":false}}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -153,7 +154,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"add", "configtest1", "test..com"}
file := makeConfigFile("")
defer os.Remove(file)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -167,7 +168,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"remove", "configtest"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -185,7 +186,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"remove", "configtest"}
configPath := makeConfigFile(`{"configs":[]`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -199,7 +200,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"remove", "configtest"}
configPath := makeConfigFile(`{"asdf":[]`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -213,7 +214,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"remove", "configtest"}
configPath := makeConfigFile(`{"configs":[asdad]`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(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
So(err, ShouldBeNil)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -246,7 +247,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"--list"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -259,7 +260,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"-l"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -273,7 +274,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"-l"}
configPath := makeConfigFile(``)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -288,7 +289,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "--list"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -302,7 +303,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "-l"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -317,7 +318,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "-l"}
configPath := makeConfigFile(``)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -332,7 +333,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "url"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -345,7 +346,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "url"}
configPath := makeConfigFile(``)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -360,7 +361,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "showspinner", "false"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com"}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -381,7 +382,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "showspinner", "false"}
configPath := makeConfigFile(``)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -396,7 +397,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "url", "https://new-url.com"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -419,7 +420,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "showspinner", "--reset"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -441,7 +442,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"configtest", "url", "--reset"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -455,7 +456,7 @@ func TestConfigCmdMain(t *testing.T) {
args := []string{"add", "configtest", "https://test-url.com/new"}
configPath := makeConfigFile(`{"configs":[{"_name":"configtest","url":"https://test-url.com","showspinner":false}]}`)
defer os.Remove(configPath)
cmd := NewConfigCommand()
cmd := client.NewConfigCommand()
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)

View file

@ -6,22 +6,14 @@ package client
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"path"
"regexp"
"strconv"
"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"
@ -29,18 +21,7 @@ import (
"zotregistry.io/zot/pkg/api/config"
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/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) {
@ -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) {
port := test.GetFreePort()
baseURL := test.GetBaseURL(port)
@ -1096,7 +424,7 @@ func TestCVECommandGQL(t *testing.T) {
args := []string{"affected", "CVE-12345", "--config", "cvetest"}
defer os.Remove(configPath)
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,
) {
if count == 0 {
@ -1143,7 +471,7 @@ func TestCVECommandGQL(t *testing.T) {
args := []string{"fixed", "repo", "CVE-2222", "--config", "cvetest"}
defer os.Remove(configPath)
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,
) {
if count == 0 {
@ -1190,7 +518,7 @@ func TestCVECommandGQL(t *testing.T) {
args := []string{"list", "repo:vuln", "--config", "cvetest"}
defer os.Remove(configPath)
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,
) {
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 {
mockService
retryCounter 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,
) (*zcommon.ImagesForCve, error) {
service.retryCounter += 1

View 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
}

View file

@ -90,11 +90,11 @@ func haveSameArgs(query field, reqQuery GQLQuery) bool {
return true
}
func CheckExtEndPointQuery(config searchConfig, requiredQueries ...GQLQuery) error {
username, password := getUsernameAndPassword(config.user)
func CheckExtEndPointQuery(config SearchConfig, requiredQueries ...GQLQuery) error {
username, password := getUsernameAndPassword(config.User)
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))
if err != nil {
return err
@ -102,8 +102,8 @@ func CheckExtEndPointQuery(config searchConfig, requiredQueries ...GQLQuery) err
discoverResponse := &distext.ExtensionList{}
_, err = makeGETRequest(ctx, discoverEndPoint, username, password, config.verifyTLS,
config.debug, &discoverResponse, config.resultWriter)
_, err = makeGETRequest(ctx, discoverEndPoint, username, password, config.VerifyTLS,
config.Debug, &discoverResponse, config.ResultWriter)
if err != nil {
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)
}
searchEndPoint, _ := combineServerAndEndpointURL(config.servURL, constants.FullSearchPrefix)
searchEndPoint, _ := combineServerAndEndpointURL(config.ServURL, constants.FullSearchPrefix)
schemaQuery := `
{
@ -153,8 +153,8 @@ func CheckExtEndPointQuery(config searchConfig, requiredQueries ...GQLQuery) err
queryResponse := &schemaList{}
err = makeGraphQLRequest(ctx, searchEndPoint, schemaQuery, username, password, config.verifyTLS,
config.debug, queryResponse, config.resultWriter)
err = makeGraphQLRequest(ctx, searchEndPoint, schemaQuery, username, password, config.VerifyTLS,
config.Debug, queryResponse, config.ResultWriter)
if err != nil {
return fmt.Errorf("gql query failed: %w", err)
}

View file

@ -1,7 +1,7 @@
//go:build search && needprivileges
// +build search,needprivileges
package client
package client_test
import (
"bytes"
@ -19,6 +19,7 @@ import (
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/api/constants"
"zotregistry.io/zot/pkg/cli/client"
test "zotregistry.io/zot/pkg/test/common"
)
@ -94,7 +95,7 @@ func TestElevatedPrivilegesTLSNewControllerPrivilegedCert(t *testing.T) {
defer os.Remove(configPath)
args := []string{"list", "--config", "imagetest"}
imageCmd := NewImageCommand(new(searchService))
imageCmd := client.NewImageCommand(client.NewSearchService())
imageBuff := bytes.NewBufferString("")
imageCmd.SetOut(imageBuff)
imageCmd.SetErr(imageBuff)

View file

@ -1,7 +1,7 @@
//go:build search
// +build search
package client
package client_test
import (
"io"
@ -11,6 +11,7 @@ import (
"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"
)
@ -36,57 +37,57 @@ func TestGQLQueries(t *testing.T) {
defer cm.StopServer()
searchConfig := searchConfig{
servURL: baseURL,
user: "",
verifyTLS: false,
debug: false,
resultWriter: io.Discard,
searchConfig := client.SearchConfig{
ServURL: baseURL,
User: "",
VerifyTLS: false,
Debug: false,
ResultWriter: io.Discard,
}
Convey("Make sure the current CLI used the right queries in case they change", t, func() {
Convey("ImageList", func() {
err := CheckExtEndPointQuery(searchConfig, ImageListQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.ImageListQuery())
So(err, ShouldBeNil)
})
Convey("ImageListForDigest", func() {
err := CheckExtEndPointQuery(searchConfig, ImageListForDigestQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.ImageListForDigestQuery())
So(err, ShouldBeNil)
})
Convey("BaseImageList", func() {
err := CheckExtEndPointQuery(searchConfig, BaseImageListQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.BaseImageListQuery())
So(err, ShouldBeNil)
})
Convey("DerivedImageList", func() {
err := CheckExtEndPointQuery(searchConfig, DerivedImageListQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.DerivedImageListQuery())
So(err, ShouldBeNil)
})
Convey("CVEListForImage", func() {
err := CheckExtEndPointQuery(searchConfig, CVEListForImageQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.CVEListForImageQuery())
So(err, ShouldBeNil)
})
Convey("ImageListForCVE", func() {
err := CheckExtEndPointQuery(searchConfig, ImageListForCVEQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.ImageListForCVEQuery())
So(err, ShouldBeNil)
})
Convey("ImageListWithCVEFixed", func() {
err := CheckExtEndPointQuery(searchConfig, ImageListWithCVEFixedQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.ImageListWithCVEFixedQuery())
So(err, ShouldBeNil)
})
Convey("Referrers", func() {
err := CheckExtEndPointQuery(searchConfig, ReferrersQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.ReferrersQuery())
So(err, ShouldBeNil)
})
Convey("GlobalSearch", func() {
err := CheckExtEndPointQuery(searchConfig, GlobalSearchQuery())
err := client.CheckExtEndPointQuery(searchConfig, client.GlobalSearchQuery())
So(err, ShouldBeNil)
})
})

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
//go:build search
// +build search
package client
package client_test
import (
"bytes"
@ -15,6 +15,7 @@ import (
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/cli/client"
test "zotregistry.io/zot/pkg/test/common"
. "zotregistry.io/zot/pkg/test/image-utils"
)
@ -43,7 +44,7 @@ func TestReposCommand(t *testing.T) {
defer os.Remove(configPath)
args := []string{"list", "--config", "repostest"}
cmd := NewRepoCommand(mockService{})
cmd := client.NewRepoCommand(client.NewSearchService())
buff := bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -57,7 +58,7 @@ func TestReposCommand(t *testing.T) {
So(actual, ShouldContainSubstring, "repo2")
args = []string{"list", "--sort-by", "alpha-dsc", "--config", "repostest"}
cmd = NewRepoCommand(new(searchService))
cmd = client.NewRepoCommand(client.NewSearchService())
buff = bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -72,7 +73,7 @@ func TestReposCommand(t *testing.T) {
So(strings.Index(actual, "repo2"), ShouldBeLessThan, strings.Index(actual, "repo1"))
args = []string{"list", "--sort-by", "alpha-asc", "--config", "repostest"}
cmd = NewRepoCommand(new(searchService))
cmd = client.NewRepoCommand(client.NewSearchService())
buff = bytes.NewBufferString("")
cmd.SetOut(buff)
cmd.SetErr(buff)
@ -91,11 +92,13 @@ func TestReposCommand(t *testing.T) {
func TestSuggestions(t *testing.T) {
Convey("Suggestions", t, func() {
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(), " ")
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(), " ")
So(str, ShouldContainSubstring, "Did you mean this? list")
})

View file

@ -10,9 +10,7 @@ import (
"regexp"
"strings"
"testing"
"time"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/api"
@ -20,713 +18,8 @@ import (
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 := 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) {
port := test.GetFreePort()
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"))
})
}

View 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"))
})
}

View file

@ -17,8 +17,8 @@ import (
const CveDBRetryInterval = 3
func SearchAllImages(config searchConfig) error {
username, password := getUsernameAndPassword(config.user)
func SearchAllImages(config SearchConfig) error {
username, password := getUsernameAndPassword(config.User)
imageErr := make(chan stringResult)
ctx, cancel := context.WithCancel(context.Background())
@ -26,7 +26,7 @@ func SearchAllImages(config searchConfig) error {
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)
errCh := make(chan error, 1)
@ -41,13 +41,13 @@ func SearchAllImages(config searchConfig) error {
}
}
func SearchAllImagesGQL(config searchConfig) error {
username, password := getUsernameAndPassword(config.user)
func SearchAllImagesGQL(config SearchConfig) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
imageList, err := config.searchService.getImagesGQL(ctx, config, username, password, "")
imageList, err := config.SearchService.getImagesGQL(ctx, config, username, password, "")
if err != nil {
return err
}
@ -61,8 +61,8 @@ func SearchAllImagesGQL(config searchConfig) error {
return printImageResult(config, imageListData)
}
func SearchImageByName(config searchConfig, image string) error {
username, password := getUsernameAndPassword(config.user)
func SearchImageByName(config SearchConfig, image string) error {
username, password := getUsernameAndPassword(config.User)
imageErr := make(chan stringResult)
ctx, cancel := context.WithCancel(context.Background())
@ -70,7 +70,7 @@ func SearchImageByName(config searchConfig, image string) error {
wg.Add(1)
go config.searchService.getImageByName(ctx, config, username, password,
go config.SearchService.getImageByName(ctx, config, username, password,
image, imageErr, &wg)
wg.Add(1)
@ -91,15 +91,15 @@ func SearchImageByName(config searchConfig, image string) error {
}
}
func SearchImageByNameGQL(config searchConfig, imageName string) error {
username, password := getUsernameAndPassword(config.user)
func SearchImageByNameGQL(config SearchConfig, imageName string) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
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 {
return err
}
@ -115,8 +115,8 @@ func SearchImageByNameGQL(config searchConfig, imageName string) error {
return printImageResult(config, imageListData)
}
func SearchImagesByDigest(config searchConfig, digest string) error {
username, password := getUsernameAndPassword(config.user)
func SearchImagesByDigest(config SearchConfig, digest string) error {
username, password := getUsernameAndPassword(config.User)
imageErr := make(chan stringResult)
ctx, cancel := context.WithCancel(context.Background())
@ -124,7 +124,7 @@ func SearchImagesByDigest(config searchConfig, digest string) error {
wg.Add(1)
go config.searchService.getImagesByDigest(ctx, config, username, password,
go config.SearchService.getImagesByDigest(ctx, config, username, password,
digest, imageErr, &wg)
wg.Add(1)
@ -141,13 +141,13 @@ func SearchImagesByDigest(config searchConfig, digest string) error {
}
}
func SearchDerivedImageListGQL(config searchConfig, derivedImage string) error {
username, password := getUsernameAndPassword(config.user)
func SearchDerivedImageListGQL(config SearchConfig, derivedImage string) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
imageList, err := config.searchService.getDerivedImageListGQL(ctx, config, username,
imageList, err := config.SearchService.getDerivedImageListGQL(ctx, config, username,
password, derivedImage)
if err != nil {
return err
@ -162,13 +162,13 @@ func SearchDerivedImageListGQL(config searchConfig, derivedImage string) error {
return printImageResult(config, imageListData)
}
func SearchBaseImageListGQL(config searchConfig, baseImage string) error {
username, password := getUsernameAndPassword(config.user)
func SearchBaseImageListGQL(config SearchConfig, baseImage string) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
imageList, err := config.searchService.getBaseImageListGQL(ctx, config, username,
imageList, err := config.SearchService.getBaseImageListGQL(ctx, config, username,
password, baseImage)
if err != nil {
return err
@ -183,13 +183,13 @@ func SearchBaseImageListGQL(config searchConfig, baseImage string) error {
return printImageResult(config, imageListData)
}
func SearchImagesForDigestGQL(config searchConfig, digest string) error {
username, password := getUsernameAndPassword(config.user)
func SearchImagesForDigestGQL(config SearchConfig, digest string) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
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 {
return err
}
@ -207,8 +207,8 @@ func SearchImagesForDigestGQL(config searchConfig, digest string) error {
return nil
}
func SearchCVEForImageGQL(config searchConfig, image, searchedCveID string) error {
username, password := getUsernameAndPassword(config.user)
func SearchCVEForImageGQL(config SearchConfig, image, searchedCveID string) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
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 {
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 !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
cancel()
@ -226,7 +226,7 @@ func SearchCVEForImageGQL(config searchConfig, image, searchedCveID string) erro
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()))
}
@ -237,30 +237,30 @@ func SearchCVEForImageGQL(config searchConfig, image, searchedCveID string) erro
}
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
}
var builder strings.Builder
if config.outputFormat == defaultOutputFormat || config.outputFormat == "" {
if config.OutputFormat == defaultOutputFormat || config.OutputFormat == "" {
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 {
return err
}
fmt.Fprint(config.resultWriter, out)
fmt.Fprint(config.ResultWriter, out)
return nil
}
func SearchImagesByCVEIDGQL(config searchConfig, repo, cveid string) error {
username, password := getUsernameAndPassword(config.user)
func SearchImagesByCVEIDGQL(config SearchConfig, repo, cveid string) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
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 {
var err error
imageList, err = config.searchService.getTagsForCVEGQL(ctx, config, username, password,
imageList, err = config.SearchService.getTagsForCVEGQL(ctx, config, username, password,
repo, cveid)
if err != nil {
if !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
@ -279,7 +279,7 @@ func SearchImagesByCVEIDGQL(config searchConfig, repo, cveid string) error {
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()))
}
@ -298,8 +298,8 @@ func SearchImagesByCVEIDGQL(config searchConfig, repo, cveid string) error {
return printImageResult(config, imageListData)
}
func SearchFixedTagsGQL(config searchConfig, repo, cveid string) error {
username, password := getUsernameAndPassword(config.user)
func SearchFixedTagsGQL(config SearchConfig, repo, cveid string) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
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 {
var err error
fixedTags, err = config.searchService.getFixedTagsForCVEGQL(ctx, config, username, password,
fixedTags, err = config.SearchService.getFixedTagsForCVEGQL(ctx, config, username, password,
repo, cveid)
if err != nil {
if !strings.Contains(err.Error(), zerr.ErrCVEDBNotFound.Error()) {
@ -318,7 +318,7 @@ func SearchFixedTagsGQL(config searchConfig, repo, cveid string) error {
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()))
}
@ -337,13 +337,13 @@ func SearchFixedTagsGQL(config searchConfig, repo, cveid string) error {
return printImageResult(config, imageList)
}
func GlobalSearchGQL(config searchConfig, query string) error {
username, password := getUsernameAndPassword(config.user)
func GlobalSearchGQL(config SearchConfig, query string) error {
username, password := getUsernameAndPassword(config.User)
ctx, cancel := context.WithCancel(context.Background())
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 {
return err
}
@ -367,8 +367,8 @@ func GlobalSearchGQL(config searchConfig, query string) error {
return printRepoResults(config, reposList)
}
func SearchReferrersGQL(config searchConfig, subject string) error {
username, password := getUsernameAndPassword(config.user)
func SearchReferrersGQL(config SearchConfig, subject string) error {
username, password := getUsernameAndPassword(config.User)
repo, ref, refIsTag, err := zcommon.GetRepoReference(subject)
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 {
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)
}
func SearchReferrers(config searchConfig, subject string) error {
username, password := getUsernameAndPassword(config.user)
func SearchReferrers(config SearchConfig, subject string) error {
username, password := getUsernameAndPassword(config.User)
repo, ref, refIsTag, err := zcommon.GetRepoReference(subject)
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)
if err != nil {
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)
}
func SearchRepos(config searchConfig) error {
username, password := getUsernameAndPassword(config.user)
func SearchRepos(config SearchConfig) error {
username, password := getUsernameAndPassword(config.User)
repoErr := make(chan stringResult)
ctx, cancel := context.WithCancel(context.Background())
@ -449,7 +449,7 @@ func SearchRepos(config searchConfig) error {
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)
errCh := make(chan error, 1)

View file

@ -29,7 +29,7 @@ func TestSearchAllImages(t *testing.T) {
Convey("SearchAllImages", t, func() {
buff := bytes.NewBufferString("")
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,
) {
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
@ -51,7 +51,7 @@ func TestSearchAllImagesGQL(t *testing.T) {
Convey("SearchAllImagesGQL", t, func() {
buff := bytes.NewBufferString("")
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) {
return &common.ImageListResponse{ImageList: common.ImageList{
PaginatedImagesResult: common.PaginatedImagesResult{
@ -72,7 +72,7 @@ func TestSearchAllImagesGQL(t *testing.T) {
Convey("SearchAllImagesGQL error", t, func() {
buff := bytes.NewBufferString("")
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) {
return &common.ImageListResponse{ImageList: common.ImageList{
PaginatedImagesResult: common.PaginatedImagesResult{
@ -91,7 +91,7 @@ func TestSearchImageByName(t *testing.T) {
Convey("SearchImageByName", t, func() {
buff := bytes.NewBufferString("")
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,
) {
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
@ -111,7 +111,7 @@ func TestSearchImageByName(t *testing.T) {
Convey("SearchImageByName error", t, func() {
buff := bytes.NewBufferString("")
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 <- stringResult{StrValue: "", Err: zerr.ErrInjected}
@ -127,7 +127,7 @@ func TestSearchImageByNameGQL(t *testing.T) {
Convey("SearchImageByNameGQL", t, func() {
buff := bytes.NewBufferString("")
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) {
return &common.ImageListResponse{ImageList: common.ImageList{
PaginatedImagesResult: common.PaginatedImagesResult{
@ -148,7 +148,7 @@ func TestSearchImageByNameGQL(t *testing.T) {
Convey("SearchImageByNameGQL error", t, func() {
buff := bytes.NewBufferString("")
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) {
return &common.ImageListResponse{ImageList: common.ImageList{
PaginatedImagesResult: common.PaginatedImagesResult{
@ -167,7 +167,7 @@ func TestSearchImagesByDigest(t *testing.T) {
Convey("SearchImagesByDigest", t, func() {
buff := bytes.NewBufferString("")
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,
) {
str, err := getMockImageStruct().stringPlainText(10, 10, 10, false)
@ -187,7 +187,7 @@ func TestSearchImagesByDigest(t *testing.T) {
Convey("SearchImagesByDigest error", t, func() {
buff := bytes.NewBufferString("")
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 <- stringResult{StrValue: "", Err: zerr.ErrInjected}
@ -203,7 +203,7 @@ func TestSearchDerivedImageListGQL(t *testing.T) {
Convey("SearchDerivedImageListGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
@ -227,7 +227,7 @@ func TestSearchDerivedImageListGQL(t *testing.T) {
Convey("SearchDerivedImageListGQL error", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.DerivedImageListResponse{DerivedImageList: common.DerivedImageList{
@ -245,7 +245,7 @@ func TestSearchBaseImageListGQL(t *testing.T) {
Convey("SearchBaseImageListGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
@ -267,7 +267,7 @@ func TestSearchBaseImageListGQL(t *testing.T) {
Convey("SearchBaseImageListGQL error", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.BaseImageListResponse{BaseImageList: common.BaseImageList{
@ -285,7 +285,7 @@ func TestSearchImagesForDigestGQL(t *testing.T) {
Convey("SearchImagesForDigestGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
@ -307,7 +307,7 @@ func TestSearchImagesForDigestGQL(t *testing.T) {
Convey("SearchImagesForDigestGQL error", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.ImagesForDigest{ImagesForDigestList: common.ImagesForDigestList{
@ -325,7 +325,7 @@ func TestSearchCVEForImageGQL(t *testing.T) {
Convey("SearchCVEForImageGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &cveResult{
@ -363,7 +363,7 @@ func TestSearchCVEForImageGQL(t *testing.T) {
Convey("SearchCVEForImageGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &cveResult{}, zerr.ErrInjected
@ -379,7 +379,7 @@ func TestSearchImagesByCVEIDGQL(t *testing.T) {
Convey("SearchImagesByCVEIDGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.ImagesForCve{
@ -405,7 +405,7 @@ func TestSearchImagesByCVEIDGQL(t *testing.T) {
Convey("SearchImagesByCVEIDGQL error", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.ImagesForCve{
@ -425,7 +425,7 @@ func TestSearchFixedTagsGQL(t *testing.T) {
Convey("SearchFixedTagsGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.ImageListWithCVEFixedResponse{
@ -449,7 +449,7 @@ func TestSearchFixedTagsGQL(t *testing.T) {
Convey("SearchFixedTagsGQL error", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.ImageListWithCVEFixedResponse{
@ -469,7 +469,7 @@ func TestSearchReferrersGQL(t *testing.T) {
Convey("SearchReferrersGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.ReferrersResp{
@ -497,7 +497,7 @@ func TestSearchReferrersGQL(t *testing.T) {
Convey("SearchReferrersGQL error", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.ReferrersResp{}, zerr.ErrInjected
@ -513,7 +513,7 @@ func TestGlobalSearchGQL(t *testing.T) {
Convey("GlobalSearchGQL", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.GlobalSearch{
@ -538,7 +538,7 @@ func TestGlobalSearchGQL(t *testing.T) {
Convey("GlobalSearchGQL error", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return &common.GlobalSearch{}, zerr.ErrInjected
@ -554,7 +554,7 @@ func TestSearchReferrers(t *testing.T) {
Convey("SearchReferrers", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return referrersResult([]common.Referrer{
@ -580,7 +580,7 @@ func TestSearchReferrers(t *testing.T) {
Convey("SearchReferrers error", t, func() {
buff := bytes.NewBufferString("")
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,
) {
return referrersResult{}, zerr.ErrInjected
@ -607,17 +607,17 @@ func TestSearchRepos(t *testing.T) {
})
}
func getMockSearchConfig(buff *bytes.Buffer, mockService mockService) searchConfig {
return searchConfig{
resultWriter: buff,
user: "",
searchService: mockService,
servURL: "http://127.0.0.1:8000",
outputFormat: "",
verifyTLS: false,
fixedFlag: false,
verbose: false,
debug: false,
func getMockSearchConfig(buff *bytes.Buffer, mockService mockService) SearchConfig {
return SearchConfig{
ResultWriter: buff,
User: "",
SearchService: mockService,
ServURL: "http://127.0.0.1:8000",
OutputFormat: "",
VerifyTLS: false,
FixedFlag: false,
Verbose: false,
Debug: false,
}
}
@ -744,19 +744,19 @@ func TestUtils(t *testing.T) {
Convey("CheckExtEndPointQuery", t, func() {
// invalid url
err := CheckExtEndPointQuery(searchConfig{
user: "",
servURL: "bad-url",
err := CheckExtEndPointQuery(SearchConfig{
User: "",
ServURL: "bad-url",
})
So(err, ShouldNotBeNil)
// good url but no connection
err = CheckExtEndPointQuery(searchConfig{
user: "",
servURL: "http://127.0.0.1:5000",
verifyTLS: false,
debug: false,
resultWriter: io.Discard,
err = CheckExtEndPointQuery(SearchConfig{
User: "",
ServURL: "http://127.0.0.1:5000",
VerifyTLS: false,
Debug: false,
ResultWriter: io.Discard,
})
So(err, ShouldNotBeNil)
})

View file

@ -32,49 +32,49 @@ const (
)
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)
getImagesForDigestGQL(ctx context.Context, config searchConfig, username, password string,
getImagesForDigestGQL(ctx context.Context, config SearchConfig, username, password string,
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)
getTagsForCVEGQL(ctx context.Context, config searchConfig, username, password, repo,
getTagsForCVEGQL(ctx context.Context, config SearchConfig, username, password, repo,
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)
getDerivedImageListGQL(ctx context.Context, config searchConfig, username, password string,
getDerivedImageListGQL(ctx context.Context, config SearchConfig, username, password string,
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)
getReferrersGQL(ctx context.Context, config searchConfig, username, password string,
getReferrersGQL(ctx context.Context, config SearchConfig, username, password string,
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)
getAllImages(ctx context.Context, config searchConfig, username, password string,
getAllImages(ctx context.Context, config SearchConfig, username, password string,
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)
getRepos(ctx context.Context, config searchConfig, username, password string,
getRepos(ctx context.Context, config SearchConfig, username, password string,
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)
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)
}
type searchConfig struct {
searchService SearchService
servURL string
user string
outputFormat string
sortBy string
verifyTLS bool
fixedFlag bool
verbose bool
debug bool
resultWriter io.Writer
spinner spinnerState
type SearchConfig struct {
SearchService SearchService
ServURL string
User string
OutputFormat string
SortBy string
VerifyTLS bool
FixedFlag bool
Verbose bool
Debug bool
ResultWriter io.Writer
Spinner spinnerState
}
type searchService struct{}
@ -83,7 +83,7 @@ func NewSearchService() 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,
) (*common.DerivedImageListResponse, error) {
query := fmt.Sprintf(`
@ -107,7 +107,7 @@ func (service searchService) getDerivedImageListGQL(ctx context.Context, config
IsSigned
}
}
}`, derivedImage, Flag2SortCriteria(config.sortBy))
}`, derivedImage, Flag2SortCriteria(config.SortBy))
result := &common.DerivedImageListResponse{}
err := service.makeGraphQLQuery(ctx, config, username, password, query, result)
@ -119,7 +119,7 @@ func (service searchService) getDerivedImageListGQL(ctx context.Context, config
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,
) (*common.ReferrersResp, error) {
query := fmt.Sprintf(`
@ -146,7 +146,7 @@ func (service searchService) getReferrersGQL(ctx context.Context, config searchC
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,
) (*common.GlobalSearch, error) {
GQLQuery := fmt.Sprintf(`
@ -179,7 +179,7 @@ func (service searchService) globalSearchGQL(ctx context.Context, config searchC
StarCount
}
}
}`, query, Flag2SortCriteria(config.sortBy))
}`, query, Flag2SortCriteria(config.SortBy))
result := &common.GlobalSearchResultResp{}
@ -191,7 +191,7 @@ func (service searchService) globalSearchGQL(ctx context.Context, config searchC
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,
) (*common.BaseImageListResponse, error) {
query := fmt.Sprintf(`
@ -215,7 +215,7 @@ func (service searchService) getBaseImageListGQL(ctx context.Context, config sea
IsSigned
}
}
}`, baseImage, Flag2SortCriteria(config.sortBy))
}`, baseImage, Flag2SortCriteria(config.SortBy))
result := &common.BaseImageListResponse{}
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
}
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,
) (*common.ImageListResponse, error) {
query := fmt.Sprintf(`
@ -251,7 +251,7 @@ func (service searchService) getImagesGQL(ctx context.Context, config searchConf
IsSigned
}
}
}`, imageName, Flag2SortCriteria(config.sortBy))
}`, imageName, Flag2SortCriteria(config.SortBy))
result := &common.ImageListResponse{}
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
}
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,
) (*common.ImagesForDigest, error) {
query := fmt.Sprintf(`
@ -287,7 +287,7 @@ func (service searchService) getImagesForDigestGQL(ctx context.Context, config s
IsSigned
}
}
}`, digest, Flag2SortCriteria(config.sortBy))
}`, digest, Flag2SortCriteria(config.SortBy))
result := &common.ImagesForDigest{}
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
}
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,
) (*cveResult, error) {
query := fmt.Sprintf(`
@ -310,7 +310,7 @@ func (service searchService) getCveByImageGQL(ctx context.Context, config search
PackageList {Name InstalledVersion FixedVersion}
}
}
}`, imageName, searchedCVE, Flag2SortCriteria(config.sortBy))
}`, imageName, searchedCVE, Flag2SortCriteria(config.SortBy))
result := &cveResult{}
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
}
func (service searchService) getTagsForCVEGQL(ctx context.Context, config searchConfig,
func (service searchService) getTagsForCVEGQL(ctx context.Context, config SearchConfig,
username, password, repo, cveID string,
) (*common.ImagesForCve, error) {
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{}
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
}
func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config searchConfig,
func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config SearchConfig,
username, password, imageName, cveID string,
) (*common.ImageListWithCVEFixedResponse, error) {
query := fmt.Sprintf(`
@ -409,10 +409,10 @@ func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config s
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,
) (referrersResult, error) {
referrersEndpoint, err := combineServerAndEndpointURL(config.servURL,
referrersEndpoint, err := combineServerAndEndpointURL(config.ServURL,
fmt.Sprintf("/v2/%s/referrers/%s", repo, digest))
if err != nil {
if isContextDone(ctx) {
@ -423,8 +423,8 @@ func (service searchService) getReferrers(ctx context.Context, config searchConf
}
referrerResp := &ispec.Index{}
_, err = makeGETRequest(ctx, referrersEndpoint, username, password, config.verifyTLS,
config.debug, &referrerResp, config.resultWriter)
_, err = makeGETRequest(ctx, referrersEndpoint, username, password, config.VerifyTLS,
config.Debug, &referrerResp, config.ResultWriter)
if err != nil {
if isContextDone(ctx) {
@ -447,7 +447,7 @@ func (service searchService) getReferrers(ctx context.Context, config searchConf
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,
) {
defer wtgrp.Done()
@ -466,7 +466,7 @@ func (service searchService) getImageByName(ctx context.Context, config searchCo
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,
) {
defer wtgrp.Done()
@ -474,7 +474,7 @@ func (service searchService) getAllImages(ctx context.Context, config searchConf
catalog := &catalogResponse{}
catalogEndPoint, err := combineServerAndEndpointURL(config.servURL, fmt.Sprintf("%s%s",
catalogEndPoint, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("%s%s",
constants.RoutePrefix, constants.ExtCatalogPrefix))
if err != nil {
if isContextDone(ctx) {
@ -485,8 +485,8 @@ func (service searchService) getAllImages(ctx context.Context, config searchConf
return
}
_, err = makeGETRequest(ctx, catalogEndPoint, username, password, config.verifyTLS,
config.debug, catalog, config.resultWriter)
_, err = makeGETRequest(ctx, catalogEndPoint, username, password, config.VerifyTLS,
config.Debug, catalog, config.ResultWriter)
if err != nil {
if isContextDone(ctx) {
return
@ -513,14 +513,14 @@ func (service searchService) getAllImages(ctx context.Context, config searchConf
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,
) {
defer wtgrp.Done()
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 isContextDone(ctx) {
return
@ -531,8 +531,8 @@ func getImage(ctx context.Context, config searchConfig, username, password, imag
}
tagList := &tagListResp{}
_, err = makeGETRequest(ctx, tagListEndpoint, username, password, config.verifyTLS,
config.debug, &tagList, config.resultWriter)
_, err = makeGETRequest(ctx, tagListEndpoint, username, password, config.VerifyTLS,
config.Debug, &tagList, config.ResultWriter)
if err != nil {
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,
) {
defer wtgrp.Done()
@ -652,16 +652,16 @@ func isContextDone(ctx context.Context) bool {
// Query using GQL, the query string is passed as a parameter
// errors are returned in the stringResult channel, the unmarshalled payload is in resultPtr.
func (service searchService) makeGraphQLQuery(ctx context.Context,
config searchConfig, username, password, query string,
config SearchConfig, username, password, query string,
resultPtr interface{},
) error {
endPoint, err := combineServerAndEndpointURL(config.servURL, constants.FullSearchPrefix)
endPoint, err := combineServerAndEndpointURL(config.ServURL, constants.FullSearchPrefix)
if err != nil {
return err
}
err = makeGraphQLRequest(ctx, endPoint, query, username, password, config.verifyTLS,
config.debug, resultPtr, config.resultWriter)
err = makeGraphQLRequest(ctx, endPoint, query, username, password, config.VerifyTLS,
config.Debug, resultPtr, config.ResultWriter)
if err != nil {
return err
}
@ -697,12 +697,12 @@ func checkResultGraphQLQuery(ctx context.Context, err error, resultErrors []comm
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,
) {
defer wtgrp.Done()
manifestEndpoint, err := combineServerAndEndpointURL(config.servURL,
manifestEndpoint, err := combineServerAndEndpointURL(config.ServURL,
fmt.Sprintf("/v2/%s/manifests/%s", imageName, tagName))
if err != nil {
if isContextDone(ctx) {
@ -1304,7 +1304,7 @@ func getRepoTableWriter(writer io.Writer) *tablewriter.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,
) {
defer wtgrp.Done()
@ -1312,7 +1312,7 @@ func (service searchService) getRepos(ctx context.Context, config searchConfig,
catalog := &catalogResponse{}
catalogEndPoint, err := combineServerAndEndpointURL(config.servURL, fmt.Sprintf("%s%s",
catalogEndPoint, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("%s%s",
constants.RoutePrefix, constants.ExtCatalogPrefix))
if err != nil {
if isContextDone(ctx) {
@ -1323,8 +1323,8 @@ func (service searchService) getRepos(ctx context.Context, config searchConfig,
return
}
_, err = makeGETRequest(ctx, catalogEndPoint, username, password, config.verifyTLS,
config.debug, catalog, config.resultWriter)
_, err = makeGETRequest(ctx, catalogEndPoint, username, password, config.VerifyTLS,
config.Debug, catalog, config.ResultWriter)
if err != nil {
if isContextDone(ctx) {
return
@ -1334,15 +1334,15 @@ func (service searchService) getRepos(ctx context.Context, config searchConfig,
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++ {
fmt.Fprintln(config.resultWriter, catalog.Repositories[i])
fmt.Fprintln(config.ResultWriter, catalog.Repositories[i])
}
} else {
for i := len(catalog.Repositories) - 1; i >= 0; i-- {
fmt.Fprintln(config.resultWriter, catalog.Repositories[i])
fmt.Fprintln(config.ResultWriter, catalog.Repositories[i])
}
}
}

View file

@ -30,31 +30,31 @@ func ref[T any](input T) *T {
return &ref
}
func fetchImageDigest(repo, ref, username, password string, config searchConfig) (string, error) {
url, err := combineServerAndEndpointURL(config.servURL, fmt.Sprintf("/v2/%s/manifests/%s", repo, ref))
func fetchImageDigest(repo, ref, username, password string, config SearchConfig) (string, error) {
url, err := combineServerAndEndpointURL(config.ServURL, fmt.Sprintf("/v2/%s/manifests/%s", repo, ref))
if err != nil {
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)
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,
) {
var foundResult bool
defer wg.Done()
config.spinner.startSpinner()
config.Spinner.startSpinner()
for {
select {
case result, ok := <-imageErr:
config.spinner.stopSpinner()
config.Spinner.stopSpinner()
if !ok {
cancel()
@ -69,18 +69,18 @@ func collectResults(config searchConfig, wg *sync.WaitGroup, imageErr chan strin
return
}
if !foundResult && (config.outputFormat == defaultOutputFormat || config.outputFormat == "") {
if !foundResult && (config.OutputFormat == defaultOutputFormat || config.OutputFormat == "") {
var builder strings.Builder
printHeader(&builder, config.verbose, 0, 0, 0)
fmt.Fprint(config.resultWriter, builder.String())
printHeader(&builder, config.Verbose, 0, 0, 0)
fmt.Fprint(config.ResultWriter, builder.String())
}
foundResult = true
fmt.Fprint(config.resultWriter, result.StrValue)
fmt.Fprint(config.ResultWriter, result.StrValue)
case <-time.After(waitTimeout):
config.spinner.stopSpinner()
config.Spinner.stopSpinner()
cancel()
errCh <- zerr.ErrCLITimeout
@ -193,8 +193,8 @@ func printCVETableHeader(writer io.Writer) {
table.Render()
}
func printReferrersTableHeader(config searchConfig, writer io.Writer, maxArtifactTypeLen int) {
if config.outputFormat != "" && config.outputFormat != defaultOutputFormat {
func printReferrersTableHeader(config SearchConfig, writer io.Writer, maxArtifactTypeLen int) {
if config.OutputFormat != "" && config.OutputFormat != defaultOutputFormat {
return
}
@ -269,18 +269,18 @@ func printRepoTableHeader(writer io.Writer, repoMaxLen, maxTimeLen int, verbose
table.Render()
}
func printReferrersResult(config searchConfig, referrersList referrersResult, maxArtifactTypeLen int) error {
out, err := referrersList.string(config.outputFormat, maxArtifactTypeLen)
func printReferrersResult(config SearchConfig, referrersList referrersResult, maxArtifactTypeLen int) error {
out, err := referrersList.string(config.OutputFormat, maxArtifactTypeLen)
if err != nil {
return err
}
fmt.Fprint(config.resultWriter, out)
fmt.Fprint(config.ResultWriter, out)
return nil
}
func printImageResult(config searchConfig, imageList []imageStruct) error {
func printImageResult(config SearchConfig, imageList []imageStruct) error {
var builder strings.Builder
maxImgNameLen := 0
maxTagLen := 0
@ -305,29 +305,29 @@ func printImageResult(config searchConfig, imageList []imageStruct) error {
}
}
if config.outputFormat == defaultOutputFormat || config.outputFormat == "" {
printImageTableHeader(&builder, config.verbose, maxImgNameLen, maxTagLen, maxPlatformLen)
if config.OutputFormat == defaultOutputFormat || config.OutputFormat == "" {
printImageTableHeader(&builder, config.Verbose, maxImgNameLen, maxTagLen, maxPlatformLen)
}
fmt.Fprint(config.resultWriter, builder.String())
fmt.Fprint(config.ResultWriter, builder.String())
}
for i := range imageList {
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 {
return err
}
fmt.Fprint(config.resultWriter, out)
fmt.Fprint(config.ResultWriter, out)
}
return nil
}
func printRepoResults(config searchConfig, repoList []repoStruct) error {
func printRepoResults(config SearchConfig, repoList []repoStruct) error {
maxRepoNameLen := 0
maxTimeLen := 0
@ -341,31 +341,31 @@ func printRepoResults(config searchConfig, repoList []repoStruct) error {
}
}
if len(repoList) > 0 && (config.outputFormat == defaultOutputFormat || config.outputFormat == "") {
printRepoTableHeader(config.resultWriter, maxRepoNameLen, maxTimeLen, config.verbose)
if len(repoList) > 0 && (config.OutputFormat == defaultOutputFormat || config.OutputFormat == "") {
printRepoTableHeader(config.ResultWriter, maxRepoNameLen, maxTimeLen, config.Verbose)
}
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 {
return err
}
fmt.Fprint(config.resultWriter, out)
fmt.Fprint(config.ResultWriter, out)
}
return nil
}
func GetSearchConfigFromFlags(cmd *cobra.Command, searchService SearchService) (searchConfig, error) {
func GetSearchConfigFromFlags(cmd *cobra.Command, searchService SearchService) (SearchConfig, error) {
serverURL, err := GetServerURLFromFlags(cmd)
if err != nil {
return searchConfig{}, err
return SearchConfig{}, err
}
isSpinner, verifyTLS, err := GetCliConfigOptions(cmd)
if err != nil {
return searchConfig{}, err
return SearchConfig{}, err
}
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.Prefix = prefix
return searchConfig{
searchService: searchService,
servURL: serverURL,
user: user,
outputFormat: outputFormat,
verifyTLS: verifyTLS,
fixedFlag: fixed,
verbose: verbose,
debug: debug,
sortBy: sortBy,
spinner: spinnerState{spin, isSpinner},
resultWriter: cmd.OutOrStdout(),
return SearchConfig{
SearchService: searchService,
ServURL: serverURL,
User: user,
OutputFormat: outputFormat,
VerifyTLS: verifyTLS,
FixedFlag: fixed,
Verbose: verbose,
Debug: debug,
SortBy: sortBy,
Spinner: spinnerState{spin, isSpinner},
ResultWriter: cmd.OutOrStdout(),
}, nil
}

View file

@ -20,19 +20,19 @@ import (
test "zotregistry.io/zot/pkg/test/common"
)
func getDefaultSearchConf(baseURL string) searchConfig {
func getDefaultSearchConf(baseURL string) SearchConfig {
verifyTLS := false
debug := false
verbose := true
outputFormat := "text"
return searchConfig{
servURL: baseURL,
resultWriter: io.Discard,
verifyTLS: verifyTLS,
debug: debug,
verbose: verbose,
outputFormat: outputFormat,
return SearchConfig{
ServURL: baseURL,
ResultWriter: io.Discard,
VerifyTLS: verifyTLS,
Debug: debug,
Verbose: verbose,
OutputFormat: outputFormat,
}
}