mirror of
https://github.com/project-zot/zot.git
synced 2026-06-18 05:28:07 +08:00
9dfa7c3ae6
Replace MakeTempFile usage with MakeTempFilePath and MakeTempFileWithContent helpers that automatically handle file lifecycle. This prevents resource leaks by ensuring temporary files are properly closed. Shoudld also make the tests easier to read. Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
1106 lines
33 KiB
Go
1106 lines
33 KiB
Go
//go:build search
|
|
|
|
package client_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"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.dev/zot/v2/errors"
|
|
"zotregistry.dev/zot/v2/pkg/api"
|
|
"zotregistry.dev/zot/v2/pkg/api/config"
|
|
"zotregistry.dev/zot/v2/pkg/cli/client"
|
|
zcommon "zotregistry.dev/zot/v2/pkg/common"
|
|
extconf "zotregistry.dev/zot/v2/pkg/extensions/config"
|
|
"zotregistry.dev/zot/v2/pkg/extensions/monitoring"
|
|
cveinfo "zotregistry.dev/zot/v2/pkg/extensions/search/cve"
|
|
cvemodel "zotregistry.dev/zot/v2/pkg/extensions/search/cve/model"
|
|
"zotregistry.dev/zot/v2/pkg/log"
|
|
mTypes "zotregistry.dev/zot/v2/pkg/meta/types"
|
|
"zotregistry.dev/zot/v2/pkg/storage"
|
|
"zotregistry.dev/zot/v2/pkg/storage/local"
|
|
test "zotregistry.dev/zot/v2/pkg/test/common"
|
|
. "zotregistry.dev/zot/v2/pkg/test/image-utils"
|
|
"zotregistry.dev/zot/v2/pkg/test/mocks"
|
|
ociutils "zotregistry.dev/zot/v2/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.NewTestLogger())
|
|
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 := test.MakeTempFile(t, "zot-log.txt")
|
|
defer logFile.Close()
|
|
logPath := logFile.Name()
|
|
|
|
writers := io.MultiWriter(os.Stdout, logFile)
|
|
|
|
ctlr := api.NewController(conf)
|
|
ctlr.Log = log.NewLoggerWithWriter("info", 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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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.NewTestLogger(), monitoring.NewMetricsServer(false, log.NewTestLogger()), nil, nil, 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 := test.MakeTempFile(t, "zot-log.txt")
|
|
defer logFile.Close()
|
|
logPath := logFile.Name()
|
|
|
|
writers := io.MultiWriter(os.Stdout, logFile)
|
|
|
|
ctlr := api.NewController(conf)
|
|
ctlr.Log = log.NewLoggerWithWriter("info", writers)
|
|
|
|
if err := ctlr.Init(); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ctlr.CveScanner = getMockCveScanner(ctlr.MetaDB)
|
|
|
|
go func() {
|
|
if err := ctlr.Run(); !errors.Is(err, http.ErrServerClosed) {
|
|
panic(err)
|
|
}
|
|
}()
|
|
|
|
defer ctlr.Shutdown()
|
|
|
|
test.WaitTillServerReady(url)
|
|
|
|
_, err = test.ReadLogFileAndSearchString(logPath, "cve-db update completed, next update scheduled after interval",
|
|
90*time.Second)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
args := []string{"fixed", "zot-cve-test", "CVE-2019-9923", "--config", "cvetest"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
err = cveCmd.Execute()
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
}
|
|
|
|
func TestCVEDiffList(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 := test.MakeTempFile(t, "zot-log.txt")
|
|
defer logFile.Close()
|
|
writers := io.MultiWriter(os.Stdout, logFile)
|
|
|
|
ctlr := api.NewController(conf)
|
|
ctlr.Log = log.NewLoggerWithWriter("info", writers)
|
|
|
|
if err := ctlr.Init(); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
layer1 := []byte{10, 20, 30}
|
|
layer2 := []byte{11, 21, 31}
|
|
layer3 := []byte{12, 22, 23}
|
|
|
|
otherImage := CreateImageWith().LayerBlobs([][]byte{
|
|
layer1,
|
|
}).DefaultConfig().Build()
|
|
|
|
baseImage := CreateImageWith().LayerBlobs([][]byte{
|
|
layer1,
|
|
layer2,
|
|
}).PlatformConfig("testArch", "testOs").Build()
|
|
|
|
image := CreateImageWith().LayerBlobs([][]byte{
|
|
layer1,
|
|
layer2,
|
|
layer3,
|
|
}).PlatformConfig("testArch", "testOs").Build()
|
|
|
|
multiArchBase := CreateMultiarchWith().Images([]Image{baseImage, CreateRandomImage(), CreateRandomImage()}).
|
|
Build()
|
|
multiArchImage := CreateMultiarchWith().Images([]Image{image, CreateRandomImage(), CreateRandomImage()}).
|
|
Build()
|
|
|
|
getCveResults := func(digestStr string) map[string]cvemodel.CVE {
|
|
switch digestStr {
|
|
case image.DigestStr():
|
|
return map[string]cvemodel.CVE{
|
|
"CVE1": {
|
|
ID: "CVE1",
|
|
Severity: "HIGH",
|
|
Title: "Title CVE1",
|
|
Description: "Description CVE1",
|
|
PackageList: []cvemodel.Package{{}},
|
|
},
|
|
"CVE2": {
|
|
ID: "CVE2",
|
|
Severity: "MEDIUM",
|
|
Title: "Title CVE2",
|
|
Description: "Description CVE2",
|
|
PackageList: []cvemodel.Package{{}},
|
|
},
|
|
"CVE3": {
|
|
ID: "CVE3",
|
|
Severity: "LOW",
|
|
Title: "Title CVE3",
|
|
Description: "Description CVE3",
|
|
PackageList: []cvemodel.Package{{}},
|
|
},
|
|
}
|
|
case baseImage.DigestStr():
|
|
return map[string]cvemodel.CVE{
|
|
"CVE1": {
|
|
ID: "CVE1",
|
|
Severity: "HIGH",
|
|
Title: "Title CVE1",
|
|
Description: "Description CVE1",
|
|
PackageList: []cvemodel.Package{{}},
|
|
},
|
|
"CVE2": {
|
|
ID: "CVE2",
|
|
Severity: "MEDIUM",
|
|
Title: "Title CVE2",
|
|
Description: "Description CVE2",
|
|
PackageList: []cvemodel.Package{{}},
|
|
},
|
|
}
|
|
case otherImage.DigestStr():
|
|
return map[string]cvemodel.CVE{
|
|
"CVE1": {
|
|
ID: "CVE1",
|
|
Severity: "HIGH",
|
|
Title: "Title CVE1",
|
|
Description: "Description CVE1",
|
|
PackageList: []cvemodel.Package{{}},
|
|
},
|
|
}
|
|
}
|
|
|
|
// By default the image has no vulnerabilities
|
|
return map[string]cvemodel.CVE{}
|
|
}
|
|
|
|
// MetaDB loaded with initial data, now mock the scanner
|
|
// Setup test CVE data in mock scanner
|
|
scanner := mocks.CveScannerMock{
|
|
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
|
|
repo, ref, _, _ := zcommon.GetRepoReference(image)
|
|
|
|
if zcommon.IsDigest(ref) {
|
|
return getCveResults(ref), nil
|
|
}
|
|
|
|
repoMeta, _ := ctlr.MetaDB.GetRepoMeta(ctx, repo)
|
|
|
|
if _, ok := repoMeta.Tags[ref]; !ok {
|
|
panic("unexpected tag '" + ref + "', test might be wrong")
|
|
}
|
|
|
|
return getCveResults(repoMeta.Tags[ref].Digest), nil
|
|
},
|
|
GetCachedResultFn: func(digestStr string) map[string]cvemodel.CVE {
|
|
return getCveResults(digestStr)
|
|
},
|
|
IsResultCachedFn: func(digestStr string) bool {
|
|
return true
|
|
},
|
|
}
|
|
|
|
ctlr.CveScanner = scanner
|
|
|
|
go func() {
|
|
if err := ctlr.Run(); !errors.Is(err, http.ErrServerClosed) {
|
|
panic(err)
|
|
}
|
|
}()
|
|
|
|
defer ctlr.Shutdown()
|
|
|
|
test.WaitTillServerReady(url)
|
|
|
|
ctx := context.Background()
|
|
_, _ = ociutils.InitializeTestMetaDB(ctx, ctlr.MetaDB,
|
|
ociutils.Repo{
|
|
Name: "repo",
|
|
Images: []ociutils.RepoImage{
|
|
{Image: otherImage, Reference: "other-image"},
|
|
{Image: baseImage, Reference: "base-image"},
|
|
{Image: image, Reference: "image"},
|
|
},
|
|
},
|
|
ociutils.Repo{
|
|
Name: "repo-multi",
|
|
MultiArchImages: []ociutils.RepoMultiArchImage{
|
|
{MultiarchImage: CreateRandomMultiarch(), Reference: "multi-rand"},
|
|
{MultiarchImage: multiArchBase, Reference: "multi-base"},
|
|
{MultiarchImage: multiArchImage, Reference: "multi-img"},
|
|
},
|
|
},
|
|
)
|
|
|
|
Convey("Test CVE by image name - GQL - positive", t, func() {
|
|
args := []string{"diff", "repo:image", "repo:base-image", "--config", "cvetest"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
err := cveCmd.Execute()
|
|
So(err, ShouldBeNil)
|
|
|
|
fmt.Println(buff.String())
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
str = strings.TrimSpace(str)
|
|
So(str, ShouldContainSubstring, "CVE3")
|
|
So(str, ShouldNotContainSubstring, "CVE1")
|
|
So(str, ShouldNotContainSubstring, "CVE2")
|
|
})
|
|
|
|
Convey("Errors", t, func() {
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
|
|
Convey("Set wrong number of params", func() {
|
|
args := []string{"diff", "repo:image", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldNotBeNil)
|
|
})
|
|
Convey("First input is not a repo:tag", func() {
|
|
args := []string{"diff", "bad-input", "repo:base-image", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldNotBeNil)
|
|
})
|
|
Convey("Second input is arch but not enough args", func() {
|
|
args := []string{"diff", "repo:base-image", "linux/amd64", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldNotBeNil)
|
|
})
|
|
Convey("Second input is arch 3rd is repo:tag", func() {
|
|
args := []string{"diff", "repo:base-image", "linux/amd64", "repo:base-image", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldBeNil)
|
|
})
|
|
Convey("Second input is repo:tag 3rd is repo:tag", func() {
|
|
args := []string{"diff", "repo:base-image", "repo:base-image", "repo:base-image", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldNotBeNil)
|
|
})
|
|
Convey("Second input is arch 3rd is arch as well", func() {
|
|
args := []string{"diff", "repo:base-image", "linux/amd64", "linux/amd64", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldNotBeNil)
|
|
})
|
|
Convey("Second input is repo:tag 3rd is arch", func() {
|
|
args := []string{"diff", "repo:base-image", "repo:base-image", "linux/amd64", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldBeNil)
|
|
})
|
|
Convey("Second input is repo:tag 3rd is arch, 4th is repo:tag", func() {
|
|
args := []string{
|
|
"diff", "repo:base-image", "repo:base-image", "linux/amd64", "repo:base-image",
|
|
"--config", "cvetest",
|
|
}
|
|
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldNotBeNil)
|
|
})
|
|
Convey("Second input is arch 3rd is repo:tag, 4th is arch", func() {
|
|
args := []string{"diff", "repo:base-image", "linux/amd64", "repo:base-image", "linux/amd64", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldBeNil)
|
|
})
|
|
Convey("input is with digest ref", func() {
|
|
args := []string{"diff", "repo@sha256:123123", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), ShouldNotBeNil)
|
|
})
|
|
Convey("input is with just repo no ref", func() {
|
|
args := []string{"diff", "repo", "--config", "cvetest"}
|
|
cveCmd.SetArgs(args)
|
|
So(cveCmd.Execute(), 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 := test.MakeTempFile(t, "zot-log.txt")
|
|
defer logFile.Close()
|
|
writers := io.MultiWriter(os.Stdout, logFile)
|
|
|
|
ctlr := api.NewController(conf)
|
|
ctlr.Log = log.NewLoggerWithWriter("info", writers)
|
|
|
|
if err := ctlr.Init(); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ctlr.CveScanner = getMockCveScanner(ctlr.MetaDB)
|
|
|
|
go func() {
|
|
if err := ctlr.Run(); !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)
|
|
}
|
|
|
|
logPath := logFile.Name()
|
|
_, err = test.ReadLogFileAndSearchString(logPath, "cve-db update completed, next update scheduled after interval",
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
|
|
err = cveCmd.Execute()
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
str = strings.TrimSpace(str)
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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 cli output format", t, func() {
|
|
args := []string{"list", "zot-cve-test:0.0.1", "-f", "random", "--config", "cvetest"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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 cli output format")
|
|
})
|
|
|
|
Convey("Test images by CVE ID - GQL - positive", t, func() {
|
|
args := []string{"affected", "CVE-2019-9923", "--config", "cvetest"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
|
|
err := cveCmd.Execute()
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
str = strings.TrimSpace(str)
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
|
|
err := cveCmd.Execute()
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
str = strings.TrimSpace(str)
|
|
|
|
So(str, ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
|
})
|
|
|
|
Convey("Test images by CVE ID - GQL - invalid cli output format", t, func() {
|
|
args := []string{"affected", "CVE-2019-9923", "-f", "random", "--config", "cvetest"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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 cli 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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
|
|
err := cveCmd.Execute()
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
str = strings.TrimSpace(str)
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
|
|
err := cveCmd.Execute()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
str = strings.TrimSpace(str)
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
|
|
err := cveCmd.Execute()
|
|
So(err, ShouldNotBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
str = strings.TrimSpace(str)
|
|
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
|
|
err := cveCmd.Execute()
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
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"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
cveCmd := client.NewCVECommand(client.NewSearchService())
|
|
buff := bytes.NewBufferString("")
|
|
cveCmd.SetOut(buff)
|
|
cveCmd.SetErr(buff)
|
|
cveCmd.SetArgs(args)
|
|
|
|
err := cveCmd.Execute()
|
|
So(err, ShouldBeNil)
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
So(strings.TrimSpace(str), ShouldNotContainSubstring, "REPOSITORY TAG OS/ARCH SIGNED SIZE")
|
|
})
|
|
|
|
Convey("Test CVE by name and CVE ID - GQL - invalid cli output format", t, func() {
|
|
args := []string{"affected", "CVE-2019-9923", "--repo", "zot-cve-test", "-f", "random", "--config", "cvetest"}
|
|
|
|
_ = makeConfigFile(t, fmt.Sprintf(`{"configs":[{"_name":"cvetest","url":"%s","showspinner":false}]}`, url))
|
|
|
|
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 cli 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()
|
|
}
|
|
|
|
if err := ctlr.Init(); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ctlr.CveScanner = mocks.CveScannerMock{
|
|
ScanImageFn: func(ctx context.Context, 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(); !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)
|
|
|
|
outputLines := strings.Split(buff.String(), "\n")
|
|
|
|
expected := []string{
|
|
"CRITICAL 1, HIGH 1, MEDIUM 2, LOW 1, UNKNOWN 0, TOTAL 5",
|
|
"",
|
|
"ID SEVERITY TITLE VULNERABLE PACKAGE PATH INSTALL-VER FIXED-VER",
|
|
"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...",
|
|
}
|
|
|
|
for expectedLineIndex, expectedLine := range expected {
|
|
currentOutputLine := outputLines[expectedLineIndex]
|
|
str := space.ReplaceAllString(currentOutputLine, " ")
|
|
So(strings.TrimSpace(str), ShouldResemble, expectedLine)
|
|
}
|
|
|
|
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)
|
|
|
|
outputLines = strings.Split(buff.String(), "\n")
|
|
|
|
expected = []string{
|
|
"CRITICAL 1, HIGH 1, MEDIUM 2, LOW 1, UNKNOWN 0, TOTAL 5",
|
|
"",
|
|
"ID SEVERITY TITLE VULNERABLE PACKAGE PATH INSTALL-VER FIXED-VER",
|
|
"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 ...",
|
|
}
|
|
|
|
for expectedLineIndex, expectedLine := range expected {
|
|
currentOutputLine := outputLines[expectedLineIndex]
|
|
str := space.ReplaceAllString(currentOutputLine, " ")
|
|
So(strings.TrimSpace(str), ShouldResemble, expectedLine)
|
|
}
|
|
|
|
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)
|
|
|
|
outputLines = strings.Split(buff.String(), "\n")
|
|
|
|
expected = []string{
|
|
"CRITICAL 1, HIGH 1, MEDIUM 2, LOW 1, UNKNOWN 0, TOTAL 5",
|
|
"",
|
|
"ID SEVERITY TITLE VULNERABLE PACKAGE PATH INSTALL-VER FIXED-VER",
|
|
"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...",
|
|
}
|
|
|
|
for expectedLineIndex, expectedLine := range expected {
|
|
currentOutputLine := outputLines[expectedLineIndex]
|
|
str := space.ReplaceAllString(currentOutputLine, " ")
|
|
So(strings.TrimSpace(str), ShouldResemble, expectedLine)
|
|
}
|
|
})
|
|
}
|
|
|
|
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(ctx context.Context, 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(context.Background(), 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.GetImageMeta(manifestDigest)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
for _, imageLayer := range manifestData.Manifests[0].Manifest.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
|
|
}
|