refactor(metadb): improve UX by speeding up metadb serialize/deserialize (#1842)

Use protocol buffers and update the metadb interface to better suit our search needs

Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>
Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
Co-authored-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
LaurentiuNiculae 2023-10-30 22:06:04 +02:00 committed by GitHub
parent f34af3cb3f
commit 56ad9e6707
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 10455 additions and 11676 deletions

View File

@ -38,6 +38,7 @@ jobs:
# Optional: if set to true then the action don't cache or restore ~/go/pkg. # Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true # skip-pkg-cache: true
# skip-pkg-cache: false
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build. # Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true # skip-build-cache: true

1
.gitignore vendored
View File

@ -18,6 +18,7 @@ pkg/extensions/build/
hack/ hack/
.stacker/ .stacker/
oci/ oci/
!pkg/meta/proto/oci
roots/ roots/
bin/ bin/
bazel-* bazel-*

View File

@ -32,6 +32,22 @@ TESTDATA := $(TOP_LEVEL)/test/data
OS ?= $(shell go env GOOS) OS ?= $(shell go env GOOS)
ARCH ?= $(shell go env GOARCH) ARCH ?= $(shell go env GOARCH)
PROTOC := $(TOOLSDIR)/bin/protoc
PROTOC_VERSION := 24.4
GO_PROTOC_VERSION := 1.31.0
HOST_OS := $(shell go env GOOS)
HOST_ARCH := $(shell go env GOARCH)
ifeq ($(HOST_OS),linux)
PROTOC_OS := linux
else ifeq ($(HOST_OS),darwin)
PROTOC_OS := osx
endif
ifeq ($(HOST_ARCH),amd64)
PROTOC_ARCH := x86_64
else ifeq ($(HOST_ARCH),arm64)
PROTOC_ARCH := aarch_64
endif
BENCH_OUTPUT ?= stdout BENCH_OUTPUT ?= stdout
ALL_EXTENSIONS = debug,imagetrust,lint,metrics,mgmt,profile,scrub,search,sync,ui,userprefs ALL_EXTENSIONS = debug,imagetrust,lint,metrics,mgmt,profile,scrub,search,sync,ui,userprefs
EXTENSIONS ?= sync,search,scrub,metrics,lint,ui,mgmt,profile,userprefs,imagetrust EXTENSIONS ?= sync,search,scrub,metrics,lint,ui,mgmt,profile,userprefs,imagetrust
@ -97,6 +113,51 @@ build-metadata: $(if $(findstring ui,$(BUILD_LABELS)), ui)
echo "\n Files: \n" echo "\n Files: \n"
go list -tags $(BUILD_TAGS) -f '{{ join .GoFiles "\n" }}' ./... | sort -u go list -tags $(BUILD_TAGS) -f '{{ join .GoFiles "\n" }}' ./... | sort -u
.PHONY: gen-protobuf
gen-protobuf: check-not-freebds $(PROTOC)
$(PROTOC) --experimental_allow_proto3_optional \
--proto_path=$(TOP_LEVEL)/pkg/meta/proto \
--go_out=$(TOP_LEVEL)/pkg/meta/proto \
--go_opt='Moci/oci.proto=./gen' \
--go_opt='Mmeta/meta.proto=./gen' \
--go_opt='Moci/config.proto=./gen' \
--go_opt='Moci/manifest.proto=./gen' \
--go_opt='Moci/index.proto=./gen' \
--go_opt='Moci/descriptor.proto=./gen' \
--go_opt='Moci/versioned.proto=./gen' \
$(TOP_LEVEL)/pkg/meta/proto/meta/meta.proto
$(PROTOC) --experimental_allow_proto3_optional \
--proto_path=$(TOP_LEVEL)/pkg/meta/proto \
--go_out=$(TOP_LEVEL)/pkg/meta/proto \
--go_opt='Moci/versioned.proto=./gen' \
$(TOP_LEVEL)/pkg/meta/proto/oci/versioned.proto
$(PROTOC) --experimental_allow_proto3_optional \
--proto_path=$(TOP_LEVEL)/pkg/meta/proto \
--go_out=$(TOP_LEVEL)/pkg/meta/proto \
--go_opt='Moci/descriptor.proto=./gen' \
$(TOP_LEVEL)/pkg/meta/proto/oci/descriptor.proto
$(PROTOC) --experimental_allow_proto3_optional \
--proto_path=$(TOP_LEVEL)/pkg/meta/proto \
--go_out=$(TOP_LEVEL)/pkg/meta/proto \
--go_opt='Moci/descriptor.proto=./gen' \
--go_opt='Moci/versioned.proto=./gen' \
--go_opt='Moci/index.proto=./gen' \
$(TOP_LEVEL)/pkg/meta/proto/oci/index.proto
$(PROTOC) --experimental_allow_proto3_optional \
--proto_path=$(TOP_LEVEL)/pkg/meta/proto \
--go_out=$(TOP_LEVEL)/pkg/meta/proto \
--go_opt='Moci/oci.proto=./gen' \
--go_opt='Moci/descriptor.proto=./gen' \
--go_opt='Moci/config.proto=./gen' \
$(TOP_LEVEL)/pkg/meta/proto/oci/config.proto
$(PROTOC) --experimental_allow_proto3_optional \
--proto_path=$(TOP_LEVEL)/pkg/meta/proto \
--go_out=$(TOP_LEVEL)/pkg/meta/proto \
--go_opt='Moci/versioned.proto=./gen' \
--go_opt='Moci/descriptor.proto=./gen' \
--go_opt='Moci/manifest.proto=./gen' \
$(TOP_LEVEL)/pkg/meta/proto/oci/manifest.proto
.PHONY: binary-minimal .PHONY: binary-minimal
binary-minimal: EXTENSIONS= binary-minimal: EXTENSIONS=
binary-minimal: modcheck build-metadata binary-minimal: modcheck build-metadata
@ -218,6 +279,13 @@ $(CRICTL):
mv crictl $(TOOLSDIR)/bin/crictl mv crictl $(TOOLSDIR)/bin/crictl
chmod +x $(TOOLSDIR)/bin/crictl chmod +x $(TOOLSDIR)/bin/crictl
$(PROTOC):
mkdir -p $(TOOLSDIR)/bin
curl -Lo protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/protoc-$(PROTOC_VERSION)-$(PROTOC_OS)-$(PROTOC_ARCH).zip
unzip -o -d $(TOOLSDIR) protoc.zip bin/protoc
rm protoc.zip
chmod +x $(PROTOC)
go install google.golang.org/protobuf/cmd/protoc-gen-go@v$(GO_PROTOC_VERSION)
$(ACTION_VALIDATOR): $(ACTION_VALIDATOR):
mkdir -p $(TOOLSDIR)/bin mkdir -p $(TOOLSDIR)/bin
@ -515,6 +583,12 @@ ifneq ($(shell go env GOOS),linux)
$(error makefile target can be run only on linux) $(error makefile target can be run only on linux)
endif endif
.PHONY: check-not-freebds
check-not-freebds:
ifneq ($(shell go env GOOS),freebsd)
$(error makefile target can't be run on freebsd)
endif
.PHONY: check-compatibility .PHONY: check-compatibility
check-compatibility: check-compatibility:
ifeq ($(OS),freebsd) ifeq ($(OS),freebsd)

View File

@ -6,3 +6,4 @@ ignore:
- "./pkg/test/mocks/*.go" - "./pkg/test/mocks/*.go"
- "./swagger/*.go" - "./swagger/*.go"
- "./pkg/test/test_http_server.go" - "./pkg/test/test_http_server.go"
- "./pkg/meta/proto/gen/*.go"

View File

@ -107,8 +107,8 @@ var (
ErrBadLayerCount = errors.New("manifest: layers count doesn't correspond to config history") ErrBadLayerCount = errors.New("manifest: layers count doesn't correspond to config history")
ErrManifestConflict = errors.New("manifest: multiple manifests found") ErrManifestConflict = errors.New("manifest: multiple manifests found")
ErrManifestMetaNotFound = errors.New("metadb: image metadata not found for given manifest reference") ErrManifestMetaNotFound = errors.New("metadb: image metadata not found for given manifest reference")
ErrManifestDataNotFound = errors.New("metadb: image data not found for given manifest digest") ErrImageMetaNotFound = errors.New("metadb: image meta not found")
ErrIndexDataNotFount = errors.New("metadb: index data not found for given digest") ErrUnexpectedMediaType = errors.New("metadb: got unexpected media type")
ErrRepoMetaNotFound = errors.New("metadb: repo metadata not found for given repo name") ErrRepoMetaNotFound = errors.New("metadb: repo metadata not found for given repo name")
ErrTagMetaNotFound = errors.New("metadb: tag metadata not found for given repo and tag names") ErrTagMetaNotFound = errors.New("metadb: tag metadata not found for given repo and tag names")
ErrTypeAssertionFailed = errors.New("storage: failed DatabaseDriver type assertion") ErrTypeAssertionFailed = errors.New("storage: failed DatabaseDriver type assertion")
@ -163,4 +163,5 @@ var (
ErrInvalidOutputFormat = errors.New("cli: invalid output format") ErrInvalidOutputFormat = errors.New("cli: invalid output format")
ErrFlagValueUnsupported = errors.New("supported values ") ErrFlagValueUnsupported = errors.New("supported values ")
ErrUnknownSubcommand = errors.New("cli: unknown subcommand") ErrUnknownSubcommand = errors.New("cli: unknown subcommand")
ErrMultipleReposSameName = errors.New("test: can't have multiple repos with the same name")
) )

View File

@ -18,7 +18,8 @@
"region": "us-east-2", "region": "us-east-2",
"cacheTablename": "ZotBlobTable", "cacheTablename": "ZotBlobTable",
"repoMetaTablename": "ZotRepoMetadataTable", "repoMetaTablename": "ZotRepoMetadataTable",
"manifestDataTablename": "ZotManifestDataTable", "imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"versionTablename": "ZotVersion" "versionTablename": "ZotVersion"
} }
}, },

View File

@ -19,7 +19,8 @@
"region": "us-east-2", "region": "us-east-2",
"cacheTablename": "ZotBlobTable", "cacheTablename": "ZotBlobTable",
"repoMetaTablename": "ZotRepoMetadataTable", "repoMetaTablename": "ZotRepoMetadataTable",
"manifestDataTablename": "ZotManifestDataTable", "imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable", "userDataTablename": "ZotUserDataTable",
"versionTablename": "ZotVersion" "versionTablename": "ZotVersion"
} }

2
go.mod
View File

@ -500,7 +500,7 @@ require (
google.golang.org/appengine v1.6.8 // indirect google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/grpc v1.58.2 // indirect google.golang.org/grpc v1.58.2 // indirect
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/protobuf v1.31.0
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect

View File

@ -148,7 +148,8 @@ func TestCreateCacheDatabaseDriver(t *testing.T) {
"region": "us-east-2", "region": "us-east-2",
"cacheTablename": "BlobTable", "cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable", "repoMetaTablename": "RepoMetadataTable",
"manifestDataTablename": "ManifestDataTable", "imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable", "userDataTablename": "ZotUserDataTable",
"versionTablename": "Version", "versionTablename": "Version",
} }
@ -163,7 +164,8 @@ func TestCreateCacheDatabaseDriver(t *testing.T) {
"region": "us-east-2", "region": "us-east-2",
"cacheTablename": "BlobTable", "cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable", "repoMetaTablename": "RepoMetadataTable",
"manifestDataTablename": "ManifestDataTable", "imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable", "userDataTablename": "ZotUserDataTable",
"versionTablename": "Version", "versionTablename": "Version",
} }
@ -177,7 +179,8 @@ func TestCreateCacheDatabaseDriver(t *testing.T) {
"region": "us-east-2", "region": "us-east-2",
"cacheTablename": "BlobTable", "cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable", "repoMetaTablename": "RepoMetadataTable",
"manifestDataTablename": "ManifestDataTable", "imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable", "userDataTablename": "ZotUserDataTable",
"versionTablename": "Version", "versionTablename": "Version",
} }
@ -210,7 +213,8 @@ func TestCreateMetaDBDriver(t *testing.T) {
"region": "us-east-2", "region": "us-east-2",
"cachetablename": "BlobTable", "cachetablename": "BlobTable",
"repometatablename": "RepoMetadataTable", "repometatablename": "RepoMetadataTable",
"manifestdatatablename": "ManifestDataTable", "imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userdatatablename": "UserDatatable", "userdatatablename": "UserDatatable",
} }
@ -223,7 +227,8 @@ func TestCreateMetaDBDriver(t *testing.T) {
"region": "us-east-2", "region": "us-east-2",
"cachetablename": "", "cachetablename": "",
"repometatablename": "RepoMetadataTable", "repometatablename": "RepoMetadataTable",
"manifestdatatablename": "ManifestDataTable", "imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable", "userDataTablename": "ZotUserDataTable",
"versiontablename": 1, "versiontablename": 1,
} }
@ -237,8 +242,8 @@ func TestCreateMetaDBDriver(t *testing.T) {
"region": "us-east-2", "region": "us-east-2",
"cachetablename": "test", "cachetablename": "test",
"repometatablename": "RepoMetadataTable", "repometatablename": "RepoMetadataTable",
"manifestdatatablename": "ManifestDataTable", "imagemetatablename": "ZotImageMetaTable",
"indexdatatablename": "IndexDataTable", "repoblobsinfotablename": "ZotRepoBlobsInfoTable",
"userdatatablename": "ZotUserDataTable", "userdatatablename": "ZotUserDataTable",
"apikeytablename": "APIKeyTable", "apikeytablename": "APIKeyTable",
"versiontablename": "1", "versiontablename": "1",
@ -419,8 +424,8 @@ func TestObjectStorageController(t *testing.T) {
"region": "us-east-2", "region": "us-east-2",
"cachetablename": "test", "cachetablename": "test",
"repometatablename": "RepoMetadataTable", "repometatablename": "RepoMetadataTable",
"manifestdatatablename": "ManifestDataTable", "imagemetatablename": "ZotImageMetaTable",
"indexdatatablename": "IndexDataTable", "repoblobsinfotablename": "ZotRepoBlobsInfoTable",
"userdatatablename": "ZotUserDataTable", "userdatatablename": "ZotUserDataTable",
"apikeytablename": "APIKeyTable1", "apikeytablename": "APIKeyTable1",
"versiontablename": "Version", "versiontablename": "Version",
@ -7773,6 +7778,8 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
} }
func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) { func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
ctx := context.Background()
Convey("Make controller", t, func() { Convey("Make controller", t, func() {
Convey("Garbage collect signatures without subject and manifests without tags", func(c C) { Convey("Garbage collect signatures without subject and manifests without tags", func(c C) {
repoName := "testrepo" //nolint:goconst repoName := "testrepo" //nolint:goconst
@ -7804,7 +7811,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
ctlr.Config.Storage.Dedupe = false ctlr.Config.Storage.Dedupe = false
cm := test.NewControllerManager(ctlr) cm := test.NewControllerManager(ctlr)
cm.StartServer() cm.StartServer() //nolint: contextcheck
cm.WaitServerToBeReady(port) cm.WaitServerToBeReady(port)
defer cm.StopServer() defer cm.StopServer()
@ -7835,7 +7842,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
// generate a keypair // generate a keypair
os.Setenv("COSIGN_PASSWORD", "") os.Setenv("COSIGN_PASSWORD", "")
err = generate.GenerateKeyPairCmd(context.TODO(), "", "cosign", nil) err = generate.GenerateKeyPairCmd(ctx, "", "cosign", nil)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image := fmt.Sprintf("localhost:%s/%s@%s", port, repoName, digest.String()) image := fmt.Sprintf("localhost:%s/%s@%s", port, repoName, digest.String())
@ -7864,7 +7871,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
// sign the image // sign the image
err = signature.SignWithNotation("good", image, tdir, true) err = signature.SignWithNotation("good", image, tdir, true) //nolint: contextcheck
So(err, ShouldBeNil) So(err, ShouldBeNil)
// get cosign signature manifest // get cosign signature manifest
@ -7894,7 +7901,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
// make sure both signatures are stored in repodb // make sure both signatures are stored in repodb
repoMeta, err := ctlr.MetaDB.GetRepoMeta(repoName) repoMeta, err := ctlr.MetaDB.GetRepoMeta(ctx, repoName)
So(err, ShouldBeNil) So(err, ShouldBeNil)
sigMeta := repoMeta.Signatures[digest.String()] sigMeta := repoMeta.Signatures[digest.String()]
@ -7955,7 +7962,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
// make sure repoDB reference was added // make sure repoDB reference was added
repoMeta, err := ctlr.MetaDB.GetRepoMeta(repoName) repoMeta, err := ctlr.MetaDB.GetRepoMeta(ctx, repoName)
So(err, ShouldBeNil) So(err, ShouldBeNil)
_, ok := repoMeta.Referrers[untaggedManifestDigest.String()] _, ok := repoMeta.Referrers[untaggedManifestDigest.String()]
@ -7984,8 +7991,8 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
err = gc.CleanRepo(repoName) err = gc.CleanRepo(repoName)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// make sure both signatures are removed from repodb and repo reference for untagged is removed // make sure both signatures are removed from metaDB and repo reference for untagged is removed
repoMeta, err = ctlr.MetaDB.GetRepoMeta(repoName) repoMeta, err = ctlr.MetaDB.GetRepoMeta(ctx, repoName)
So(err, ShouldBeNil) So(err, ShouldBeNil)
sigMeta := repoMeta.Signatures[digest.String()] sigMeta := repoMeta.Signatures[digest.String()]

View File

@ -516,7 +516,7 @@ func (rh *RouteHandler) GetManifest(response http.ResponseWriter, request *http.
} }
if rh.c.MetaDB != nil { if rh.c.MetaDB != nil {
err := meta.OnGetManifest(name, reference, content, rh.c.StoreController, rh.c.MetaDB, rh.c.Log) err := meta.OnGetManifest(name, reference, mediaType, content, rh.c.StoreController, rh.c.MetaDB, rh.c.Log)
if err != nil { if err != nil {
response.WriteHeader(http.StatusInternalServerError) response.WriteHeader(http.StatusInternalServerError)

View File

@ -6,7 +6,6 @@ package client_test
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -733,7 +732,7 @@ func getMockCveScanner(metaDB mTypes.MetaDB) cveinfo.Scanner {
imageDir := repo imageDir := repo
inputTag := reference inputTag := reference
repoMeta, err := metaDB.GetRepoMeta(imageDir) repoMeta, err := metaDB.GetRepoMeta(context.Background(), imageDir)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -756,19 +755,12 @@ func getMockCveScanner(metaDB mTypes.MetaDB) cveinfo.Scanner {
return false, err return false, err
} }
manifestData, err := metaDB.GetManifestData(manifestDigest) manifestData, err := metaDB.GetImageMeta(manifestDigest)
if err != nil { if err != nil {
return false, err return false, err
} }
var manifestContent ispec.Manifest for _, imageLayer := range manifestData.Manifests[0].Manifest.Layers {
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
return false, zerr.ErrScanNotSupported
}
for _, imageLayer := range manifestContent.Layers {
switch imageLayer.MediaType { switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer): case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):

View File

@ -29,6 +29,12 @@ const (
ArtifactTypeNotation = "application/vnd.cncf.notary.signature" ArtifactTypeNotation = "application/vnd.cncf.notary.signature"
) )
var cosignTagRule = regexp.MustCompile(`sha256\-.+\.sig`)
func IsCosignTag(tag string) bool {
return cosignTagRule.MatchString(tag)
}
func Contains[T comparable](elems []T, v T) bool { func Contains[T comparable](elems []T, v T) bool {
for _, s := range elems { for _, s := range elems {
if v == s { if v == s {

View File

@ -131,11 +131,11 @@ func TestSignatureUploadAndVerificationAWS(t *testing.T) {
cacheTablename := "BlobTable" + uuid.String() cacheTablename := "BlobTable" + uuid.String()
repoMetaTablename := "RepoMetadataTable" + uuid.String() repoMetaTablename := "RepoMetadataTable" + uuid.String()
manifestDataTablename := "ManifestDataTable" + uuid.String()
versionTablename := "Version" + uuid.String() versionTablename := "Version" + uuid.String()
indexDataTablename := "IndexDataTable" + uuid.String()
userDataTablename := "UserDataTable" + uuid.String() userDataTablename := "UserDataTable" + uuid.String()
apiKeyTablename := "ApiKeyTable" + uuid.String() apiKeyTablename := "ApiKeyTable" + uuid.String()
imageMetaTablename := "imageMetaTable" + uuid.String()
repoBlobsInfoTablename := "repoBlobsInfoTable" + uuid.String()
cacheDriverParams := map[string]interface{}{ cacheDriverParams := map[string]interface{}{
"name": "dynamoDB", "name": "dynamoDB",
@ -143,8 +143,8 @@ func TestSignatureUploadAndVerificationAWS(t *testing.T) {
"region": "us-east-2", "region": "us-east-2",
"cacheTablename": cacheTablename, "cacheTablename": cacheTablename,
"repoMetaTablename": repoMetaTablename, "repoMetaTablename": repoMetaTablename,
"manifestDataTablename": manifestDataTablename, "imageMetaTablename": imageMetaTablename,
"indexDataTablename": indexDataTablename, "repoBlobsInfoTablename": repoBlobsInfoTablename,
"userDataTablename": userDataTablename, "userDataTablename": userDataTablename,
"apiKeyTablename": apiKeyTablename, "apiKeyTablename": apiKeyTablename,
"versionTablename": versionTablename, "versionTablename": versionTablename,

View File

@ -5,7 +5,6 @@ package imagetrust
import ( import (
"context" "context"
"encoding/json"
"time" "time"
"github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws"
@ -158,18 +157,13 @@ func IsResourceExistsException(err error) bool {
} }
func (imgTrustStore *ImageTrustStore) VerifySignature( func (imgTrustStore *ImageTrustStore) VerifySignature(
signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, manifestContent []byte, signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, imageMeta mTypes.ImageMeta,
repo string, repo string,
) (string, time.Time, bool, error) { ) (string, time.Time, bool, error) {
var manifest ispec.Manifest
if err := json.Unmarshal(manifestContent, &manifest); err != nil {
return "", time.Time{}, false, err
}
desc := ispec.Descriptor{ desc := ispec.Descriptor{
MediaType: manifest.MediaType, MediaType: imageMeta.MediaType,
Digest: manifestDigest, Digest: imageMeta.Digest,
Size: int64(len(manifestContent)), Size: imageMeta.Size,
} }
if manifestDigest.String() == "" { if manifestDigest.String() == "" {
@ -190,7 +184,7 @@ func (imgTrustStore *ImageTrustStore) VerifySignature(
func NewTaskGenerator(metaDB mTypes.MetaDB, log log.Logger) scheduler.TaskGenerator { func NewTaskGenerator(metaDB mTypes.MetaDB, log log.Logger) scheduler.TaskGenerator {
return &sigValidityTaskGenerator{ return &sigValidityTaskGenerator{
repos: []mTypes.RepoMetadata{}, repos: []mTypes.RepoMeta{},
metaDB: metaDB, metaDB: metaDB,
repoIndex: -1, repoIndex: -1,
log: log, log: log,
@ -198,7 +192,7 @@ func NewTaskGenerator(metaDB mTypes.MetaDB, log log.Logger) scheduler.TaskGenera
} }
type sigValidityTaskGenerator struct { type sigValidityTaskGenerator struct {
repos []mTypes.RepoMetadata repos []mTypes.RepoMeta
metaDB mTypes.MetaDB metaDB mTypes.MetaDB
repoIndex int repoIndex int
done bool done bool
@ -209,7 +203,7 @@ func (gen *sigValidityTaskGenerator) Next() (scheduler.Task, error) {
if len(gen.repos) == 0 { if len(gen.repos) == 0 {
ctx := context.Background() ctx := context.Background()
repos, err := gen.metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMetadata) bool { repos, err := gen.metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool {
return true return true
}) })
if err != nil { if err != nil {
@ -243,18 +237,18 @@ func (gen *sigValidityTaskGenerator) IsReady() bool {
func (gen *sigValidityTaskGenerator) Reset() { func (gen *sigValidityTaskGenerator) Reset() {
gen.done = false gen.done = false
gen.repoIndex = -1 gen.repoIndex = -1
gen.repos = []mTypes.RepoMetadata{} gen.repos = []mTypes.RepoMeta{}
gen.log.Info().Msg("finished resetting task generator for updating signatures validity") gen.log.Info().Msg("finished resetting task generator for updating signatures validity")
} }
type validityTask struct { type validityTask struct {
metaDB mTypes.MetaDB metaDB mTypes.MetaDB
repo mTypes.RepoMetadata repo mTypes.RepoMeta
log log.Logger log log.Logger
} }
func NewValidityTask(metaDB mTypes.MetaDB, repo mTypes.RepoMetadata, log log.Logger) *validityTask { func NewValidityTask(metaDB mTypes.MetaDB, repo mTypes.RepoMeta, log log.Logger) *validityTask {
return &validityTask{metaDB, repo, log} return &validityTask{metaDB, repo, log}
} }

View File

@ -7,6 +7,8 @@ import (
"time" "time"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
mTypes "zotregistry.io/zot/pkg/meta/types"
) )
func NewLocalImageTrustStore(dir string) (*imageTrustDisabled, error) { func NewLocalImageTrustStore(dir string) (*imageTrustDisabled, error) {
@ -20,7 +22,7 @@ func NewAWSImageTrustStore(region, endpoint string) (*imageTrustDisabled, error)
type imageTrustDisabled struct{} type imageTrustDisabled struct{}
func (imgTrustStore *imageTrustDisabled) VerifySignature( func (imgTrustStore *imageTrustDisabled) VerifySignature(
signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, manifestContent []byte, signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, imageMeta mTypes.ImageMeta,
repo string, repo string,
) (string, time.Time, bool, error) { ) (string, time.Time, bool, error) {
return "", time.Time{}, false, nil return "", time.Time{}, false, nil

View File

@ -27,15 +27,13 @@ func TestImageTrust(t *testing.T) {
repo := "repo" repo := "repo"
image := CreateRandomImage() //nolint:staticcheck image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
manifestDigest := image.ManifestDescriptor.Digest
localImgTrustStore, err := imagetrust.NewLocalImageTrustStore(rootDir) localImgTrustStore, err := imagetrust.NewLocalImageTrustStore(rootDir)
So(err, ShouldBeNil) So(err, ShouldBeNil)
author, expTime, ok, err := localImgTrustStore.VerifySignature("cosign", author, expTime, ok, err := localImgTrustStore.VerifySignature("cosign",
[]byte(""), "", manifestDigest, manifestContent, repo, []byte(""), "", image.Digest(), image.AsImageMeta(), repo,
) )
So(author, ShouldBeEmpty) So(author, ShouldBeEmpty)
So(expTime, ShouldBeZeroValue) So(expTime, ShouldBeZeroValue)
@ -54,7 +52,7 @@ func TestImageTrust(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
author, expTime, ok, err = cloudImgTrustStore.VerifySignature("cosign", author, expTime, ok, err = cloudImgTrustStore.VerifySignature("cosign",
[]byte(""), "", manifestDigest, manifestContent, repo, []byte(""), "", image.Digest(), image.AsImageMeta(), repo,
) )
So(author, ShouldBeEmpty) So(author, ShouldBeEmpty)
So(expTime, ShouldBeZeroValue) So(expTime, ShouldBeZeroValue)

View File

@ -150,31 +150,21 @@ func TestInitCosignAndNotationDirs(t *testing.T) {
} }
func TestVerifySignatures(t *testing.T) { func TestVerifySignatures(t *testing.T) {
Convey("wrong manifest content", t, func() {
manifestContent := []byte("wrong json")
imgTrustStore := &imagetrust.ImageTrustStore{}
_, _, _, err := imgTrustStore.VerifySignature("", []byte(""), "", "", manifestContent, "repo")
So(err, ShouldNotBeNil)
})
Convey("empty manifest digest", t, func() { Convey("empty manifest digest", t, func() {
image := CreateRandomImage() image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
imgTrustStore := &imagetrust.ImageTrustStore{} imgTrustStore := &imagetrust.ImageTrustStore{}
_, _, _, err := imgTrustStore.VerifySignature("", []byte(""), "", "", manifestContent, "repo") _, _, _, err := imgTrustStore.VerifySignature("", []byte(""), "", "", image.AsImageMeta(), "repo")
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(err, ShouldEqual, zerr.ErrBadManifestDigest) So(err, ShouldEqual, zerr.ErrBadManifestDigest)
}) })
Convey("wrong signature type", t, func() { Convey("wrong signature type", t, func() {
image := CreateRandomImage() image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
manifestDigest := image.ManifestDescriptor.Digest
imgTrustStore := &imagetrust.ImageTrustStore{} imgTrustStore := &imagetrust.ImageTrustStore{}
_, _, _, err := imgTrustStore.VerifySignature("wrongType", []byte(""), "", manifestDigest, manifestContent, "repo") _, _, _, err := imgTrustStore.VerifySignature("wrongType", []byte(""), "", image.Digest(), image.AsImageMeta(),
"repo")
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(err, ShouldEqual, zerr.ErrInvalidSignatureType) So(err, ShouldEqual, zerr.ErrInvalidSignatureType)
}) })
@ -184,15 +174,13 @@ func TestVerifySignatures(t *testing.T) {
tag := "test" //nolint:goconst tag := "test" //nolint:goconst
image := CreateRandomImage() image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
manifestDigest := image.ManifestDescriptor.Digest
Convey("cosignDir is not set", func() { Convey("cosignDir is not set", func() {
imgTrustStore := &imagetrust.ImageTrustStore{ imgTrustStore := &imagetrust.ImageTrustStore{
CosignStorage: &imagetrust.PublicKeyLocalStorage{}, CosignStorage: &imagetrust.PublicKeyLocalStorage{},
} }
_, _, _, err := imgTrustStore.VerifySignature("cosign", []byte(""), "", manifestDigest, manifestContent, repo) _, _, _, err := imgTrustStore.VerifySignature("cosign", []byte(""), "", image.Digest(), image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(err, ShouldEqual, zerr.ErrSignConfigDirNotSet) So(err, ShouldEqual, zerr.ErrSignConfigDirNotSet)
}) })
@ -212,7 +200,7 @@ func TestVerifySignatures(t *testing.T) {
CosignStorage: pubKeyStorage, CosignStorage: pubKeyStorage,
} }
_, _, _, err = imgTrustStore.VerifySignature("cosign", []byte(""), "", manifestDigest, manifestContent, repo) _, _, _, err = imgTrustStore.VerifySignature("cosign", []byte(""), "", image.Digest(), image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
@ -232,8 +220,8 @@ func TestVerifySignatures(t *testing.T) {
CosignStorage: pubKeyStorage, CosignStorage: pubKeyStorage,
} }
_, _, isTrusted, err := imgTrustStore.VerifySignature("cosign", []byte(""), "", manifestDigest, _, _, isTrusted, err := imgTrustStore.VerifySignature("cosign", []byte(""), "", image.Digest(), image.AsImageMeta(),
manifestContent, repo) repo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(isTrusted, ShouldBeFalse) So(isTrusted, ShouldBeFalse)
}) })
@ -282,7 +270,7 @@ func TestVerifySignatures(t *testing.T) {
AnnotationOptions: options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", tag)}}, AnnotationOptions: options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", tag)}},
Upload: true, Upload: true,
}, },
[]string{fmt.Sprintf("localhost:%s/%s@%s", port, repo, manifestDigest.String())}) []string{fmt.Sprintf("localhost:%s/%s@%s", port, repo, image.DigestStr())})
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = os.Remove(path.Join(cosignDir, "cosign.key")) err = os.Remove(path.Join(cosignDir, "cosign.key"))
@ -299,7 +287,7 @@ func TestVerifySignatures(t *testing.T) {
var sigKey string var sigKey string
for _, manifest := range index.Manifests { for _, manifest := range index.Manifests {
if manifest.Digest != manifestDigest { if manifest.Digest != image.Digest() {
blobContent, err := ctlr.StoreController.DefaultStore.GetBlobContent(repo, manifest.Digest) blobContent, err := ctlr.StoreController.DefaultStore.GetBlobContent(repo, manifest.Digest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -320,8 +308,8 @@ func TestVerifySignatures(t *testing.T) {
} }
// signature is trusted // signature is trusted
author, _, isTrusted, err := imgTrustStore.VerifySignature("cosign", rawSignature, sigKey, manifestDigest, author, _, isTrusted, err := imgTrustStore.VerifySignature("cosign", rawSignature, sigKey, image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(isTrusted, ShouldBeTrue) So(isTrusted, ShouldBeTrue)
So(author, ShouldNotBeEmpty) So(author, ShouldNotBeEmpty)
@ -332,16 +320,14 @@ func TestVerifySignatures(t *testing.T) {
repo := "repo" //nolint:goconst repo := "repo" //nolint:goconst
tag := "test" //nolint:goconst tag := "test" //nolint:goconst
image := CreateRandomImage() image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
manifestDigest := image.ManifestDescriptor.Digest
Convey("notationDir is not set", func() { Convey("notationDir is not set", func() {
imgTrustStore := &imagetrust.ImageTrustStore{ imgTrustStore := &imagetrust.ImageTrustStore{
NotationStorage: &imagetrust.CertificateLocalStorage{}, NotationStorage: &imagetrust.CertificateLocalStorage{},
} }
_, _, _, err := imgTrustStore.VerifySignature("notation", []byte("signature"), "", manifestDigest, _, _, _, err := imgTrustStore.VerifySignature("notation", []byte("signature"), "", image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(err, ShouldEqual, zerr.ErrSignConfigDirNotSet) So(err, ShouldEqual, zerr.ErrSignConfigDirNotSet)
}) })
@ -356,8 +342,8 @@ func TestVerifySignatures(t *testing.T) {
NotationStorage: certStorage, NotationStorage: certStorage,
} }
_, _, isTrusted, err := imgTrustStore.VerifySignature("notation", []byte(""), "", manifestDigest, _, _, isTrusted, err := imgTrustStore.VerifySignature("notation", []byte(""), "", image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(isTrusted, ShouldBeFalse) So(isTrusted, ShouldBeFalse)
}) })
@ -377,8 +363,8 @@ func TestVerifySignatures(t *testing.T) {
NotationStorage: certStorage, NotationStorage: certStorage,
} }
_, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", manifestDigest, _, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
@ -399,8 +385,8 @@ func TestVerifySignatures(t *testing.T) {
NotationStorage: certStorage, NotationStorage: certStorage,
} }
_, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", manifestDigest, manifestContent, _, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", image.Digest(),
repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
@ -437,10 +423,10 @@ func TestVerifySignatures(t *testing.T) {
err = signature.GenerateNotationCerts(notationDir, "notation-sign-test") err = signature.GenerateNotationCerts(notationDir, "notation-sign-test")
So(err, ShouldBeNil) So(err, ShouldBeNil)
// sign the image // sign the imageURL
image := fmt.Sprintf("localhost:%s/%s", port, fmt.Sprintf("%s:%s", repo, tag)) imageURL := fmt.Sprintf("localhost:%s/%s", port, fmt.Sprintf("%s:%s", repo, tag))
err = signature.SignWithNotation("notation-sign-test", image, notationDir, true) err = signature.SignWithNotation("notation-sign-test", imageURL, notationDir, true)
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = test.CopyFiles(path.Join(notationDir, "notation", "truststore"), path.Join(notationDir, "truststore")) err = test.CopyFiles(path.Join(notationDir, "notation", "truststore"), path.Join(notationDir, "truststore"))
@ -481,7 +467,7 @@ func TestVerifySignatures(t *testing.T) {
var sigKey string var sigKey string
for _, manifest := range index.Manifests { for _, manifest := range index.Manifests {
if manifest.Digest != manifestDigest { if manifest.Digest != image.Digest() {
blobContent, err := ctlr.StoreController.DefaultStore.GetBlobContent(repo, manifest.Digest) blobContent, err := ctlr.StoreController.DefaultStore.GetBlobContent(repo, manifest.Digest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -502,8 +488,8 @@ func TestVerifySignatures(t *testing.T) {
} }
// signature is trusted // signature is trusted
author, _, isTrusted, err := imgTrustStore.VerifySignature("notation", rawSignature, sigKey, manifestDigest, author, _, isTrusted, err := imgTrustStore.VerifySignature("notation", rawSignature, sigKey, image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(isTrusted, ShouldBeTrue) So(isTrusted, ShouldBeTrue)
So(author, ShouldNotBeEmpty) So(author, ShouldNotBeEmpty)
@ -512,8 +498,8 @@ func TestVerifySignatures(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
// signature is not trusted // signature is not trusted
author, _, isTrusted, err = imgTrustStore.VerifySignature("notation", rawSignature, sigKey, manifestDigest, author, _, isTrusted, err = imgTrustStore.VerifySignature("notation", rawSignature, sigKey, image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(isTrusted, ShouldBeFalse) So(isTrusted, ShouldBeFalse)
So(author, ShouldNotBeEmpty) So(author, ShouldNotBeEmpty)
@ -977,9 +963,6 @@ func TestAWSTrustStore(t *testing.T) {
repo := "repo" repo := "repo"
image := CreateRandomImage() image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
manifestDigest := image.ManifestDescriptor.Digest
secretsManagerMock := mocks.SecretsManagerMock{ secretsManagerMock := mocks.SecretsManagerMock{
CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput, CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput,
optFns ...func(*secretsmanager.Options), optFns ...func(*secretsmanager.Options),
@ -1001,8 +984,8 @@ func TestAWSTrustStore(t *testing.T) {
NotationStorage: notationStorage, NotationStorage: notationStorage,
} }
_, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", manifestDigest, _, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
@ -1010,9 +993,6 @@ func TestAWSTrustStore(t *testing.T) {
repo := "repo" repo := "repo"
image := CreateRandomImage() image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
manifestDigest := image.ManifestDescriptor.Digest
secretsManagerMock := mocks.SecretsManagerMock{ secretsManagerMock := mocks.SecretsManagerMock{
CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput, CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput,
optFns ...func(*secretsmanager.Options), optFns ...func(*secretsmanager.Options),
@ -1034,8 +1014,8 @@ func TestAWSTrustStore(t *testing.T) {
NotationStorage: notationStorage, NotationStorage: notationStorage,
} }
_, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", manifestDigest, _, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
secretsManagerCacheMock = mocks.SecretsManagerCacheMock{ secretsManagerCacheMock = mocks.SecretsManagerCacheMock{
@ -1051,8 +1031,8 @@ func TestAWSTrustStore(t *testing.T) {
NotationStorage: notationStorage, NotationStorage: notationStorage,
} }
_, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", manifestDigest, _, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
secretsManagerCacheMock = mocks.SecretsManagerCacheMock{ secretsManagerCacheMock = mocks.SecretsManagerCacheMock{
@ -1068,8 +1048,8 @@ func TestAWSTrustStore(t *testing.T) {
NotationStorage: notationStorage, NotationStorage: notationStorage,
} }
_, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", manifestDigest, _, _, _, err = imgTrustStore.VerifySignature("notation", []byte("signature"), "", image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
@ -1080,19 +1060,19 @@ func TestAWSTrustStore(t *testing.T) {
} }
repoMetaTablename := "RepoMetadataTable" + uuid.String() repoMetaTablename := "RepoMetadataTable" + uuid.String()
manifestDataTablename := "ManifestDataTable" + uuid.String()
versionTablename := "Version" + uuid.String() versionTablename := "Version" + uuid.String()
indexDataTablename := "IndexDataTable" + uuid.String()
userDataTablename := "UserDataTable" + uuid.String() userDataTablename := "UserDataTable" + uuid.String()
apiKeyTablename := "ApiKeyTable" + uuid.String() apiKeyTablename := "ApiKeyTable" + uuid.String()
imageMetaTablename := "imageMetaTable" + uuid.String()
repoBlobsInfoTablename := "repoBlobsInfoTable" + uuid.String()
dynamoDBDriverParams := map[string]interface{}{ dynamoDBDriverParams := map[string]interface{}{
"name": "dynamoDB", "name": "dynamoDB",
"endpoint": os.Getenv("DYNAMODBMOCK_ENDPOINT"), "endpoint": os.Getenv("DYNAMODBMOCK_ENDPOINT"),
"region": "us-east-2", "region": "us-east-2",
"repometatablename": repoMetaTablename, "repometatablename": repoMetaTablename,
"manifestdatatablename": manifestDataTablename, "imagemetatablename": imageMetaTablename,
"indexdatatablename": indexDataTablename, "repoblobsinfotablename": repoBlobsInfoTablename,
"userdatatablename": userDataTablename, "userdatatablename": userDataTablename,
"apikeytablename": apiKeyTablename, "apikeytablename": apiKeyTablename,
"versiontablename": versionTablename, "versiontablename": versionTablename,
@ -1237,8 +1217,6 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
Convey("verify cosign signature is trusted", func() { Convey("verify cosign signature is trusted", func() {
image := CreateRandomImage() image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
manifestDigest := image.ManifestDescriptor.Digest
err = UploadImage(image, baseURL, repo, tag) err = UploadImage(image, baseURL, repo, tag)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -1264,7 +1242,7 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
AnnotationOptions: options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", tag)}}, AnnotationOptions: options.AnnotationOptions{Annotations: []string{fmt.Sprintf("tag=%s", tag)}},
Upload: true, Upload: true,
}, },
[]string{fmt.Sprintf("localhost:%s/%s@%s", port, repo, manifestDigest.String())}) []string{fmt.Sprintf("localhost:%s/%s@%s", port, repo, image.DigestStr())})
So(err, ShouldBeNil) So(err, ShouldBeNil)
indexContent, err := ctlr.StoreController.DefaultStore.GetIndexContent(repo) indexContent, err := ctlr.StoreController.DefaultStore.GetIndexContent(repo)
@ -1278,7 +1256,7 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
var sigKey string var sigKey string
for _, manifest := range index.Manifests { for _, manifest := range index.Manifests {
if manifest.Digest != manifestDigest { if manifest.Digest != image.Digest() {
blobContent, err := ctlr.StoreController.DefaultStore.GetBlobContent(repo, manifest.Digest) blobContent, err := ctlr.StoreController.DefaultStore.GetBlobContent(repo, manifest.Digest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -1308,8 +1286,8 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
imageTrustStore := ctlr.MetaDB.ImageTrustStore() imageTrustStore := ctlr.MetaDB.ImageTrustStore()
// signature is trusted // signature is trusted
author, _, isTrusted, err := imageTrustStore.VerifySignature("cosign", rawSignature, sigKey, manifestDigest, author, _, isTrusted, err := imageTrustStore.VerifySignature("cosign", rawSignature, sigKey, image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(isTrusted, ShouldBeTrue) So(isTrusted, ShouldBeTrue)
So(author, ShouldNotBeEmpty) So(author, ShouldNotBeEmpty)
@ -1317,8 +1295,6 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
Convey("verify notation signature is trusted", func() { Convey("verify notation signature is trusted", func() {
image := CreateRandomImage() image := CreateRandomImage()
manifestContent := image.ManifestDescriptor.Data
manifestDigest := image.ManifestDescriptor.Digest
err = UploadImage(image, baseURL, repo, tag) err = UploadImage(image, baseURL, repo, tag)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -1366,7 +1342,7 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
t.Logf("Processing manifest %v", notationSig) t.Logf("Processing manifest %v", notationSig)
if notationSig.Config.MediaType != notreg.ArtifactTypeNotation || if notationSig.Config.MediaType != notreg.ArtifactTypeNotation ||
notationSig.Subject.Digest != manifestDigest { notationSig.Subject.Digest != image.Digest() {
continue continue
} }
@ -1400,8 +1376,8 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
imageTrustStore := ctlr.MetaDB.ImageTrustStore() imageTrustStore := ctlr.MetaDB.ImageTrustStore()
// signature is trusted // signature is trusted
author, _, isTrusted, err := imageTrustStore.VerifySignature("notation", rawSignature, sigKey, manifestDigest, author, _, isTrusted, err := imageTrustStore.VerifySignature("notation", rawSignature, sigKey, image.Digest(),
manifestContent, repo) image.AsImageMeta(), repo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(isTrusted, ShouldBeTrue) So(isTrusted, ShouldBeTrue)
So(author, ShouldEqual, "CN=cert,O=Notary,L=Seattle,ST=WA,C=US") So(author, ShouldEqual, "CN=cert,O=Notary,L=Seattle,ST=WA,C=US")

View File

@ -4,12 +4,10 @@ package convert
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"testing" "testing"
"github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
@ -17,7 +15,7 @@ import (
"zotregistry.io/zot/pkg/extensions/search/gql_generated" "zotregistry.io/zot/pkg/extensions/search/gql_generated"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/boltdb" "zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types" . "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks" "zotregistry.io/zot/pkg/test/mocks"
) )
@ -34,33 +32,20 @@ func TestCVEConvert(t *testing.T) {
metaDB, err := boltdb.New(boltDB, log.NewLogger("debug", "")) metaDB, err := boltdb.New(boltDB, log.NewLogger("debug", ""))
So(err, ShouldBeNil) So(err, ShouldBeNil)
configBlob, err := json.Marshal(ispec.Image{}) image := CreateImageWith().
So(err, ShouldBeNil) Layers([]Layer{{
manifestBlob, err := json.Marshal(ispec.Manifest{
Layers: []ispec.Descriptor{
{
MediaType: ispec.MediaTypeImageLayerGzip, MediaType: ispec.MediaTypeImageLayerGzip,
Size: 0, Digest: ispec.MediaTypeEmptyJSON,
Digest: godigest.NewDigestFromEncoded(godigest.SHA256, "digest"), Blob: ispec.DescriptorEmptyJSON.Data,
}, }}).DefaultConfig().Build()
},
}) err = metaDB.SetRepoReference("repo1", "0.1.0", image.AsImageMeta())
So(err, ShouldBeNil) So(err, ShouldBeNil)
repoMeta11 := mTypes.ManifestMetadata{ repoMetaList, err := metaDB.SearchRepos(context.Background(), "")
ManifestBlob: manifestBlob,
ConfigBlob: configBlob,
}
digest11 := godigest.FromString("abc1")
err = metaDB.SetManifestMeta("repo1", digest11, repoMeta11)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "0.1.0", digest11, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
reposMeta, manifestMetaMap, _, err := metaDB.SearchRepos(context.Background(), "") imageMeta, err := metaDB.FilterImageMeta(context.Background(), []string{image.DigestStr()})
So(err, ShouldBeNil)
ctx := graphql.WithResponseContext(context.Background(), ctx := graphql.WithResponseContext(context.Background(),
graphql.DefaultErrorPresenter, graphql.DefaultRecover) graphql.DefaultErrorPresenter, graphql.DefaultRecover)
@ -86,8 +71,8 @@ func TestCVEConvert(t *testing.T) {
So(imageSummary, ShouldBeNil) So(imageSummary, ShouldBeNil)
So(graphql.GetErrors(ctx), ShouldBeNil) So(graphql.GetErrors(ctx), ShouldBeNil)
imageSummary, _, err = ImageManifest2ImageSummary(ctx, "repo1", "0.1.0", digest11, reposMeta[0], imageSummary, _, err = ImageManifest2ImageSummary(ctx, GetFullImageMeta("0.1.0", repoMetaList[0],
manifestMetaMap[digest11.String()]) imageMeta[image.DigestStr()]))
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(imageSummary, ShouldNotBeNil) So(imageSummary, ShouldNotBeNil)
@ -177,8 +162,8 @@ func TestCVEConvert(t *testing.T) {
So(repoSummary, ShouldBeNil) So(repoSummary, ShouldBeNil)
So(graphql.GetErrors(ctx), ShouldBeNil) So(graphql.GetErrors(ctx), ShouldBeNil)
imageSummary, _, err := ImageManifest2ImageSummary(ctx, "repo1", "0.1.0", digest11, reposMeta[0], imageSummary, _, err := ImageManifest2ImageSummary(ctx, GetFullImageMeta("0.1.0", repoMetaList[0],
manifestMetaMap[digest11.String()]) imageMeta[image.DigestStr()]))
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(imageSummary, ShouldNotBeNil) So(imageSummary, ShouldNotBeNil)
@ -235,8 +220,8 @@ func TestCVEConvert(t *testing.T) {
So(manifestSummary, ShouldBeNil) So(manifestSummary, ShouldBeNil)
So(graphql.GetErrors(ctx), ShouldBeNil) So(graphql.GetErrors(ctx), ShouldBeNil)
imageSummary, _, err := ImageManifest2ImageSummary(ctx, "repo1", "0.1.0", digest11, reposMeta[0], imageSummary, _, err := ImageManifest2ImageSummary(ctx, GetFullImageMeta("0.1.0", repoMetaList[0],
manifestMetaMap[digest11.String()]) imageMeta[image.DigestStr()]))
So(err, ShouldBeNil) So(err, ShouldBeNil)
manifestSummary = imageSummary.Manifests[0] manifestSummary = imageSummary.Manifests[0]

View File

@ -4,21 +4,19 @@ package convert_test
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"testing" "testing"
"time" "time"
"github.com/99designs/gqlgen/graphql"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/extensions/search/convert" "zotregistry.io/zot/pkg/extensions/search/convert"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/extensions/search/gql_generated" "zotregistry.io/zot/pkg/extensions/search/gql_generated"
"zotregistry.io/zot/pkg/extensions/search/pagination" "zotregistry.io/zot/pkg/extensions/search/pagination"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
. "zotregistry.io/zot/pkg/test/image-utils" . "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks" "zotregistry.io/zot/pkg/test/mocks"
@ -27,187 +25,6 @@ import (
var ErrTestError = errors.New("TestError") var ErrTestError = errors.New("TestError")
func TestConvertErrors(t *testing.T) {
Convey("ImageIndex2ImageSummary errors", t, func() {
ctx := graphql.WithResponseContext(context.Background(),
graphql.DefaultErrorPresenter, graphql.DefaultRecover)
_, _, err := convert.ImageIndex2ImageSummary(
ctx,
"repo",
"tag",
godigest.FromString("indexDigest"),
mTypes.RepoMetadata{},
mTypes.IndexData{
IndexBlob: []byte("bad json"),
},
map[string]mTypes.ManifestMetadata{},
)
So(err, ShouldNotBeNil)
})
Convey("ImageIndex2ImageSummary cve scanning", t, func() {
ctx := graphql.WithResponseContext(context.Background(),
graphql.DefaultErrorPresenter, graphql.DefaultRecover)
_, _, err := convert.ImageIndex2ImageSummary(
ctx,
"repo",
"tag",
godigest.FromString("indexDigest"),
mTypes.RepoMetadata{},
mTypes.IndexData{
IndexBlob: []byte("{}"),
},
map[string]mTypes.ManifestMetadata{},
)
So(err, ShouldBeNil)
})
Convey("ImageManifest2ImageSummary", t, func() {
ctx := graphql.WithResponseContext(context.Background(),
graphql.DefaultErrorPresenter, graphql.DefaultRecover)
configBlob, err := json.Marshal(ispec.Image{
Platform: ispec.Platform{
OS: "os",
Architecture: "arch",
Variant: "var",
},
})
So(err, ShouldBeNil)
_, _, err = convert.ImageManifest2ImageSummary(
ctx,
"repo",
"tag",
godigest.FromString("manifestDigest"),
mTypes.RepoMetadata{},
mTypes.ManifestMetadata{
ManifestBlob: []byte("{}"),
ConfigBlob: configBlob,
},
)
So(err, ShouldBeNil)
})
Convey("ImageManifest2ManifestSummary", t, func() {
ctx := graphql.WithResponseContext(context.Background(),
graphql.DefaultErrorPresenter, graphql.DefaultRecover)
// with bad config json, shouldn't error when unmarshaling
_, _, _, err := convert.ImageManifest2ManifestSummary(
ctx,
"repo",
"tag",
ispec.Descriptor{
Digest: "dig",
MediaType: ispec.MediaTypeImageManifest,
},
mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{},
Statistics: map[string]mTypes.DescriptorStatistics{},
Signatures: map[string]mTypes.ManifestSignatures{},
Referrers: map[string][]mTypes.ReferrerInfo{},
},
mTypes.ManifestMetadata{
ManifestBlob: []byte(`{}`),
ConfigBlob: []byte("bad json"),
},
nil,
)
So(err, ShouldBeNil)
// CVE scan using platform
configBlob, err := json.Marshal(ispec.Image{
Platform: ispec.Platform{
OS: "os",
Architecture: "arch",
Variant: "var",
},
})
So(err, ShouldBeNil)
_, _, _, err = convert.ImageManifest2ManifestSummary(
ctx,
"repo",
"tag",
ispec.Descriptor{
Digest: "dig",
MediaType: ispec.MediaTypeImageManifest,
},
mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{},
Statistics: map[string]mTypes.DescriptorStatistics{},
Signatures: map[string]mTypes.ManifestSignatures{"dig": {"cosine": []mTypes.SignatureInfo{{}}}},
Referrers: map[string][]mTypes.ReferrerInfo{},
},
mTypes.ManifestMetadata{
ManifestBlob: []byte("{}"),
ConfigBlob: configBlob,
},
nil,
)
So(err, ShouldBeNil)
})
Convey("RepoMeta2ExpandedRepoInfo", t, func() {
ctx := graphql.WithResponseContext(context.Background(),
graphql.DefaultErrorPresenter, graphql.DefaultRecover)
// with bad config json, error while unmarshaling
_, imageSummaries := convert.RepoMeta2ExpandedRepoInfo(
ctx,
mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{
"tag1": {Digest: "dig", MediaType: ispec.MediaTypeImageManifest},
},
},
map[string]mTypes.ManifestMetadata{
"dig": {
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("bad json"),
},
},
map[string]mTypes.IndexData{},
convert.SkipQGLField{
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo, digest, mediaType string) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{}, ErrTestError
},
}, log.NewLogger("debug", ""),
)
So(len(imageSummaries), ShouldEqual, 1)
// cveInfo present no error
_, imageSummaries = convert.RepoMeta2ExpandedRepoInfo(
ctx,
mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{
"tag1": {Digest: "dig", MediaType: ispec.MediaTypeImageManifest},
},
},
map[string]mTypes.ManifestMetadata{
"dig": {
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
},
},
map[string]mTypes.IndexData{},
convert.SkipQGLField{
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo, digest, mediaType string) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{}, ErrTestError
},
}, log.NewLogger("debug", ""),
)
So(len(imageSummaries), ShouldEqual, 1)
})
}
func TestUpdateLastUpdatedTimestamp(t *testing.T) { func TestUpdateLastUpdatedTimestamp(t *testing.T) {
Convey("Image summary is the first image checked for the repo", t, func() { Convey("Image summary is the first image checked for the repo", t, func() {
before := time.Time{} before := time.Time{}
@ -300,14 +117,25 @@ func TestLabels(t *testing.T) {
func TestGetSignaturesInfo(t *testing.T) { func TestGetSignaturesInfo(t *testing.T) {
Convey("Test get signatures info - cosign", t, func() { Convey("Test get signatures info - cosign", t, func() {
indexDigest := godigest.FromString("123") digest := godigest.FromString("dig")
repoMeta := mTypes.RepoMetadata{ signatures := map[string]mTypes.ManifestSignatures{
Signatures: map[string]mTypes.ManifestSignatures{string(indexDigest): {"cosign": []mTypes.SignatureInfo{{ digest.String(): {
LayersInfo: []mTypes.LayerInfo{{LayerContent: []byte{}, LayerDigest: "", SignatureKey: "", Signer: "author"}}, "cosign": []mTypes.SignatureInfo{
}}}}, {
LayersInfo: []mTypes.LayerInfo{
{
LayerContent: []byte{},
LayerDigest: "",
SignatureKey: "",
Signer: "author",
},
},
},
},
},
} }
signaturesSummary := convert.GetSignaturesInfo(true, repoMeta, indexDigest) signaturesSummary := convert.GetSignaturesInfo(true, signatures[digest.String()])
So(signaturesSummary, ShouldNotBeEmpty) So(signaturesSummary, ShouldNotBeEmpty)
So(*signaturesSummary[0].Author, ShouldEqual, "author") So(*signaturesSummary[0].Author, ShouldEqual, "author")
So(*signaturesSummary[0].IsTrusted, ShouldEqual, true) So(*signaturesSummary[0].IsTrusted, ShouldEqual, true)
@ -315,9 +143,11 @@ func TestGetSignaturesInfo(t *testing.T) {
}) })
Convey("Test get signatures info - notation", t, func() { Convey("Test get signatures info - notation", t, func() {
indexDigest := godigest.FromString("123") digest := godigest.FromString("dig")
repoMeta := mTypes.RepoMetadata{ signatures := map[string]mTypes.ManifestSignatures{
Signatures: map[string]mTypes.ManifestSignatures{string(indexDigest): {"notation": []mTypes.SignatureInfo{{ digest.String(): {
"notation": []mTypes.SignatureInfo{
{
LayersInfo: []mTypes.LayerInfo{ LayersInfo: []mTypes.LayerInfo{
{ {
LayerContent: []byte{}, LayerContent: []byte{},
@ -327,10 +157,12 @@ func TestGetSignaturesInfo(t *testing.T) {
Date: time.Now().AddDate(0, 0, -1), Date: time.Now().AddDate(0, 0, -1),
}, },
}, },
}}}}, },
},
},
} }
signaturesSummary := convert.GetSignaturesInfo(true, repoMeta, indexDigest) signaturesSummary := convert.GetSignaturesInfo(true, signatures[digest.String()])
So(signaturesSummary, ShouldNotBeEmpty) So(signaturesSummary, ShouldNotBeEmpty)
So(*signaturesSummary[0].Author, ShouldEqual, "author") So(*signaturesSummary[0].Author, ShouldEqual, "author")
So(*signaturesSummary[0].IsTrusted, ShouldEqual, false) So(*signaturesSummary[0].IsTrusted, ShouldEqual, false)
@ -422,6 +254,18 @@ func ref[T any](val T) *T {
func TestPaginatedConvert(t *testing.T) { func TestPaginatedConvert(t *testing.T) {
ctx := context.Background() ctx := context.Background()
tempDir := t.TempDir()
driver, err := boltdb.GetBoltDriver(boltdb.DBParameters{RootDir: tempDir})
if err != nil {
t.FailNow()
}
metaDB, err := boltdb.New(driver, log.NewLogger("debug", ""))
if err != nil {
t.FailNow()
}
var ( var (
badBothImage = CreateImageWith().DefaultLayers().ImageConfig( badBothImage = CreateImageWith().DefaultLayers().ImageConfig(
ispec.Image{Platform: ispec.Platform{OS: "bad-os", Architecture: "bad-arch"}}).Build() ispec.Image{Platform: ispec.Platform{OS: "bad-os", Architecture: "bad-arch"}}).Build()
@ -434,6 +278,7 @@ func TestPaginatedConvert(t *testing.T) {
randomImage1 = CreateRandomImage() randomImage1 = CreateRandomImage()
randomImage2 = CreateRandomImage() randomImage2 = CreateRandomImage()
signatureDigest = godigest.FromString("signature")
badMultiArch = CreateMultiarchWith().Images( badMultiArch = CreateMultiarchWith().Images(
[]Image{badBothImage, badOsImage, badArchImage, randomImage1}).Build() []Image{badBothImage, badOsImage, badArchImage, randomImage1}).Build()
@ -441,14 +286,14 @@ func TestPaginatedConvert(t *testing.T) {
[]Image{badOsImage, badArchImage, randomImage2, goodImage}).Build() []Image{badOsImage, badArchImage, randomImage2, goodImage}).Build()
) )
reposMeta, manifestMetaMap, indexDataMap := ociutils.GetMetadataForRepos( ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB,
ociutils.Repo{ ociutils.Repo{
Name: "repo1-only-images", Name: "repo1-only-images",
Images: []ociutils.RepoImage{ Images: []ociutils.RepoImage{
{Image: goodImage, Tag: "goodImage"}, {Image: goodImage, Reference: "goodImage"},
{Image: badOsImage, Tag: "badOsImage"}, {Image: badOsImage, Reference: "badOsImage"},
{Image: badArchImage, Tag: "badArchImage"}, {Image: badArchImage, Reference: "badArchImage"},
{Image: badBothImage, Tag: "badBothImage"}, {Image: badBothImage, Reference: "badBothImage"},
}, },
IsBookmarked: true, IsBookmarked: true,
IsStarred: true, IsStarred: true,
@ -456,9 +301,9 @@ func TestPaginatedConvert(t *testing.T) {
ociutils.Repo{ ociutils.Repo{
Name: "repo2-only-bad-images", Name: "repo2-only-bad-images",
Images: []ociutils.RepoImage{ Images: []ociutils.RepoImage{
{Image: randomImage1, Tag: "randomImage1"}, {Image: randomImage1, Reference: "randomImage1"},
{Image: randomImage2, Tag: "randomImage2"}, {Image: randomImage2, Reference: "randomImage2"},
{Image: badBothImage, Tag: "badBothImage"}, {Image: badBothImage, Reference: "badBothImage"},
}, },
IsBookmarked: true, IsBookmarked: true,
IsStarred: true, IsStarred: true,
@ -466,8 +311,8 @@ func TestPaginatedConvert(t *testing.T) {
ociutils.Repo{ ociutils.Repo{
Name: "repo3-only-multiarch", Name: "repo3-only-multiarch",
MultiArchImages: []ociutils.RepoMultiArchImage{ MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: badMultiArch, Tag: "badMultiArch"}, {MultiarchImage: badMultiArch, Reference: "badMultiArch"},
{MultiarchImage: goodMultiArch, Tag: "goodMultiArch"}, {MultiarchImage: goodMultiArch, Reference: "goodMultiArch"},
}, },
IsBookmarked: true, IsBookmarked: true,
IsStarred: true, IsStarred: true,
@ -475,44 +320,56 @@ func TestPaginatedConvert(t *testing.T) {
ociutils.Repo{ ociutils.Repo{
Name: "repo4-not-bookmarked-or-starred", Name: "repo4-not-bookmarked-or-starred",
Images: []ociutils.RepoImage{ Images: []ociutils.RepoImage{
{Image: goodImage, Tag: "goodImage"}, {Image: goodImage, Reference: "goodImage"},
}, },
MultiArchImages: []ociutils.RepoMultiArchImage{ MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: goodMultiArch, Tag: "goodMultiArch"}, {MultiarchImage: goodMultiArch, Reference: "goodMultiArch"},
}, },
}, },
ociutils.Repo{ ociutils.Repo{
Name: "repo5-signed", Name: "repo5-signed",
Images: []ociutils.RepoImage{ Images: []ociutils.RepoImage{
{Image: goodImage, Tag: "goodImage"}, // is fake signed by the image below {Image: goodImage, Reference: "goodImage"}, // is fake signed by the image below
{Image: CreateFakeTestSignature(goodImage.DescriptorRef())}, },
Signatures: map[string]mTypes.ManifestSignatures{
goodImage.DigestStr(): ociutils.GetFakeSignatureInfo(signatureDigest.String()),
}, },
}, },
) )
if err != nil {
t.FailNow()
}
skipCVE := convert.SkipQGLField{Vulnerabilities: true} skipCVE := convert.SkipQGLField{Vulnerabilities: true}
Convey("PaginatedRepoMeta2RepoSummaries filtering and sorting", t, func() { Convey("PaginatedRepoMeta2RepoSummaries filtering and sorting", t, func() {
// Test different combinations of the filter // Test different combinations of the filter
repoMetaList, err := metaDB.FilterRepos(ctx, mTypes.AcceptAllRepoNames, mTypes.AcceptAllRepoMeta)
So(err, ShouldBeNil)
imageMeta, err := metaDB.FilterImageMeta(ctx, mTypes.GetLatestImageDigests(repoMetaList))
So(err, ShouldBeNil)
reposSum, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries( reposSum, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, repoMetaList, imageMeta,
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
IsBookmarked: ref(true), IsBookmarked: ref(true),
IsStarred: ref(true), IsStarred: ref(true),
}, },
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
) )
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 2) So(len(reposSum), ShouldEqual, 2)
So(*reposSum[0].Name, ShouldResemble, "repo1-only-images") So(*reposSum[0].Name, ShouldResemble, "repo1-only-images")
So(*reposSum[1].Name, ShouldResemble, "repo3-only-multiarch") So(*reposSum[1].Name, ShouldResemble, "repo3-only-multiarch")
So(pageInfo.ItemCount, ShouldEqual, 2) So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries( reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, repoMetaList, imageMeta,
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
@ -520,18 +377,18 @@ func TestPaginatedConvert(t *testing.T) {
IsStarred: ref(true), IsStarred: ref(true),
HasToBeSigned: ref(true), HasToBeSigned: ref(true),
}, },
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
) )
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 0) So(len(reposSum), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries( reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, repoMetaList, imageMeta,
mTypes.Filter{ mTypes.Filter{
HasToBeSigned: ref(true), HasToBeSigned: ref(true),
}, },
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
) )
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 1) So(len(reposSum), ShouldEqual, 1)
@ -540,8 +397,8 @@ func TestPaginatedConvert(t *testing.T) {
// no filter // no filter
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries( reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, repoMetaList, imageMeta,
mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
) )
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 5) So(len(reposSum), ShouldEqual, 5)
@ -554,8 +411,8 @@ func TestPaginatedConvert(t *testing.T) {
// no filter opposite sorting // no filter opposite sorting
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries( reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, repoMetaList, imageMeta,
mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticDsc}, mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticDsc}, mocks.CveInfoMock{}, skipCVE,
) )
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 5) So(len(reposSum), ShouldEqual, 5)
@ -568,14 +425,14 @@ func TestPaginatedConvert(t *testing.T) {
// add pagination // add pagination
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries( reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, repoMetaList, imageMeta,
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
IsBookmarked: ref(true), IsBookmarked: ref(true),
IsStarred: ref(true), IsStarred: ref(true),
}, },
pagination.PageInput{Limit: 1, Offset: 0, SortBy: pagination.AlphabeticAsc}, pagination.PageInput{Limit: 1, Offset: 0, SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
) )
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 1) So(len(reposSum), ShouldEqual, 1)
@ -584,14 +441,14 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.TotalCount, ShouldEqual, 2) So(pageInfo.TotalCount, ShouldEqual, 2)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries( reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, repoMetaList, imageMeta,
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
IsBookmarked: ref(true), IsBookmarked: ref(true),
IsStarred: ref(true), IsStarred: ref(true),
}, },
pagination.PageInput{Limit: 1, Offset: 1, SortBy: pagination.AlphabeticAsc}, pagination.PageInput{Limit: 1, Offset: 1, SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
) )
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 1) So(len(reposSum), ShouldEqual, 1)
@ -601,8 +458,11 @@ func TestPaginatedConvert(t *testing.T) {
}) })
Convey("PaginatedRepoMeta2ImageSummaries filtering and sorting", t, func() { Convey("PaginatedRepoMeta2ImageSummaries filtering and sorting", t, func() {
imgSum, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries( fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, So(err, ShouldBeNil)
imgSum, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
@ -624,8 +484,8 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.ItemCount, ShouldEqual, 5) So(pageInfo.ItemCount, ShouldEqual, 5)
// add page of size 2 // add page of size 2
imgSum, pageInfo, err = convert.PaginatedRepoMeta2ImageSummaries( imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
@ -642,8 +502,8 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.TotalCount, ShouldEqual, 5) So(pageInfo.TotalCount, ShouldEqual, 5)
// next page // next page
imgSum, pageInfo, err = convert.PaginatedRepoMeta2ImageSummaries( imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
@ -660,8 +520,8 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.TotalCount, ShouldEqual, 5) So(pageInfo.TotalCount, ShouldEqual, 5)
// last page // last page
imgSum, pageInfo, err = convert.PaginatedRepoMeta2ImageSummaries( imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
@ -676,8 +536,8 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.TotalCount, ShouldEqual, 5) So(pageInfo.TotalCount, ShouldEqual, 5)
// has to be signed // has to be signed
imgSum, pageInfo, err = convert.PaginatedRepoMeta2ImageSummaries( imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{}, ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{ mTypes.Filter{
Os: []*string{ref("good-os")}, Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")}, Arch: []*string{ref("good-arch")},
@ -697,6 +557,16 @@ func TestIndexAnnotations(t *testing.T) {
Convey("Test ImageIndex2ImageSummary annotations logic", t, func() { Convey("Test ImageIndex2ImageSummary annotations logic", t, func() {
ctx := context.Background() ctx := context.Background()
tempDir := t.TempDir()
driver, err := boltdb.GetBoltDriver(boltdb.DBParameters{RootDir: tempDir})
if err != nil {
t.FailNow()
}
metaDB, err := boltdb.New(driver, log.NewLogger("debug", ""))
So(err, ShouldBeNil)
configLabels := map[string]string{ configLabels := map[string]string{
ispec.AnnotationDescription: "ConfigDescription", ispec.AnnotationDescription: "ConfigDescription",
ispec.AnnotationLicenses: "ConfigLicenses", ispec.AnnotationLicenses: "ConfigLicenses",
@ -746,17 +616,22 @@ func TestIndexAnnotations(t *testing.T) {
[]Image{imageWithManifestAndConfigAnnotations}, []Image{imageWithManifestAndConfigAnnotations},
).Annotations(indexAnnotations).Build() ).Annotations(indexAnnotations).Build()
repoMeta, manifestMetadata, indexData := ociutils.GetMetadataForRepos(ociutils.Repo{ ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB,
ociutils.Repo{
Name: "repo", Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{ MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithAnnotations, Tag: "tag"}, {MultiarchImage: indexWithAnnotations, Reference: "tag"},
}, },
}) })
So(err, ShouldBeNil)
digest := indexWithAnnotations.Digest() repoMeta, err := metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err := metaDB.FilterImageMeta(ctx, []string{indexWithAnnotations.DigestStr()})
So(err, ShouldBeNil)
imageSummary, _, err := convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest, repoMeta[0], imageSummary, _, err := convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
indexData[digest.String()], manifestMetadata) imageMeta[indexWithAnnotations.DigestStr()]))
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "IndexDescription") So(*imageSummary.Description, ShouldResemble, "IndexDescription")
So(*imageSummary.Licenses, ShouldResemble, "IndexLicenses") So(*imageSummary.Licenses, ShouldResemble, "IndexLicenses")
@ -766,19 +641,30 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Vendor, ShouldResemble, "IndexVendor") So(*imageSummary.Vendor, ShouldResemble, "IndexVendor")
So(*imageSummary.Authors, ShouldResemble, "IndexAuthors") So(*imageSummary.Authors, ShouldResemble, "IndexAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
// -------------------------------------------------------- // --------------------------------------------------------
indexWithManifestAndConfigAnnotations := CreateMultiarchWith().Images( indexWithManifestAndConfigAnnotations := CreateMultiarchWith().Images(
[]Image{imageWithManifestAndConfigAnnotations, CreateRandomImage(), CreateRandomImage()}, []Image{imageWithManifestAndConfigAnnotations, CreateRandomImage(), CreateRandomImage()},
).Build() ).Build()
repoMeta, manifestMetadata, indexData = ociutils.GetMetadataForRepos(ociutils.Repo{ ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo", Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{{MultiarchImage: indexWithManifestAndConfigAnnotations}}, MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithManifestAndConfigAnnotations, Reference: "tag"},
},
}) })
digest = indexWithManifestAndConfigAnnotations.Digest() So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest, digest := indexWithManifestAndConfigAnnotations.DigestStr()
repoMeta[0], indexData[digest.String()], manifestMetadata)
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err = metaDB.FilterImageMeta(ctx, []string{digest})
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[digest]))
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "ManifestDescription") So(*imageSummary.Description, ShouldResemble, "ManifestDescription")
So(*imageSummary.Licenses, ShouldResemble, "ManifestLicenses") So(*imageSummary.Licenses, ShouldResemble, "ManifestLicenses")
@ -787,19 +673,31 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Documentation, ShouldResemble, "ManifestDocumentation") So(*imageSummary.Documentation, ShouldResemble, "ManifestDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "ManifestVendor") So(*imageSummary.Vendor, ShouldResemble, "ManifestVendor")
So(*imageSummary.Authors, ShouldResemble, "ManifestAuthors") So(*imageSummary.Authors, ShouldResemble, "ManifestAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
// -------------------------------------------------------- // --------------------------------------------------------
indexWithConfigAnnotations := CreateMultiarchWith().Images( indexWithConfigAnnotations := CreateMultiarchWith().Images(
[]Image{imageWithConfigAnnotations, CreateRandomImage(), CreateRandomImage()}, []Image{imageWithConfigAnnotations, CreateRandomImage(), CreateRandomImage()},
).Build() ).Build()
repoMeta, manifestMetadata, indexData = ociutils.GetMetadataForRepos(ociutils.Repo{ ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo", Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{{MultiarchImage: indexWithConfigAnnotations, Tag: "tag"}}, MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithConfigAnnotations, Reference: "tag"},
},
}) })
digest = indexWithConfigAnnotations.Digest() So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest, digest = indexWithConfigAnnotations.DigestStr()
repoMeta[0], indexData[digest.String()], manifestMetadata)
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err = metaDB.FilterImageMeta(ctx, []string{digest})
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[digest]))
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "ConfigDescription") So(*imageSummary.Description, ShouldResemble, "ConfigDescription")
So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses") So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses")
@ -808,6 +706,9 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Documentation, ShouldResemble, "ConfigDocumentation") So(*imageSummary.Documentation, ShouldResemble, "ConfigDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "ConfigVendor") So(*imageSummary.Vendor, ShouldResemble, "ConfigVendor")
So(*imageSummary.Authors, ShouldResemble, "ConfigAuthors") So(*imageSummary.Authors, ShouldResemble, "ConfigAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
//-------------------------------------------------------- //--------------------------------------------------------
indexWithMixAnnotations := CreateMultiarchWith().Images( indexWithMixAnnotations := CreateMultiarchWith().Images(
@ -834,14 +735,23 @@ func TestIndexAnnotations(t *testing.T) {
}, },
).Build() ).Build()
repoMeta, manifestMetadata, indexData = ociutils.GetMetadataForRepos(ociutils.Repo{ ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo", Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{{MultiarchImage: indexWithMixAnnotations, Tag: "tag"}}, MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithMixAnnotations, Reference: "tag"},
},
}) })
digest = indexWithMixAnnotations.Digest() So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest, digest = indexWithMixAnnotations.DigestStr()
repoMeta[0], indexData[digest.String()], manifestMetadata)
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err = metaDB.FilterImageMeta(ctx, []string{digest})
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[digest]))
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "ConfigDescription") So(*imageSummary.Description, ShouldResemble, "ConfigDescription")
So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses") So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses")
@ -851,17 +761,28 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Documentation, ShouldResemble, "IndexDocumentation") So(*imageSummary.Documentation, ShouldResemble, "IndexDocumentation")
So(*imageSummary.Source, ShouldResemble, "IndexSource") So(*imageSummary.Source, ShouldResemble, "IndexSource")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
//-------------------------------------------------------- //--------------------------------------------------------
indexWithNoAnnotations := CreateRandomMultiarch() indexWithNoAnnotations := CreateRandomMultiarch()
repoMeta, manifestMetadata, indexData = ociutils.GetMetadataForRepos(ociutils.Repo{ ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo", Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{{MultiarchImage: indexWithNoAnnotations, Tag: "tag"}}, MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithNoAnnotations, Reference: "tag"},
},
}) })
digest = indexWithNoAnnotations.Digest() So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest, digest = indexWithNoAnnotations.DigestStr()
repoMeta[0], indexData[digest.String()], manifestMetadata)
repoMeta, err = metaDB.GetRepoMeta(ctx, "repo")
So(err, ShouldBeNil)
imageMeta, err = metaDB.FilterImageMeta(ctx, []string{digest})
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[digest]))
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldBeBlank) So(*imageSummary.Description, ShouldBeBlank)
So(*imageSummary.Licenses, ShouldBeBlank) So(*imageSummary.Licenses, ShouldBeBlank)
@ -870,94 +791,8 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Title, ShouldBeBlank) So(*imageSummary.Title, ShouldBeBlank)
So(*imageSummary.Documentation, ShouldBeBlank) So(*imageSummary.Documentation, ShouldBeBlank)
So(*imageSummary.Source, ShouldBeBlank) So(*imageSummary.Source, ShouldBeBlank)
})
} err = metaDB.ResetDB()
So(err, ShouldBeNil)
func TestDownloadCount(t *testing.T) {
Convey("manifest", t, func() {
repoMeta, manifestMetaMap, indexDataMap := ociutils.GetMetadataForRepos(
ociutils.Repo{
Name: "repo",
Images: []ociutils.RepoImage{
{
Image: CreateRandomImage(),
Tag: "10-downloads",
Statistics: mTypes.DescriptorStatistics{
DownloadCount: 10,
},
},
},
},
)
repoSummary := convert.RepoMeta2RepoSummary(context.Background(), repoMeta[0], manifestMetaMap, indexDataMap)
So(*repoSummary.DownloadCount, ShouldEqual, 10)
So(*repoSummary.NewestImage.DownloadCount, ShouldEqual, 10)
})
Convey("index", t, func() {
img1, img2, img3 := CreateRandomImage(), CreateRandomImage(), CreateRandomImage()
multiArch := CreateMultiarchWith().Images([]Image{img1, img2, img3}).Build()
repoMeta, manifestMetaMap, indexDataMap := ociutils.GetMetadataForRepos(
ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{
MultiarchImage: multiArch,
Tag: "160-multiarch",
ImageStatistics: map[string]mTypes.DescriptorStatistics{
img1.DigestStr(): {DownloadCount: 10},
img2.DigestStr(): {DownloadCount: 20},
img3.DigestStr(): {DownloadCount: 30},
multiArch.DigestStr(): {DownloadCount: 100},
},
},
},
},
)
repoSummary := convert.RepoMeta2RepoSummary(context.Background(), repoMeta[0], manifestMetaMap, indexDataMap)
So(*repoSummary.DownloadCount, ShouldEqual, 100)
So(*repoSummary.NewestImage.DownloadCount, ShouldEqual, 100)
})
Convey("index + manifest mixed", t, func() {
img1 := CreateRandomImage()
img2 := CreateRandomImage()
img3 := CreateImageWith().DefaultLayers().ImageConfig(
ispec.Image{Created: DateRef(2020, 1, 1, 1, 1, 1, 0, time.UTC)},
).Build()
multiArch := CreateMultiarchWith().Images([]Image{img1, img2, img3}).Build()
repoMeta, manifestMetaMap, indexDataMap := ociutils.GetMetadataForRepos(
ociutils.Repo{
Name: "repo",
Images: []ociutils.RepoImage{
{
Image: CreateRandomImage(),
Tag: "5-downloads",
Statistics: mTypes.DescriptorStatistics{DownloadCount: 5},
},
},
MultiArchImages: []ociutils.RepoMultiArchImage{
{
MultiarchImage: multiArch,
Tag: "160-multiarch",
ImageStatistics: map[string]mTypes.DescriptorStatistics{
img1.DigestStr(): {DownloadCount: 10},
img2.DigestStr(): {DownloadCount: 20},
img3.DigestStr(): {DownloadCount: 30},
multiArch.DigestStr(): {DownloadCount: 100},
},
},
},
},
)
repoSummary := convert.RepoMeta2RepoSummary(context.Background(), repoMeta[0], manifestMetaMap, indexDataMap)
So(*repoSummary.DownloadCount, ShouldEqual, 105)
So(*repoSummary.NewestImage.DownloadCount, ShouldEqual, 100)
}) })
} }

File diff suppressed because it is too large Load Diff

View File

@ -9,19 +9,6 @@ import (
"zotregistry.io/zot/pkg/extensions/search/gql_generated" "zotregistry.io/zot/pkg/extensions/search/gql_generated"
) )
// updateRepoBlobsMap adds all the image blobs and their respective size to the repo blobs map
// and returnes the total size of the image.
func updateRepoBlobsMap(imageBlobs map[string]int64, repoBlob2Size map[string]int64) int64 {
imgSize := int64(0)
for digest, size := range imageBlobs {
repoBlob2Size[digest] = size
imgSize += size
}
return imgSize
}
func getLayersSummaries(manifestContent ispec.Manifest) []*gql_generated.LayerSummary { func getLayersSummaries(manifestContent ispec.Manifest) []*gql_generated.LayerSummary {
layers := make([]*gql_generated.LayerSummary, 0, len(manifestContent.Layers)) layers := make([]*gql_generated.LayerSummary, 0, len(manifestContent.Layers))

View File

@ -1,7 +1,7 @@
package cveinfo package cveinfo
import ( import (
"encoding/json" "context"
"sort" "sort"
"strings" "strings"
"time" "time"
@ -9,6 +9,7 @@ import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common" zcommon "zotregistry.io/zot/pkg/common"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model" cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/extensions/search/cve/trivy" "zotregistry.io/zot/pkg/extensions/search/cve/trivy"
@ -57,7 +58,7 @@ func NewCVEInfo(scanner Scanner, metaDB mTypes.MetaDB, log log.Logger) *BaseCveI
func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]cvemodel.TagInfo, error) { func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]cvemodel.TagInfo, error) {
imgList := make([]cvemodel.TagInfo, 0) imgList := make([]cvemodel.TagInfo, 0)
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(repo) repoMeta, err := cveinfo.MetaDB.GetRepoMeta(context.Background(), repo)
if err != nil { if err != nil {
cveinfo.Log.Error().Err(err).Str("repository", repo).Str("cve-id", cveID). cveinfo.Log.Error().Err(err).Str("repository", repo).Str("cve-id", cveID).
Msg("unable to get list of tags from repo") Msg("unable to get list of tags from repo")
@ -105,7 +106,7 @@ func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]cvemodel.Ta
} }
func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]cvemodel.TagInfo, error) { func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]cvemodel.TagInfo, error) {
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(repo) repoMeta, err := cveinfo.MetaDB.GetRepoMeta(context.Background(), repo)
if err != nil { if err != nil {
cveinfo.Log.Error().Err(err).Str("repository", repo).Str("cve-id", cveID). cveinfo.Log.Error().Err(err).Str("repository", repo).Str("cve-id", cveID).
Msg("unable to get list of tags from repo") Msg("unable to get list of tags from repo")
@ -287,19 +288,16 @@ func getIndexContent(metaDB mTypes.MetaDB, indexDigestStr string) (ispec.Index,
return ispec.Index{}, err return ispec.Index{}, err
} }
indexData, err := metaDB.GetIndexData(indexDigest) indexData, err := metaDB.GetImageMeta(indexDigest)
if err != nil { if err != nil {
return ispec.Index{}, err return ispec.Index{}, err
} }
var indexContent ispec.Index if indexData.Index == nil {
return ispec.Index{}, zerr.ErrUnexpectedMediaType
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
return ispec.Index{}, err
} }
return indexContent, nil return *indexData.Index, nil
} }
func getConfigAndDigest(metaDB mTypes.MetaDB, manifestDigestStr string) (ispec.Image, godigest.Digest, error) { func getConfigAndDigest(metaDB mTypes.MetaDB, manifestDigestStr string) (ispec.Image, godigest.Digest, error) {
@ -308,17 +306,17 @@ func getConfigAndDigest(metaDB mTypes.MetaDB, manifestDigestStr string) (ispec.I
return ispec.Image{}, "", err return ispec.Image{}, "", err
} }
manifestData, err := metaDB.GetManifestData(manifestDigest) manifestData, err := metaDB.GetImageMeta(manifestDigest)
if err != nil { if err != nil {
return ispec.Image{}, "", err return ispec.Image{}, "", err
} }
var configContent ispec.Image // we'll fail the execution if the config is not compatible with ispec.Image because we can't scan this type of images.
if manifestData.Manifests[0].Manifest.Config.MediaType != ispec.MediaTypeImageConfig {
return ispec.Image{}, "", zerr.ErrUnexpectedMediaType
}
// we'll fail the execution if the config is not compatibe with ispec.Image because we can't scan this type of images. return manifestData.Manifests[0].Config, manifestDigest, err
err = json.Unmarshal(manifestData.ConfigBlob, &configContent)
return configContent, manifestDigest, err
} }
func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE string, pageFinder *CvePageFinder) { func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE string, pageFinder *CvePageFinder) {

View File

@ -5,6 +5,7 @@
package cveinfo_test package cveinfo_test
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -385,8 +386,8 @@ func TestImageFormat(t *testing.T) {
log := log.NewLogger("debug", "") log := log.NewLogger("debug", "")
metaDB := &mocks.MetaDBMock{ metaDB := &mocks.MetaDBMock{
GetRepoMetaFn: func(repo string) (mTypes.RepoMetadata, error) { GetRepoMetaFn: func(ctx context.Context, repo string) (mTypes.RepoMeta, error) {
return mTypes.RepoMetadata{ return mTypes.RepoMeta{
Tags: map[string]mTypes.Descriptor{ Tags: map[string]mTypes.Descriptor{
"tag": { "tag": {
MediaType: ispec.MediaTypeImageIndex, MediaType: ispec.MediaTypeImageIndex,
@ -395,8 +396,12 @@ func TestImageFormat(t *testing.T) {
}, },
}, nil }, nil
}, },
GetIndexDataFn: func(indexDigest godigest.Digest) (mTypes.IndexData, error) { GetImageMetaFn: func(digest godigest.Digest) (mTypes.ImageMeta, error) {
return mTypes.IndexData{IndexBlob: []byte(`{}`)}, nil return mTypes.ImageMeta{
MediaType: ispec.MediaTypeImageIndex,
Digest: godigest.FromString("digest"),
Index: &ispec.Index{},
}, nil
}, },
} }
storeController := storage.StoreController{ storeController := storage.StoreController{
@ -765,73 +770,32 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
image11 := CreateImageWith().DefaultLayers(). image11 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2008, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2008, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta11 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference(repo1, "0.1.0", image11.AsImageMeta())
ManifestBlob: image11.ManifestDescriptor.Data,
ConfigBlob: image11.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta(repo1, image11.ManifestDescriptor.Digest, repoMeta11)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo1, "0.1.0", image11.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image12 := CreateImageWith().DefaultLayers(). image12 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta12 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference(repo1, "1.0.0", image12.AsImageMeta())
ManifestBlob: image12.ManifestDescriptor.Data,
ConfigBlob: image12.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta(repo1, image12.ManifestDescriptor.Digest, repoMeta12)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo1, "1.0.0", image12.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image13 := CreateImageWith().DefaultLayers(). image13 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta13 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference(repo1, "1.1.0", image13.AsImageMeta())
ManifestBlob: image13.ManifestDescriptor.Data,
ConfigBlob: image13.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta(repo1, image13.ManifestDescriptor.Digest, repoMeta13)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo1, "1.1.0", image13.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image14 := CreateImageWith().DefaultLayers(). image14 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2011, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2011, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta14 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference(repo1, "1.0.1", image14.AsImageMeta())
ManifestBlob: image14.ManifestDescriptor.Data,
ConfigBlob: image14.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta(repo1, image14.ManifestDescriptor.Digest, repoMeta14)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo1, "1.0.1", image14.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create metadb data for scannable image with no vulnerabilities // Create metadb data for scannable image with no vulnerabilities
image61 := CreateImageWith().DefaultLayers(). image61 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2016, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2016, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta61 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference(repo6, "1.0.0", image61.AsImageMeta())
ManifestBlob: image61.ManifestDescriptor.Data,
ConfigBlob: image61.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta(repo6, image61.ManifestDescriptor.Digest, repoMeta61)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo6, "1.0.0", image61.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create metadb data for image not supporting scanning // Create metadb data for image not supporting scanning
@ -841,106 +805,59 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
Digest: godigest.FromBytes([]byte{10, 10, 10}), Digest: godigest.FromBytes([]byte{10, 10, 10}),
}}).ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() }}).ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta21 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference(repo2, "1.0.0", image21.AsImageMeta())
ManifestBlob: image21.ManifestDescriptor.Data,
ConfigBlob: image21.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta(repo2, image21.ManifestDescriptor.Digest, repoMeta21)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo2, "1.0.0", image21.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create metadb data for invalid images/negative tests // Create metadb data for invalid images/negative tests
manifestBlob31 := []byte("invalid manifest blob") image := CreateRandomImage()
So(err, ShouldBeNil) err = metaDB.SetRepoReference(repo3, "invalid-manifest", image.AsImageMeta())
repoMeta31 := mTypes.ManifestMetadata{
ManifestBlob: manifestBlob31,
}
digest31 := godigest.FromBytes(manifestBlob31)
err = metaDB.SetManifestMeta(repo3, digest31, repoMeta31)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo3, "invalid-manifest", digest31, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image41 := CreateImageWith().DefaultLayers(). image41 := CreateImageWith().DefaultLayers().
CustomConfigBlob([]byte("invalid config blob"), ispec.MediaTypeImageConfig).Build() CustomConfigBlob([]byte("invalid config blob"), ispec.MediaTypeImageConfig).Build()
repoMeta41 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference(repo4, "invalid-config", image41.AsImageMeta())
ManifestBlob: image41.ManifestDescriptor.Data,
ConfigBlob: image41.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta(repo4, image41.ManifestDescriptor.Digest, repoMeta41)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo4, "invalid-config", image41.ManifestDescriptor.Digest,
ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
digest51 := godigest.FromString("abc8") digest51 := godigest.FromString("abc8")
err = metaDB.SetRepoReference(repo5, "nonexitent-manifest", digest51, ispec.MediaTypeImageManifest) randomImgData := CreateRandomImage().AsImageMeta()
randomImgData.Digest = digest51
randomImgData.Manifests[0].Digest = digest51
err = metaDB.SetRepoReference(repo5, "nonexitent-manifest", randomImgData)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create metadb data for scannable image which errors during scan // Create metadb data for scannable image which errors during scan
image71 := CreateImageWith().DefaultLayers(). image71 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2000, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2000, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta71 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference(repo7, "1.0.0", image71.AsImageMeta())
ManifestBlob: image71.ManifestDescriptor.Data,
ConfigBlob: image71.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta(repo7, image71.ManifestDescriptor.Digest, repoMeta71)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo7, "1.0.0", image71.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// create multiarch image with vulnerabilities // create multiarch image with vulnerabilities
multiarchImage := CreateRandomMultiarch() multiarchImage := CreateRandomMultiarch()
err = metaDB.SetIndexData( err = metaDB.SetRepoReference(repoMultiarch, multiarchImage.Images[0].DigestStr(),
multiarchImage.IndexDescriptor.Digest, multiarchImage.Images[0].AsImageMeta())
mTypes.IndexData{IndexBlob: multiarchImage.IndexDescriptor.Data},
)
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = metaDB.SetManifestData( err = metaDB.SetRepoReference(repoMultiarch, multiarchImage.Images[1].DigestStr(),
multiarchImage.Images[0].ManifestDescriptor.Digest, multiarchImage.Images[1].AsImageMeta())
mTypes.ManifestData{ So(err, ShouldBeNil)
ManifestBlob: multiarchImage.Images[0].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[0].ConfigDescriptor.Data, err = metaDB.SetRepoReference(repoMultiarch, multiarchImage.Images[2].DigestStr(),
multiarchImage.Images[2].AsImageMeta())
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repoMultiarch, "tagIndex", multiarchImage.AsImageMeta())
So(err, ShouldBeNil)
err = metaDB.SetRepoMeta("repo-with-bad-tag-digest", mTypes.RepoMeta{
Name: "repo-with-bad-tag-digest",
Tags: map[string]mTypes.Descriptor{
"tag": {MediaType: ispec.MediaTypeImageManifest, Digest: godigest.FromString("1").String()},
}, },
) })
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = metaDB.SetManifestData(
multiarchImage.Images[1].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[1].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[1].ConfigDescriptor.Data,
},
)
So(err, ShouldBeNil)
err = metaDB.SetManifestData(
multiarchImage.Images[2].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[2].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[2].ConfigDescriptor.Data,
},
)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(
repoMultiarch,
"tagIndex",
multiarchImage.IndexDescriptor.Digest,
ispec.MediaTypeImageIndex,
)
So(err, ShouldBeNil)
// Keep a record of all the image references / digest pairings // Keep a record of all the image references / digest pairings
// This is normally done in MetaDB, but we want to verify // This is normally done in MetaDB, but we want to verify
// the whole flow, including MetaDB // the whole flow, including MetaDB
@ -966,18 +883,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
image21Media := image21.ManifestDescriptor.MediaType image21Media := image21.ManifestDescriptor.MediaType
image21Name := repo2 + ":1.0.0" image21Name := repo2 + ":1.0.0"
imageMap[image21Name] = image21Digest imageMap[image21Name] = image21Digest
image31Digest := digest31.String()
image31Media := ispec.MediaTypeImageManifest
image31Name := repo3 + ":invalid-manifest"
imageMap[image31Name] = image31Digest
image41Digest := image41.ManifestDescriptor.Digest.String()
image41Media := image41.ManifestDescriptor.MediaType
image41Name := repo4 + ":invalid-config"
imageMap[image41Name] = image41Digest
image51Digest := digest51.String()
image51Media := ispec.MediaTypeImageManifest
image51Name := repo5 + ":nonexitent-manifest"
imageMap[image51Name] = digest51.String()
image61Digest := image61.ManifestDescriptor.Digest.String() image61Digest := image61.ManifestDescriptor.Digest.String()
image61Media := image61.ManifestDescriptor.MediaType image61Media := image61.ManifestDescriptor.MediaType
image61Name := repo6 + ":1.0.0" image61Name := repo6 + ":1.0.0"
@ -1151,7 +1056,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
// Almost same logic compared to actual Trivy specific implementation // Almost same logic compared to actual Trivy specific implementation
imageDir, inputTag := repo, reference imageDir, inputTag := repo, reference
repoMeta, err := metaDB.GetRepoMeta(imageDir) repoMeta, err := metaDB.GetRepoMeta(context.Background(), imageDir)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -1174,19 +1079,12 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
return false, err return false, err
} }
manifestData, err := metaDB.GetManifestData(manifestDigest) manifestData, err := metaDB.GetImageMeta(manifestDigest)
if err != nil { if err != nil {
return false, err return false, err
} }
var manifestContent ispec.Manifest for _, imageLayer := range manifestData.Manifests[0].Manifest.Layers {
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
return false, zerr.ErrScanNotSupported
}
for _, imageLayer := range manifestContent.Layers {
switch imageLayer.MediaType { switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer): case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
@ -1203,12 +1101,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
if repo == repo2 && digest == image21Digest { if repo == repo2 && digest == image21Digest {
return false, zerr.ErrScanNotSupported return false, zerr.ErrScanNotSupported
} }
if repo == repo3 && digest == image31Digest {
return false, zerr.ErrTagMetaNotFound
}
if repo == repo5 && digest == image51Digest {
return false, zerr.ErrManifestDataNotFound
}
if repo == repo100 { if repo == repo100 {
return false, zerr.ErrRepoMetaNotFound return false, zerr.ErrRepoMetaNotFound
} }
@ -1295,20 +1187,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0) So(pageInfo.TotalCount, ShouldEqual, 0)
// Config not valid
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo4, "invalid-config", "", pageInput)
So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
// Manifest is not found
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo5, "nonexitent-manifest", "", pageInput)
So(err, ShouldEqual, zerr.ErrManifestDataNotFound)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
// Scan failed // Scan failed
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo7, "1.0.0", "", pageInput) cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo7, "1.0.0", "", pageInput)
So(err, ShouldEqual, ErrFailedScan) So(err, ShouldEqual, ErrFailedScan)
@ -1316,6 +1194,13 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0) So(pageInfo.TotalCount, ShouldEqual, 0)
// Tag is not found
cveList, pageInfo, err = cveInfo.GetCVEListForImage("repo-with-bad-tag-digest", "tag", "", pageInput)
So(err, ShouldEqual, zerr.ErrImageMetaNotFound)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
// Repo is not found // Repo is not found
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo100, "1.0.0", "", pageInput) cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo100, "1.0.0", "", pageInput)
So(err, ShouldEqual, zerr.ErrRepoMetaNotFound) So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
@ -1364,24 +1249,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.Count, ShouldEqual, 0) So(cveSummary.Count, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "") So(cveSummary.MaxSeverity, ShouldEqual, "")
// Tag is not found
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo3, image31Digest, image31Media)
So(err, ShouldEqual, zerr.ErrTagMetaNotFound)
So(cveSummary.Count, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "")
// Config not valid
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo4, image41Digest, image41Media)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "NONE")
// Manifest is not found
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo5, image51Digest, image51Media)
So(err, ShouldEqual, zerr.ErrManifestDataNotFound)
So(cveSummary.Count, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "")
// Scan failed // Scan failed
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo5, image71Digest, image71Media) cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo5, image71Digest, image71Media)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -1430,16 +1297,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 0) So(len(tagList), ShouldEqual, 0)
// Tag is not found, but we should not error
tagList, err = cveInfo.GetImageListWithCVEFixed(repo3, "CVE101")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 0)
// Manifest is not found, we just consider exclude it from the fixed list
tagList, err = cveInfo.GetImageListWithCVEFixed(repo5, "CVE101")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 0)
// Repo is not found, there could potentially be unaffected tags in the repo // Repo is not found, there could potentially be unaffected tags in the repo
// but we can't access their data // but we can't access their data
tagList, err = cveInfo.GetImageListWithCVEFixed(repo100, "CVE100") tagList, err = cveInfo.GetImageListWithCVEFixed(repo100, "CVE100")
@ -1719,158 +1576,6 @@ func TestFixedTagsWithIndex(t *testing.T) {
}) })
} }
func TestImageListWithCVEFixedErrors(t *testing.T) {
indexDigest := godigest.FromString("index")
manifestDigest := "sha256:1111111111111111111111111111111111111111111111111111111111111111"
Convey("Errors", t, func() {
storeController := storage.StoreController{}
storeController.DefaultStore = mocks.MockedImageStore{}
metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "")
Convey("getIndexContent errors", func() {
metaDB.GetRepoMetaFn = func(repo string) (mTypes.RepoMetadata, error) {
return mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{
"tag": {
Digest: indexDigest.String(),
MediaType: ispec.MediaTypeImageIndex,
},
},
}, nil
}
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{}, zerr.ErrIndexDataNotFount
}
scanner := cveinfo.NewScanner(storeController, metaDB, "", "", log)
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, log)
_, err := cveInfo.GetImageListWithCVEFixed("repo", Vulnerability1ID)
So(err, ShouldBeNil)
})
Convey("getIndexContent bad indexDigest", func() {
metaDB.GetRepoMetaFn = func(repo string) (mTypes.RepoMetadata, error) {
return mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{
"tag": {
Digest: "bad digest",
MediaType: ispec.MediaTypeImageIndex,
},
},
}, nil
}
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{}, zerr.ErrIndexDataNotFount
}
scanner := cveinfo.NewScanner(storeController, metaDB, "", "", log)
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, log)
_, err := cveInfo.GetImageListWithCVEFixed("repo", Vulnerability1ID)
So(err, ShouldBeNil)
})
Convey("getIndexContent bad index content", func() {
metaDB.GetRepoMetaFn = func(repo string) (mTypes.RepoMetadata, error) {
return mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{
"tag": {
Digest: indexDigest.String(),
MediaType: ispec.MediaTypeImageIndex,
},
},
}, nil
}
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{IndexBlob: []byte(`bad index`)}, nil
}
scanner := cveinfo.NewScanner(storeController, metaDB, "", "", log)
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, log)
_, err := cveInfo.GetImageListWithCVEFixed("repo", Vulnerability1ID)
So(err, ShouldBeNil)
})
Convey("getTagInfoForManifest bad manifest digest", func() {
metaDB.GetRepoMetaFn = func(repo string) (mTypes.RepoMetadata, error) {
return mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{
"tag": {
Digest: "bad digest",
MediaType: ispec.MediaTypeImageManifest,
},
},
}, nil
}
scanner := cveinfo.NewScanner(storeController, metaDB, "", "", log)
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, log)
_, err := cveInfo.GetImageListWithCVEFixed("repo", Vulnerability1ID)
So(err, ShouldBeNil)
})
Convey("getTagInfoForManifest fails for index", func() {
metaDB.GetRepoMetaFn = func(repo string) (mTypes.RepoMetadata, error) {
return mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{
"tag": {
Digest: indexDigest.String(),
MediaType: ispec.MediaTypeImageIndex,
},
},
}, nil
}
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{
IndexBlob: []byte(fmt.Sprintf(`{
"manifests": [
{
"digest": "%s",
"mediaType": "application/vnd.oci.image.manifest.v1+json"
}
]}`, manifestDigest)),
}, nil
}
metaDB.GetManifestDataFn = func(manifestDigest godigest.Digest) (mTypes.ManifestData, error) {
return mTypes.ManifestData{}, zerr.ErrManifestDataNotFound
}
scanner := cveinfo.NewScanner(storeController, metaDB, "", "", log)
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, log)
tagsInfo, err := cveInfo.GetImageListWithCVEFixed("repo", Vulnerability1ID)
So(err, ShouldBeNil)
So(tagsInfo, ShouldBeEmpty)
})
Convey("media type not supported", func() {
metaDB.GetRepoMetaFn = func(repo string) (mTypes.RepoMetadata, error) {
return mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{
"tag": {
Digest: godigest.FromString("media type").String(),
MediaType: "bad media type",
},
},
}, nil
}
scanner := cveinfo.NewScanner(storeController, metaDB, "", "", log)
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, log)
tagsInfo, err := cveInfo.GetImageListWithCVEFixed("repo", Vulnerability1ID)
So(err, ShouldBeNil)
So(tagsInfo, ShouldBeEmpty)
})
})
}
func TestGetCVESummaryForImageMediaErrors(t *testing.T) { func TestGetCVESummaryForImageMediaErrors(t *testing.T) {
Convey("Errors", t, func() { Convey("Errors", t, func() {
storeController := storage.StoreController{} storeController := storage.StoreController{}

View File

@ -4,13 +4,11 @@
package cveinfo_test package cveinfo_test
import ( import (
"encoding/json"
"fmt" "fmt"
"sort" "sort"
"testing" "testing"
"time" "time"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
@ -18,7 +16,7 @@ import (
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model" cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/boltdb" "zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types" . "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks" "zotregistry.io/zot/pkg/test/mocks"
) )
@ -36,70 +34,26 @@ func TestCVEPagination(t *testing.T) {
// Create metadb data for scannable image with vulnerabilities // Create metadb data for scannable image with vulnerabilities
timeStamp11 := time.Date(2008, 1, 1, 12, 0, 0, 0, time.UTC) timeStamp11 := time.Date(2008, 1, 1, 12, 0, 0, 0, time.UTC)
configBlob11, err := json.Marshal(ispec.Image{ image := CreateImageWith().
Created: &timeStamp11, Layers([]Layer{{
})
So(err, ShouldBeNil)
manifestBlob11, err := json.Marshal(ispec.Manifest{
Config: ispec.Descriptor{
MediaType: ispec.MediaTypeImageConfig,
Size: 0,
Digest: godigest.FromBytes(configBlob11),
},
Layers: []ispec.Descriptor{
{
MediaType: ispec.MediaTypeImageLayerGzip, MediaType: ispec.MediaTypeImageLayerGzip,
Size: 0, Digest: ispec.DescriptorEmptyJSON.Digest,
Digest: godigest.NewDigestFromEncoded(godigest.SHA256, "digest"), Blob: ispec.DescriptorEmptyJSON.Data,
}, }}).ImageConfig(ispec.Image{Created: &timeStamp11}).Build()
},
})
So(err, ShouldBeNil)
repoMeta11 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo1", "0.1.0", image.AsImageMeta())
ManifestBlob: manifestBlob11,
ConfigBlob: configBlob11,
}
digest11 := godigest.FromBytes(manifestBlob11)
err = metaDB.SetManifestMeta("repo1", digest11, repoMeta11)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "0.1.0", digest11, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
timeStamp12 := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC) timeStamp12 := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC)
configBlob12, err := json.Marshal(ispec.Image{ image2 := CreateImageWith().
Created: &timeStamp12, Layers([]Layer{{
})
So(err, ShouldBeNil)
manifestBlob12, err := json.Marshal(ispec.Manifest{
Config: ispec.Descriptor{
MediaType: ispec.MediaTypeImageConfig,
Size: 0,
Digest: godigest.FromBytes(configBlob12),
},
Layers: []ispec.Descriptor{
{
MediaType: ispec.MediaTypeImageLayerGzip, MediaType: ispec.MediaTypeImageLayerGzip,
Size: 0, Digest: ispec.DescriptorEmptyJSON.Digest,
Digest: godigest.NewDigestFromEncoded(godigest.SHA256, "digest"), Blob: ispec.DescriptorEmptyJSON.Data,
}, }}).ImageConfig(ispec.Image{Created: &timeStamp12}).Build()
},
})
So(err, ShouldBeNil)
repoMeta12 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo1", "1.0.0", image2.AsImageMeta())
ManifestBlob: manifestBlob12,
ConfigBlob: configBlob12,
}
digest12 := godigest.FromBytes(manifestBlob12)
err = metaDB.SetManifestMeta("repo1", digest12, repoMeta12)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "1.0.0", digest12, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// MetaDB loaded with initial data, mock the scanner // MetaDB loaded with initial data, mock the scanner

View File

@ -4,8 +4,6 @@ import (
"context" "context"
"sync" "sync"
godigest "github.com/opencontainers/go-digest"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
reqCtx "zotregistry.io/zot/pkg/requestcontext" reqCtx "zotregistry.io/zot/pkg/requestcontext"
@ -43,13 +41,13 @@ type scanTaskGenerator struct {
} }
func (gen *scanTaskGenerator) getMatcherFunc() mTypes.FilterFunc { func (gen *scanTaskGenerator) getMatcherFunc() mTypes.FilterFunc {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
// Note this matcher will return information based on scan status of manifests // Note this matcher will return information based on scan status of manifests
// An index scan aggregates results of manifest scans // An index scan aggregates results of manifest scans
// If at least one of its manifests can be scanned, // If at least one of its manifests can be scanned,
// the index and its tag will be returned by the caller function too // the index and its tag will be returned by the caller function too
repoName := repoMeta.Name repoName := repoMeta.Name
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String() manifestDigest := imageMeta.Digest.String()
if gen.isScheduled(manifestDigest) { if gen.isScheduled(manifestDigest) {
// We skip this manifest as it has already scheduled // We skip this manifest as it has already scheduled
@ -121,18 +119,18 @@ func (gen *scanTaskGenerator) Next() (scheduler.Task, error) {
userAc.SetIsAdmin(true) userAc.SetIsAdmin(true)
ctx := userAc.DeriveContext(context.Background()) ctx := userAc.DeriveContext(context.Background())
// Obtain a list of repos with unscanned scannable manifests // Obtain a list of repos with un-scanned scannable manifests
// We may implement a method to return just 1 match at some point // We may implement a method to return just 1 match at some point
reposMeta, _, _, err := gen.metaDB.FilterTags(ctx, gen.getMatcherFunc()) imageMeta, err := gen.metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, gen.getMatcherFunc())
if err != nil { if err != nil {
// Do not crash the generator for potential repodb inconistencies // Do not crash the generator for potential metadb inconsistencies
// as there may be scannable images not yet scanned // as there may be scannable images not yet scanned
gen.log.Warn().Err(err).Msg("Scheduled CVE scan: error while obtaining repo metadata") gen.log.Warn().Err(err).Msg("Scheduled CVE scan: error while obtaining repo metadata")
} }
// no reposMeta are returned, all results are in already in cache // no imageMeta are returned, all results are in already in cache
// or manifests cannot be scanned // or manifests cannot be scanned
if len(reposMeta) == 0 { if len(imageMeta) == 0 {
gen.log.Info().Msg("Scheduled CVE scan: finished for available images") gen.log.Info().Msg("Scheduled CVE scan: finished for available images")
gen.done = true gen.done = true
@ -140,23 +138,14 @@ func (gen *scanTaskGenerator) Next() (scheduler.Task, error) {
return nil, nil return nil, nil
} }
// Since reposMeta will always contain just unscanned images we can pick // Since imageMeta will always contain just un-scanned images we can pick
// any repo and any tag out of the resulting matches // any image out of the resulting matches
repoMeta := reposMeta[0] digest := imageMeta[0].Digest.String()
var digest string
// Pick any tag
for _, descriptor := range repoMeta.Tags {
digest = descriptor.Digest
break
}
// Mark the digest as scheduled so it is skipped on next generator run // Mark the digest as scheduled so it is skipped on next generator run
gen.setScheduled(digest, true) gen.setScheduled(digest, true)
return newScanTask(gen, repoMeta.Name, digest), nil return newScanTask(gen, imageMeta[0].Repo, digest), nil
} }
func (gen *scanTaskGenerator) IsDone() bool { func (gen *scanTaskGenerator) IsDone() bool {

View File

@ -5,7 +5,6 @@ package cveinfo_test
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"io" "io"
"os" "os"
@ -69,77 +68,38 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
metaDB, err := boltdb.New(boltDriver, log.NewLogger("debug", "")) metaDB, err := boltdb.New(boltDriver, log.NewLogger("debug", ""))
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Refactor Idea: We can use InitializeTestMetaDB
// Create metadb data for scannable image with vulnerabilities // Create metadb data for scannable image with vulnerabilities
image11 := CreateImageWith().DefaultLayers(). image11 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2008, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2008, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta11 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo1", "0.1.0", image11.AsImageMeta())
ManifestBlob: image11.ManifestDescriptor.Data,
ConfigBlob: image11.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta("repo1", image11.ManifestDescriptor.Digest, repoMeta11)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "0.1.0", image11.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image12 := CreateImageWith().DefaultLayers(). image12 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta12 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo1", "1.0.0", image12.AsImageMeta())
ManifestBlob: image12.ManifestDescriptor.Data,
ConfigBlob: image12.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta("repo1", image12.ManifestDescriptor.Digest, repoMeta12)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "1.0.0", image12.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image13 := CreateImageWith().DefaultLayers(). image13 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta13 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo1", "1.1.0", image13.AsImageMeta())
ManifestBlob: image13.ManifestDescriptor.Data,
ConfigBlob: image13.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta("repo1", image13.ManifestDescriptor.Digest, repoMeta13)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "1.1.0", image13.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image14 := CreateImageWith().DefaultLayers(). image14 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2011, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2011, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta14 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo1", "1.0.1", image14.AsImageMeta())
ManifestBlob: image14.ManifestDescriptor.Data,
ConfigBlob: image14.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo1", image14.ManifestDescriptor.Digest, repoMeta14)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "1.0.1", image14.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create metadb data for scannable image with no vulnerabilities // Create metadb data for scannable image with no vulnerabilities
image61 := CreateImageWith().DefaultLayers(). image61 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2016, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2016, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta61 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo6", "1.0.0", image61.AsImageMeta())
ManifestBlob: image61.ManifestDescriptor.Data,
ConfigBlob: image61.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo6", image61.ManifestDescriptor.Digest, repoMeta61)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo6", "1.0.0", image61.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create metadb data for image not supporting scanning // Create metadb data for image not supporting scanning
@ -149,104 +109,58 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
Digest: godigest.FromBytes([]byte{10, 10, 10}), Digest: godigest.FromBytes([]byte{10, 10, 10}),
}}).ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() }}).ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta21 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo2", "1.0.0", image21.AsImageMeta())
ManifestBlob: image21.ManifestDescriptor.Data,
ConfigBlob: image21.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo2", image21.ManifestDescriptor.Digest, repoMeta21)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo2", "1.0.0", image21.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create metadb data for invalid images/negative tests // Create metadb data for invalid images/negative tests
manifestBlob31 := []byte("invalid manifest blob") img := CreateRandomImage()
So(err, ShouldBeNil) digest31 := img.Digest()
repoMeta31 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo3", "invalid-manifest", img.AsImageMeta())
ManifestBlob: manifestBlob31,
}
digest31 := godigest.FromBytes(manifestBlob31)
err = metaDB.SetManifestMeta("repo3", digest31, repoMeta31)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo3", "invalid-manifest", digest31, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
image41 := CreateImageWith().DefaultLayers(). image41 := CreateImageWith().DefaultLayers().
CustomConfigBlob([]byte("invalid config blob"), ispec.MediaTypeImageConfig).Build() CustomConfigBlob([]byte("invalid config blob"), ispec.MediaTypeImageConfig).Build()
repoMeta41 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo4", "invalid-config", image41.AsImageMeta())
ManifestBlob: image41.ManifestDescriptor.Data,
ConfigBlob: image41.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo4", image41.ManifestDescriptor.Digest, repoMeta41)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo4", "invalid-config", image41.ManifestDescriptor.Digest,
ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
digest51 := godigest.FromString("abc8") image15 := CreateRandomMultiarch()
err = metaDB.SetRepoReference("repo5", "nonexitent-manifest", digest51, ispec.MediaTypeImageManifest)
digest51 := image15.Digest()
err = metaDB.SetRepoReference("repo5", "nonexitent-manifests-for-multiarch", image15.AsImageMeta())
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create metadb data for scannable image which errors during scan // Create metadb data for scannable image which errors during scan
image71 := CreateImageWith().DefaultLayers(). image71 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2000, 1, 1, 12, 0, 0, 0, time.UTC)}).Build() ImageConfig(ispec.Image{Created: DateRef(2000, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta71 := mTypes.ManifestMetadata{ err = metaDB.SetRepoReference("repo7", "1.0.0", image71.AsImageMeta())
ManifestBlob: image71.ManifestDescriptor.Data,
ConfigBlob: image71.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo7", image71.ManifestDescriptor.Digest, repoMeta71)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo7", "1.0.0", image71.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create multiarch image with vulnerabilities // Create multiarch image with vulnerabilities
multiarchImage := CreateRandomMultiarch() multiarchImage := CreateRandomMultiarch()
err = metaDB.SetIndexData( err = metaDB.SetRepoReference(repoIndex, multiarchImage.Images[0].DigestStr(),
multiarchImage.IndexDescriptor.Digest, multiarchImage.Images[0].AsImageMeta())
mTypes.IndexData{IndexBlob: multiarchImage.IndexDescriptor.Data}, So(err, ShouldBeNil)
) err = metaDB.SetRepoReference(repoIndex, multiarchImage.Images[1].DigestStr(),
multiarchImage.Images[1].AsImageMeta())
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repoIndex, multiarchImage.Images[2].DigestStr(),
multiarchImage.Images[2].AsImageMeta())
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = metaDB.SetManifestData( err = metaDB.SetRepoReference(repoIndex, "tagIndex", multiarchImage.AsImageMeta())
multiarchImage.Images[0].ManifestDescriptor.Digest, So(err, ShouldBeNil)
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[0].ManifestDescriptor.Data, err = metaDB.SetRepoMeta("repo-with-bad-tag-digest", mTypes.RepoMeta{
ConfigBlob: multiarchImage.Images[0].ConfigDescriptor.Data, Name: "repo-with-bad-tag-digest",
Tags: map[string]mTypes.Descriptor{
"tag": {MediaType: ispec.MediaTypeImageManifest, Digest: godigest.FromString("1").String()},
"tag-multi-arch": {MediaType: ispec.MediaTypeImageIndex, Digest: godigest.FromString("2").String()},
}, },
) })
So(err, ShouldBeNil)
err = metaDB.SetManifestData(
multiarchImage.Images[1].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[1].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[1].ConfigDescriptor.Data,
},
)
So(err, ShouldBeNil)
err = metaDB.SetManifestData(
multiarchImage.Images[2].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[2].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[2].ConfigDescriptor.Data,
},
)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(
repoIndex,
"tagIndex",
multiarchImage.IndexDescriptor.Digest,
ispec.MediaTypeImageIndex,
)
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Keep a record of all the image references / digest pairings // Keep a record of all the image references / digest pairings
@ -274,7 +188,7 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
image41Digest := image41.ManifestDescriptor.Digest.String() image41Digest := image41.ManifestDescriptor.Digest.String()
image41Name := "repo4:invalid-config" image41Name := "repo4:invalid-config"
imageMap[image41Name] = image41Digest imageMap[image41Name] = image41Digest
image51Name := "repo5:nonexitent-manifest" image51Name := "repo5:nonexitent-manifest-for-multiarch"
imageMap[image51Name] = digest51.String() imageMap[image51Name] = digest51.String()
image61Digest := image61.ManifestDescriptor.Digest.String() image61Digest := image61.ManifestDescriptor.Digest.String()
image61Name := "repo6:1.0.0" image61Name := "repo6:1.0.0"
@ -296,7 +210,7 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
imageMap[indexM3Name] = indexM3Digest imageMap[indexM3Name] = indexM3Digest
// Initialize a test CVE cache // Initialize a test CVE cache
cache := cvecache.NewCveCache(10, logger) cache := cvecache.NewCveCache(20, logger)
// MetaDB loaded with initial data, now mock the scanner // MetaDB loaded with initial data, now mock the scanner
// Setup test CVE data in mock scanner // Setup test CVE data in mock scanner
@ -440,7 +354,7 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
// Almost same logic compared to actual Trivy specific implementation // Almost same logic compared to actual Trivy specific implementation
imageDir, inputTag := repo, reference imageDir, inputTag := repo, reference
repoMeta, err := metaDB.GetRepoMeta(imageDir) repoMeta, err := metaDB.GetRepoMeta(context.Background(), imageDir)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -463,19 +377,12 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
return false, err return false, err
} }
manifestData, err := metaDB.GetManifestData(manifestDigest) manifestData, err := metaDB.GetImageMeta(manifestDigest)
if err != nil { if err != nil {
return false, err return false, err
} }
var manifestContent ispec.Manifest for _, imageLayer := range manifestData.Manifests[0].Manifest.Layers {
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
return false, zerr.ErrScanNotSupported
}
for _, imageLayer := range manifestContent.Layers {
switch imageLayer.MediaType { switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer): case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
@ -531,7 +438,7 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
// Make sure the scanner generator has completed despite errors // Make sure the scanner generator has completed despite errors
found, err := test.ReadLogFileAndSearchString(logPath, found, err := test.ReadLogFileAndSearchString(logPath,
"Scheduled CVE scan: finished for available images", 20*time.Second) "Scheduled CVE scan: finished for available images", 40*time.Second)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(found, ShouldBeTrue) So(found, ShouldBeTrue)
@ -546,13 +453,12 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
t.Log("expecting " + image + " " + digestStr + " to be present in cache") t.Log("expecting " + image + " " + digestStr + " to be present in cache")
So(scanner.IsResultCached(digestStr), ShouldBeTrue) So(scanner.IsResultCached(digestStr), ShouldBeTrue)
} else { } else {
// We don't cache results for unscannable manifests // We don't cache results for un-scannable manifests
t.Log("expecting " + image + " " + digestStr + " to be absent from cache") t.Log("expecting " + image + " " + digestStr + " to be absent from cache")
So(scanner.IsResultCached(digestStr), ShouldBeFalse) So(scanner.IsResultCached(digestStr), ShouldBeFalse)
} }
} }
// Make sure the scanner generator is catching the metadb error for repo5:nonexitent-manifest
found, err = test.ReadLogFileAndSearchString(logPath, found, err = test.ReadLogFileAndSearchString(logPath,
"Scheduled CVE scan: error while obtaining repo metadata", 20*time.Second) "Scheduled CVE scan: error while obtaining repo metadata", 20*time.Second)
So(err, ShouldBeNil) So(err, ShouldBeNil)

View File

@ -2,7 +2,6 @@ package trivy
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"os" "os"
"path" "path"
@ -26,7 +25,6 @@ import (
cvecache "zotregistry.io/zot/pkg/extensions/search/cve/cache" cvecache "zotregistry.io/zot/pkg/extensions/search/cve/cache"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model" cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
mcommon "zotregistry.io/zot/pkg/meta/common"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage"
) )
@ -193,7 +191,7 @@ func (scanner Scanner) IsImageFormatScannable(repo, ref string) (bool, error) {
) )
if zcommon.IsTag(ref) { if zcommon.IsTag(ref) {
imgDescriptor, err := mcommon.GetImageDescriptor(scanner.metaDB, repo, ref) imgDescriptor, err := getImageDescriptor(scanner.metaDB, repo, ref)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -203,7 +201,7 @@ func (scanner Scanner) IsImageFormatScannable(repo, ref string) (bool, error) {
} else { } else {
var found bool var found bool
found, mediaType = mcommon.FindMediaTypeForDigest(scanner.metaDB, godigest.Digest(ref)) found, mediaType = findMediaTypeForDigest(scanner.metaDB, godigest.Digest(ref))
if !found { if !found {
return false, zerr.ErrManifestNotFound return false, zerr.ErrManifestNotFound
} }
@ -224,7 +222,7 @@ func (scanner Scanner) IsImageMediaScannable(repo, digestStr, mediaType string)
return ok, nil return ok, nil
case ispec.MediaTypeImageIndex: case ispec.MediaTypeImageIndex:
ok, err := scanner.isIndexScanable(digestStr) ok, err := scanner.isIndexScannable(digestStr)
if err != nil { if err != nil {
return ok, fmt.Errorf("image '%s' %w", image, err) return ok, fmt.Errorf("image '%s' %w", image, err)
} }
@ -240,21 +238,16 @@ func (scanner Scanner) isManifestScanable(digestStr string) (bool, error) {
return true, nil return true, nil
} }
manifestData, err := scanner.metaDB.GetManifestData(godigest.Digest(digestStr)) manifestData, err := scanner.metaDB.GetImageMeta(godigest.Digest(digestStr))
if err != nil { if err != nil {
return false, err return false, err
} }
var manifestContent ispec.Manifest if manifestData.MediaType != ispec.MediaTypeImageManifest {
return false, zerr.ErrUnexpectedMediaType
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
scanner.log.Error().Err(err).Msg("unable to unmashal manifest blob")
return false, zerr.ErrScanNotSupported
} }
for _, imageLayer := range manifestContent.Layers { for _, imageLayer := range manifestData.Manifests[0].Manifest.Layers {
switch imageLayer.MediaType { switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer): case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
continue continue
@ -266,34 +259,54 @@ func (scanner Scanner) isManifestScanable(digestStr string) (bool, error) {
return true, nil return true, nil
} }
func (scanner Scanner) isIndexScanable(digestStr string) (bool, error) { func (scanner Scanner) isManifestDataScannable(manifestData mTypes.ManifestData) (bool, error) {
if scanner.cache.Get(manifestData.Digest.String()) != nil {
return true, nil
}
if manifestData.Manifest.MediaType != ispec.MediaTypeImageManifest {
return false, zerr.ErrScanNotSupported
}
for _, imageLayer := range manifestData.Manifest.Layers {
switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
continue
default:
return false, zerr.ErrScanNotSupported
}
}
return true, nil
}
func (scanner Scanner) isIndexScannable(digestStr string) (bool, error) {
if scanner.cache.Get(digestStr) != nil { if scanner.cache.Get(digestStr) != nil {
return true, nil return true, nil
} }
indexData, err := scanner.metaDB.GetIndexData(godigest.Digest(digestStr)) indexData, err := scanner.metaDB.GetImageMeta(godigest.Digest(digestStr))
if err != nil { if err != nil {
return false, err return false, err
} }
var indexContent ispec.Index if indexData.MediaType != ispec.MediaTypeImageIndex || indexData.Index == nil {
return false, zerr.ErrUnexpectedMediaType
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
return false, err
} }
indexContent := *indexData.Index
if len(indexContent.Manifests) == 0 { if len(indexContent.Manifests) == 0 {
return true, nil return true, nil
} }
for _, manifest := range indexContent.Manifests { for _, manifest := range indexData.Manifests {
isScannable, err := scanner.isManifestScanable(manifest.Digest.String()) isScannable, err := scanner.isManifestDataScannable(manifest)
if err != nil { if err != nil {
continue continue
} }
// if at least 1 manifest is scanable, the whole index is scanable // if at least 1 manifest is scannable, the whole index is scannable
if isScannable { if isScannable {
return true, nil return true, nil
} }
@ -323,7 +336,7 @@ func (scanner Scanner) ScanImage(image string) (map[string]cvemodel.CVE, error)
digest = ref digest = ref
if isTag { if isTag {
imgDescriptor, err := mcommon.GetImageDescriptor(scanner.metaDB, repo, ref) imgDescriptor, err := getImageDescriptor(scanner.metaDB, repo, ref)
if err != nil { if err != nil {
return map[string]cvemodel.CVE{}, err return map[string]cvemodel.CVE{}, err
} }
@ -333,7 +346,7 @@ func (scanner Scanner) ScanImage(image string) (map[string]cvemodel.CVE, error)
} else { } else {
var found bool var found bool
found, mediaType = mcommon.FindMediaTypeForDigest(scanner.metaDB, godigest.Digest(ref)) found, mediaType = findMediaTypeForDigest(scanner.metaDB, godigest.Digest(ref))
if !found { if !found {
return map[string]cvemodel.CVE{}, zerr.ErrManifestNotFound return map[string]cvemodel.CVE{}, zerr.ErrManifestNotFound
} }
@ -441,21 +454,18 @@ func (scanner Scanner) scanIndex(repo, digest string) (map[string]cvemodel.CVE,
return cachedMap, nil return cachedMap, nil
} }
indexData, err := scanner.metaDB.GetIndexData(godigest.Digest(digest)) indexData, err := scanner.metaDB.GetImageMeta(godigest.Digest(digest))
if err != nil { if err != nil {
return map[string]cvemodel.CVE{}, err return map[string]cvemodel.CVE{}, err
} }
var indexContent ispec.Index if indexData.Index == nil {
return map[string]cvemodel.CVE{}, zerr.ErrUnexpectedMediaType
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
return map[string]cvemodel.CVE{}, err
} }
indexCveIDMap := map[string]cvemodel.CVE{} indexCveIDMap := map[string]cvemodel.CVE{}
for _, manifest := range indexContent.Manifests { for _, manifest := range indexData.Index.Manifests {
if isScannable, err := scanner.isManifestScanable(manifest.Digest.String()); isScannable && err == nil { if isScannable, err := scanner.isManifestScanable(manifest.Digest.String()); isScannable && err == nil {
manifestCveIDMap, err := scanner.scanManifest(repo, manifest.Digest.String()) manifestCveIDMap, err := scanner.scanManifest(repo, manifest.Digest.String())
if err != nil { if err != nil {
@ -567,6 +577,31 @@ func (scanner Scanner) checkDBPresence() error {
return nil return nil
} }
func getImageDescriptor(metaDB mTypes.MetaDB, repo, tag string) (mTypes.Descriptor, error) {
repoMeta, err := metaDB.GetRepoMeta(context.Background(), repo)
if err != nil {
return mTypes.Descriptor{}, err
}
imageDescriptor, ok := repoMeta.Tags[tag]
if !ok {
return mTypes.Descriptor{}, zerr.ErrTagMetaNotFound
}
return imageDescriptor, nil
}
// findMediaTypeForDigest will look into the buckets for a certain digest. Depending on which bucket that
// digest is found the corresponding mediatype is returned.
func findMediaTypeForDigest(metaDB mTypes.MetaDB, digest godigest.Digest) (bool, string) {
imageMeta, err := metaDB.GetImageMeta(digest)
if err == nil {
return true, imageMeta.MediaType
}
return false, ""
}
func convertSeverity(detectedSeverity string) string { func convertSeverity(detectedSeverity string) string {
trivySeverity, _ := dbTypes.NewSeverity(detectedSeverity) trivySeverity, _ := dbTypes.NewSeverity(detectedSeverity)

View File

@ -22,7 +22,7 @@ import (
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta" "zotregistry.io/zot/pkg/meta"
"zotregistry.io/zot/pkg/meta/boltdb" "zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types" "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/imagestore" "zotregistry.io/zot/pkg/storage/imagestore"
"zotregistry.io/zot/pkg/storage/local" "zotregistry.io/zot/pkg/storage/local"
@ -288,114 +288,31 @@ func TestImageScannable(t *testing.T) {
// Create metadb data for scannable image // Create metadb data for scannable image
timeStamp := time.Date(2008, 1, 1, 12, 0, 0, 0, time.UTC) timeStamp := time.Date(2008, 1, 1, 12, 0, 0, 0, time.UTC)
validConfigBlob, err := json.Marshal(ispec.Image{ validConfig := ispec.Image{
Created: &timeStamp, Created: &timeStamp,
})
if err != nil {
panic(err)
} }
validManifestBlob, err := json.Marshal(ispec.Manifest{ validImage := CreateImageWith().
Config: ispec.Descriptor{ Layers([]Layer{{
MediaType: ispec.MediaTypeImageConfig,
Size: 0,
Digest: godigest.FromBytes(validConfigBlob),
},
Layers: []ispec.Descriptor{
{
MediaType: ispec.MediaTypeImageLayerGzip, MediaType: ispec.MediaTypeImageLayerGzip,
Size: 0, Digest: ispec.DescriptorEmptyJSON.Digest,
Digest: godigest.NewDigestFromEncoded(godigest.SHA256, "digest"), Blob: ispec.DescriptorEmptyJSON.Data,
}, }}).ImageConfig(validConfig).Build()
},
})
if err != nil {
panic(err)
}
validRepoMeta := mTypes.ManifestData{ err = metaDB.SetRepoReference("repo1", "valid", validImage.AsImageMeta())
ManifestBlob: validManifestBlob,
ConfigBlob: validConfigBlob,
}
digestValidManifest := godigest.FromBytes(validManifestBlob)
err = metaDB.SetManifestData(digestValidManifest, validRepoMeta)
if err != nil {
panic(err)
}
err = metaDB.SetRepoReference("repo1", "valid", digestValidManifest, ispec.MediaTypeImageManifest)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// Create MetaDB data for manifest with unscannable layers // Create MetaDB data for manifest with unscannable layers
manifestBlobUnscannableLayer, err := json.Marshal(ispec.Manifest{ imageWithUnscannableLayer := CreateImageWith().
Config: ispec.Descriptor{ Layers([]Layer{{
MediaType: ispec.MediaTypeImageConfig,
Size: 0,
Digest: godigest.FromBytes(validConfigBlob),
},
Layers: []ispec.Descriptor{
{
MediaType: "unscannable_media_type", MediaType: "unscannable_media_type",
Size: 0, Digest: ispec.DescriptorEmptyJSON.Digest,
Digest: godigest.NewDigestFromEncoded(godigest.SHA256, "digest"), Blob: ispec.DescriptorEmptyJSON.Data,
}, }}).ImageConfig(validConfig).Build()
},
})
if err != nil {
panic(err)
}
repoMetaUnscannableLayer := mTypes.ManifestData{ err = metaDB.SetRepoReference("repo1", "unscannable-layer", imageWithUnscannableLayer.AsImageMeta())
ManifestBlob: manifestBlobUnscannableLayer,
ConfigBlob: validConfigBlob,
}
digestManifestUnscannableLayer := godigest.FromBytes(manifestBlobUnscannableLayer)
err = metaDB.SetManifestData(digestManifestUnscannableLayer, repoMetaUnscannableLayer)
if err != nil {
panic(err)
}
err = metaDB.SetRepoReference("repo1", "unscannable-layer", digestManifestUnscannableLayer,
ispec.MediaTypeImageManifest)
if err != nil {
panic(err)
}
// Create MetaDB data for unmarshable manifest
unmarshableManifestBlob := []byte("Some string")
repoMetaUnmarshable := mTypes.ManifestData{
ManifestBlob: unmarshableManifestBlob,
ConfigBlob: validConfigBlob,
}
digestUnmarshableManifest := godigest.FromBytes(unmarshableManifestBlob)
err = metaDB.SetManifestData(digestUnmarshableManifest, repoMetaUnmarshable)
if err != nil {
panic(err)
}
err = metaDB.SetRepoReference("repo1", "unmarshable", digestUnmarshableManifest, ispec.MediaTypeImageManifest)
if err != nil {
panic(err)
}
// Manifest meta cannot be found
digestMissingManifest := godigest.FromBytes([]byte("Some other string"))
err = metaDB.SetRepoReference("repo1", "missing", digestMissingManifest, ispec.MediaTypeImageManifest)
if err != nil {
panic(err)
}
// RepoMeta contains invalid digest
err = metaDB.SetRepoReference("repo1", "invalid-digest", "invalid", ispec.MediaTypeImageManifest)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -423,18 +340,6 @@ func TestImageScannable(t *testing.T) {
So(result, ShouldBeFalse) So(result, ShouldBeFalse)
}) })
Convey("Image with unmarshable manifests should be unscannable", t, func() {
result, err := scanner.IsImageFormatScannable("repo1", "unmarshable")
So(err, ShouldNotBeNil)
So(result, ShouldBeFalse)
})
Convey("Image with missing manifest meta should be unscannable", t, func() {
result, err := scanner.IsImageFormatScannable("repo1", "missing")
So(err, ShouldNotBeNil)
So(result, ShouldBeFalse)
})
Convey("Image with invalid manifest digest should be unscannable", t, func() { Convey("Image with invalid manifest digest should be unscannable", t, func() {
result, err := scanner.IsImageFormatScannable("repo1", "invalid-digest") result, err := scanner.IsImageFormatScannable("repo1", "invalid-digest")
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
@ -523,14 +428,14 @@ func TestIsIndexScanable(t *testing.T) {
scanner.cache.Add("digest", make(map[string]model.CVE)) scanner.cache.Add("digest", make(map[string]model.CVE))
found, err := scanner.isIndexScanable("digest") found, err := scanner.isIndexScannable("digest")
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(found, ShouldBeTrue) So(found, ShouldBeTrue)
}) })
}) })
} }
func TestScanIndexErrors(t *testing.T) { func TestIsIndexScannableErrors(t *testing.T) {
Convey("Errors", t, func() { Convey("Errors", t, func() {
storeController := storage.StoreController{} storeController := storage.StoreController{}
storeController.DefaultStore = mocks.MockedImageStore{} storeController.DefaultStore = mocks.MockedImageStore{}
@ -538,107 +443,22 @@ func TestScanIndexErrors(t *testing.T) {
metaDB := mocks.MetaDBMock{} metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "") log := log.NewLogger("debug", "")
Convey("GetIndexData fails", func() { Convey("all manifests of a index are not scannable", func() {
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) { unscannableLayer := []Layer{{MediaType: "unscannable-layer-type", Digest: godigest.FromString("123")}}
return mTypes.IndexData{}, godigest.ErrDigestUnsupported img1 := CreateImageWith().Layers(unscannableLayer).RandomConfig().Build()
img2 := CreateImageWith().Layers(unscannableLayer).RandomConfig().Build()
multiarch := CreateMultiarchWith().Images([]Image{img1, img2}).Build()
metaDB.GetImageMetaFn = func(digest godigest.Digest) (types.ImageMeta, error) {
return map[string]types.ImageMeta{
img1.DigestStr(): img1.AsImageMeta(),
img2.DigestStr(): img2.AsImageMeta(),
multiarch.DigestStr(): multiarch.AsImageMeta(),
}[digest.String()], nil
} }
scanner := NewScanner(storeController, metaDB, "", "", log) scanner := NewScanner(storeController, metaDB, "", "", log)
ok, err := scanner.isIndexScannable(multiarch.DigestStr())
_, err := scanner.scanIndex("repo", "digest")
So(err, ShouldNotBeNil)
})
Convey("Bad Index Blob, Unamrshal fails", func() {
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{
IndexBlob: []byte(`bad-blob`),
}, nil
}
scanner := NewScanner(storeController, metaDB, "", "", log)
_, err := scanner.scanIndex("repo", "digest")
So(err, ShouldNotBeNil)
})
})
}
func TestIsIndexScanableErrors(t *testing.T) {
Convey("Errors", t, func() {
storeController := storage.StoreController{}
storeController.DefaultStore = mocks.MockedImageStore{}
metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "")
Convey("GetIndexData errors", func() {
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{}, zerr.ErrManifestDataNotFound
}
scanner := NewScanner(storeController, metaDB, "", "", log)
_, err := scanner.isIndexScanable("digest")
So(err, ShouldNotBeNil)
})
Convey("bad index data, can't unmarshal", func() {
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{IndexBlob: []byte(`bad`)}, nil
}
scanner := NewScanner(storeController, metaDB, "", "", log)
ok, err := scanner.isIndexScanable("digest")
So(err, ShouldNotBeNil)
So(ok, ShouldBeFalse)
})
Convey("is Manifest Scanable errors", func() {
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{IndexBlob: []byte(`{
"manifests": [{
"digest": "digest2"
},
{
"digest": "digest1"
}
]
}`)}, nil
}
metaDB.GetManifestDataFn = func(manifestDigest godigest.Digest) (mTypes.ManifestData, error) {
switch manifestDigest {
case "digest1":
return mTypes.ManifestData{
ManifestBlob: []byte("{}"),
}, nil
case "digest2":
return mTypes.ManifestData{}, zerr.ErrBadBlob
}
return mTypes.ManifestData{}, nil
}
scanner := NewScanner(storeController, metaDB, "", "", log)
ok, err := scanner.isIndexScanable("digest")
So(err, ShouldBeNil)
So(ok, ShouldBeTrue)
})
Convey("is Manifest Scanable returns false because no manifest is scanable", func() {
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{IndexBlob: []byte(`{
"manifests": [{
"digest": "digest2"
}
]
}`)}, nil
}
metaDB.GetManifestDataFn = func(manifestDigest godigest.Digest) (mTypes.ManifestData, error) {
return mTypes.ManifestData{}, zerr.ErrBadBlob
}
scanner := NewScanner(storeController, metaDB, "", "", log)
ok, err := scanner.isIndexScanable("digest")
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(ok, ShouldBeFalse) So(ok, ShouldBeFalse)
}) })

View File

@ -11,7 +11,6 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api" "zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config" "zotregistry.io/zot/pkg/api/config"
extconf "zotregistry.io/zot/pkg/extensions/config" extconf "zotregistry.io/zot/pkg/extensions/config"
@ -20,13 +19,11 @@ import (
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta" "zotregistry.io/zot/pkg/meta"
"zotregistry.io/zot/pkg/meta/boltdb" "zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/local" "zotregistry.io/zot/pkg/storage/local"
. "zotregistry.io/zot/pkg/test/common" . "zotregistry.io/zot/pkg/test/common"
"zotregistry.io/zot/pkg/test/deprecated" "zotregistry.io/zot/pkg/test/deprecated"
. "zotregistry.io/zot/pkg/test/image-utils" . "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks"
) )
func TestScanBigTestFile(t *testing.T) { func TestScanBigTestFile(t *testing.T) {
@ -130,31 +127,6 @@ func TestScanningByDigest(t *testing.T) {
}) })
} }
func TestScannerErrors(t *testing.T) {
digest := godigest.FromString("dig")
Convey("Errors", t, func() {
storeController := storage.StoreController{}
storeController.DefaultStore = mocks.MockedImageStore{}
metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "")
Convey("IsImageFormatSanable", func() {
metaDB.GetManifestDataFn = func(manifestDigest godigest.Digest) (mTypes.ManifestData, error) {
return mTypes.ManifestData{}, zerr.ErrManifestDataNotFound
}
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{}, zerr.ErrManifestDataNotFound
}
scanner := trivy.NewScanner(storeController, metaDB, "", "", log)
_, err := scanner.ScanImage("repo@" + digest.String())
So(err, ShouldNotBeNil)
})
})
}
func TestVulnerableLayer(t *testing.T) { func TestVulnerableLayer(t *testing.T) {
Convey("Vulnerable layer", t, func() { Convey("Vulnerable layer", t, func() {
vulnerableLayer, err := GetLayerWithVulnerability() vulnerableLayer, err := GetLayerWithVulnerability()

View File

@ -40,8 +40,8 @@ func TestCVEDBGenerator(t *testing.T) {
sch := scheduler.NewScheduler(cfg, logger) sch := scheduler.NewScheduler(cfg, logger)
metaDB := &mocks.MetaDBMock{ metaDB := &mocks.MetaDBMock{
GetRepoMetaFn: func(repo string) (mTypes.RepoMetadata, error) { GetRepoMetaFn: func(ctx context.Context, repo string) (mTypes.RepoMeta, error) {
return mTypes.RepoMetadata{ return mTypes.RepoMeta{
Tags: map[string]mTypes.Descriptor{ Tags: map[string]mTypes.Descriptor{
"tag": {MediaType: ispec.MediaTypeImageIndex}, "tag": {MediaType: ispec.MediaTypeImageIndex},
}, },

View File

@ -6,13 +6,11 @@ package search
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
"github.com/99designs/gqlgen/graphql"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/gqlerror"
@ -75,18 +73,14 @@ func NewResolver(log log.Logger, storeController storage.StoreController,
} }
func FilterByDigest(digest string) mTypes.FilterFunc { func FilterByDigest(digest string) mTypes.FilterFunc {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { // imageMeta will always contain 1 manifest
return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
lookupDigest := digest lookupDigest := digest
contains := false contains := false
var manifest ispec.Manifest manifest := imageMeta.Manifests[0]
err := json.Unmarshal(manifestMeta.ManifestBlob, &manifest) manifestDigest := manifest.Digest.String()
if err != nil {
return false
}
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String()
// Check the image manifest in index.json matches the search digest // Check the image manifest in index.json matches the search digest
// This is a blob with mediaType application/vnd.oci.image.manifest.v1+json // This is a blob with mediaType application/vnd.oci.image.manifest.v1+json
@ -96,13 +90,13 @@ func FilterByDigest(digest string) mTypes.FilterFunc {
// Check the image config matches the search digest // Check the image config matches the search digest
// This is a blob with mediaType application/vnd.oci.image.config.v1+json // This is a blob with mediaType application/vnd.oci.image.config.v1+json
if strings.Contains(manifest.Config.Digest.String(), lookupDigest) { if strings.Contains(manifest.Manifest.Config.Digest.String(), lookupDigest) {
contains = true contains = true
} }
// Check to see if the individual layers in the oci image manifest match the digest // Check to see if the individual layers in the oci image manifest match the digest
// These are blobs with mediaType application/vnd.oci.image.layer.v1.tar+gzip // These are blobs with mediaType application/vnd.oci.image.layer.v1.tar+gzip
for _, layer := range manifest.Layers { for _, layer := range manifest.Manifest.Layers {
if strings.Contains(layer.Digest.String(), lookupDigest) { if strings.Contains(layer.Digest.String(), lookupDigest) {
contains = true contains = true
} }
@ -124,21 +118,20 @@ func getImageListForDigest(ctx context.Context, digest string, metaDB mTypes.Met
} }
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaRelevance), deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
), ),
} }
// get all repos fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, FilterByDigest(digest))
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, FilterByDigest(digest))
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
imageSummaries, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList, skip,
indexDataMap, skip, cveInfo, mTypes.Filter{}, pageInput) cveInfo, mTypes.Filter{}, pageInput)
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
@ -157,7 +150,7 @@ func getImageSummary(ctx context.Context, repo, tag string, digest *string, skip
) ( ) (
*gql_generated.ImageSummary, error, *gql_generated.ImageSummary, error,
) { ) {
repoMeta, err := metaDB.GetRepoMeta(repo) repoMeta, err := metaDB.GetRepoMeta(ctx, repo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -167,108 +160,23 @@ func getImageSummary(ctx context.Context, repo, tag string, digest *string, skip
return nil, gqlerror.Errorf("can't find image: %s:%s", repo, tag) return nil, gqlerror.Errorf("can't find image: %s:%s", repo, tag)
} }
for t := range repoMeta.Tags { repoMeta.Tags = map[string]mTypes.Descriptor{tag: manifestDescriptor}
if t != tag {
delete(repoMeta.Tags, t)
}
}
var (
manifestMetaMap = map[string]mTypes.ManifestMetadata{}
indexDataMap = map[string]mTypes.IndexData{}
)
switch manifestDescriptor.MediaType {
case ispec.MediaTypeImageManifest:
manifestDigest := manifestDescriptor.Digest
if digest != nil && *digest != manifestDigest {
return nil, fmt.Errorf("resolver: can't get ManifestData for digest %s for image '%s:%s' %w",
manifestDigest, repo, tag, zerr.ErrManifestDataNotFound)
}
manifestData, err := metaDB.GetManifestData(godigest.Digest(manifestDigest))
if err != nil {
return nil, err
}
manifestMetaMap[manifestDigest] = mTypes.ManifestMetadata{
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob,
}
case ispec.MediaTypeImageIndex:
indexDigest := manifestDescriptor.Digest
indexData, err := metaDB.GetIndexData(godigest.Digest(indexDigest))
if err != nil {
return nil, err
}
var indexContent ispec.Index
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
return nil, err
}
imageDigest := manifestDescriptor.Digest
if digest != nil { if digest != nil {
manifestDigest := *digest imageDigest = *digest
digestFound := false
for _, manifest := range indexContent.Manifests {
if manifest.Digest.String() == manifestDigest {
digestFound = true
break
}
}
if !digestFound {
return nil, fmt.Errorf("resolver: can't get ManifestData for digest %s for image '%s:%s' %w",
manifestDigest, repo, tag, zerr.ErrManifestDataNotFound)
}
manifestData, err := metaDB.GetManifestData(godigest.Digest(manifestDigest))
if err != nil {
return nil, fmt.Errorf("resolver: can't get ManifestData for digest %s for image '%s:%s' %w",
manifestDigest, repo, tag, err)
}
manifestMetaMap[manifestDigest] = mTypes.ManifestMetadata{
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob,
}
// We update the tag descriptor to be the manifest descriptor with digest specified in the
// 'digest' parameter. We treat it as a standalone image.
repoMeta.Tags[tag] = mTypes.Descriptor{ repoMeta.Tags[tag] = mTypes.Descriptor{
Digest: manifestDigest, Digest: imageDigest,
MediaType: ispec.MediaTypeImageManifest, MediaType: ispec.MediaTypeImageManifest,
} }
break
} }
for _, manifest := range indexContent.Manifests { imageMetaMap, err := metaDB.FilterImageMeta(ctx, []string{imageDigest})
manifestData, err := metaDB.GetManifestData(manifest.Digest)
if err != nil { if err != nil {
return nil, fmt.Errorf("resolver: can't get ManifestData for digest %s for image '%s:%s' %w", return &gql_generated.ImageSummary{}, err
manifest.Digest, repo, tag, err)
} }
manifestMetaMap[manifest.Digest.String()] = mTypes.ManifestMetadata{ imageSummaries := convert.RepoMeta2ImageSummaries(ctx, repoMeta, imageMetaMap, skipCVE, cveInfo)
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob,
}
}
indexDataMap[indexDigest] = indexData
default:
log.Error().Str("mediaType", manifestDescriptor.MediaType).Msg("resolver: media type not supported")
}
imageSummaries := convert.RepoMeta2ImageSummaries(ctx, repoMeta, manifestMetaMap, indexDataMap, skipCVE, cveInfo)
if len(imageSummaries) == 0 { if len(imageSummaries) == 0 {
return &gql_generated.ImageSummary{}, nil return &gql_generated.ImageSummary{}, nil
@ -290,10 +198,10 @@ func getCVEListForImage(
} }
pageInput := cvemodel.PageInput{ pageInput := cvemodel.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: cvemodel.SortCriteria( SortBy: cvemodel.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaSeverity), deref(requestedPage.SortBy, gql_generated.SortCriteriaSeverity),
), ),
} }
@ -352,8 +260,8 @@ func getCVEListForImage(
} }
func FilterByTagInfo(tagsInfo []cvemodel.TagInfo) mTypes.FilterFunc { func FilterByTagInfo(tagsInfo []cvemodel.TagInfo) mTypes.FilterFunc {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String() manifestDigest := imageMeta.Manifests[0].Digest.String()
for _, tagInfo := range tagsInfo { for _, tagInfo := range tagsInfo {
switch tagInfo.Descriptor.MediaType { switch tagInfo.Descriptor.MediaType {
@ -375,12 +283,12 @@ func FilterByTagInfo(tagsInfo []cvemodel.TagInfo) mTypes.FilterFunc {
} }
func FilterByRepoAndTagInfo(repo string, tagsInfo []cvemodel.TagInfo) mTypes.FilterFunc { func FilterByRepoAndTagInfo(repo string, tagsInfo []cvemodel.TagInfo) mTypes.FilterFunc {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
if repoMeta.Name != repo { if repoMeta.Name != repo {
return false return false
} }
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String() manifestDigest := imageMeta.Manifests[0].Digest.String()
for _, tagInfo := range tagsInfo { for _, tagInfo := range tagsInfo {
switch tagInfo.Descriptor.MediaType { switch tagInfo.Descriptor.MediaType {
@ -414,7 +322,7 @@ func getImageListForCVE(
// Infinite page to make sure we scan all repos in advance, before filtering results // Infinite page to make sure we scan all repos in advance, before filtering results
// The CVE scan logic is called from here, not in the actual filter, // The CVE scan logic is called from here, not in the actual filter,
// this is because we shouldn't keep the DB locked while we wait on scan results // this is because we shouldn't keep the DB locked while we wait on scan results
reposMeta, err := metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMetadata) bool { return true }) reposMeta, err := metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMeta) bool { return true })
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
@ -457,21 +365,21 @@ func getImageListForCVE(
// Actual page requested by user // Actual page requested by user
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime), deref(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
), ),
} }
// get all repos // get all repos
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, FilterByTagInfo(affectedImages)) fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, FilterByTagInfo(affectedImages))
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
imageSummaries, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList,
indexDataMap, skip, cveInfo, localFilter, pageInput) skip, cveInfo, localFilter, pageInput)
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
@ -530,21 +438,21 @@ func getImageListWithCVEFixed(
// Actual page requested by user // Actual page requested by user
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime), deref(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
), ),
} }
// get all repos // get all repos
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, FilterByRepoAndTagInfo(repo, tagsInfo)) fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, FilterByRepoAndTagInfo(repo, tagsInfo))
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
imageSummaries, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList,
indexDataMap, skip, cveInfo, localFilter, pageInput) skip, cveInfo, localFilter, pageInput)
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
@ -576,20 +484,25 @@ func repoListWithNewestImage(
} }
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime), deref(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
), ),
} }
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.SearchRepos(ctx, "") repoMetaList, err := metaDB.SearchRepos(ctx, "")
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, err return &gql_generated.PaginatedReposResult{}, err
} }
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap, imageMetaMap, err := metaDB.FilterImageMeta(ctx, mTypes.GetLatestImageDigests(repoMetaList))
skip, cveInfo, mTypes.Filter{}, pageInput) if err != nil {
return &gql_generated.PaginatedReposResult{}, err
}
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, repoMetaList, imageMetaMap,
mTypes.Filter{}, pageInput, cveInfo, skip)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, err return &gql_generated.PaginatedReposResult{}, err
} }
@ -611,16 +524,16 @@ func getBookmarkedRepos(
requestedPage *gql_generated.PageInput, requestedPage *gql_generated.PageInput,
metaDB mTypes.MetaDB, metaDB mTypes.MetaDB,
) (*gql_generated.PaginatedReposResult, error) { ) (*gql_generated.PaginatedReposResult, error) {
repoNames, err := metaDB.GetBookmarkedRepos(ctx) bookmarkedRepos, err := metaDB.GetBookmarkedRepos(ctx)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, err return &gql_generated.PaginatedReposResult{}, err
} }
filterFn := func(repoMeta mTypes.RepoMetadata) bool { filterByName := func(repo string) bool {
return zcommon.Contains(repoNames, repoMeta.Name) return zcommon.Contains(bookmarkedRepos, repo)
} }
return getFilteredPaginatedRepos(ctx, cveInfo, filterFn, log, requestedPage, metaDB) return getFilteredPaginatedRepos(ctx, cveInfo, filterByName, log, requestedPage, metaDB)
} }
func getStarredRepos( func getStarredRepos(
@ -630,13 +543,13 @@ func getStarredRepos(
requestedPage *gql_generated.PageInput, requestedPage *gql_generated.PageInput,
metaDB mTypes.MetaDB, metaDB mTypes.MetaDB,
) (*gql_generated.PaginatedReposResult, error) { ) (*gql_generated.PaginatedReposResult, error) {
repoNames, err := metaDB.GetStarredRepos(ctx) starredRepos, err := metaDB.GetStarredRepos(ctx)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, err return &gql_generated.PaginatedReposResult{}, err
} }
filterFn := func(repoMeta mTypes.RepoMetadata) bool { filterFn := func(repo string) bool {
return zcommon.Contains(repoNames, repoMeta.Name) return zcommon.Contains(starredRepos, repo)
} }
return getFilteredPaginatedRepos(ctx, cveInfo, filterFn, log, requestedPage, metaDB) return getFilteredPaginatedRepos(ctx, cveInfo, filterFn, log, requestedPage, metaDB)
@ -645,7 +558,7 @@ func getStarredRepos(
func getFilteredPaginatedRepos( func getFilteredPaginatedRepos(
ctx context.Context, ctx context.Context,
cveInfo cveinfo.CveInfo, cveInfo cveinfo.CveInfo,
filterFn mTypes.FilterRepoFunc, filterFn mTypes.FilterRepoNameFunc,
log log.Logger, //nolint:unparam // may be used by devs for debugging log log.Logger, //nolint:unparam // may be used by devs for debugging
requestedPage *gql_generated.PageInput, requestedPage *gql_generated.PageInput,
metaDB mTypes.MetaDB, metaDB mTypes.MetaDB,
@ -659,20 +572,25 @@ func getFilteredPaginatedRepos(
} }
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime), deref(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
), ),
} }
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterRepos(ctx, filterFn) repoMetaList, err := metaDB.FilterRepos(ctx, filterFn, mTypes.AcceptAllRepoMeta)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, err return &gql_generated.PaginatedReposResult{}, err
} }
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap, latestImageMeta, err := metaDB.FilterImageMeta(ctx, mTypes.GetLatestImageDigests(repoMetaList))
skip, cveInfo, mTypes.Filter{}, pageInput) if err != nil {
return &gql_generated.PaginatedReposResult{}, err
}
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, repoMetaList, latestImageMeta,
mTypes.Filter{}, pageInput, cveInfo, skip)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, err return &gql_generated.PaginatedReposResult{}, err
} }
@ -716,22 +634,31 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte
} }
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaRelevance), deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
), ),
} }
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.SearchRepos(ctx, query) repoMetaList, err := metaDB.SearchRepos(ctx, query)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{},
[]*gql_generated.LayerSummary{}, err
} }
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap, imageMetaMap, err := metaDB.FilterImageMeta(ctx, mTypes.GetLatestImageDigests(repoMetaList))
skip, cveInfo, localFilter, pageInput)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{},
[]*gql_generated.LayerSummary{}, err
}
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, repoMetaList, imageMetaMap, localFilter,
pageInput, cveInfo,
skip)
if err != nil {
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{},
[]*gql_generated.LayerSummary{}, err
} }
paginatedRepos.Page = &gql_generated.PageInfo{ paginatedRepos.Page = &gql_generated.PageInfo{
@ -746,20 +673,20 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte
} }
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaRelevance), deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
), ),
} }
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.SearchTags(ctx, query) fullImageMetaList, err := metaDB.SearchTags(ctx, query)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
} }
imageSummaries, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList, skip, cveInfo,
indexDataMap, skip, cveInfo, localFilter, pageInput) localFilter, pageInput)
if err != nil { if err != nil {
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
} }
@ -790,10 +717,10 @@ func derivedImageList(ctx context.Context, image string, digest *string, metaDB
} }
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime), deref(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
), ),
} }
@ -820,13 +747,13 @@ func derivedImageList(ctx context.Context, image string, digest *string, metaDB
} }
// we need all available tags // we need all available tags
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, filterDerivedImages(searchedImage)) fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, filterDerivedImages(searchedImage))
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
derivedList, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap, derivedList, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList, skip, cveInfo,
skip, cveInfo, mTypes.Filter{}, pageInput) mTypes.Filter{}, pageInput)
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
@ -841,25 +768,20 @@ func derivedImageList(ctx context.Context, image string, digest *string, metaDB
} }
func filterDerivedImages(image *gql_generated.ImageSummary) mTypes.FilterFunc { func filterDerivedImages(image *gql_generated.ImageSummary) mTypes.FilterFunc {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
var addImageToList bool var addImageToList bool
var imageManifest ispec.Manifest imageManifest := imageMeta.Manifests[0]
err := json.Unmarshal(manifestMeta.ManifestBlob, &imageManifest)
if err != nil {
return false
}
for i := range image.Manifests { for i := range image.Manifests {
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String() manifestDigest := imageManifest.Digest.String()
if manifestDigest == *image.Manifests[i].Digest { if manifestDigest == *image.Manifests[i].Digest {
return false return false
} }
imageLayers := image.Manifests[i].Layers imageLayers := image.Manifests[i].Layers
addImageToList = false addImageToList = false
layers := imageManifest.Layers layers := imageManifest.Manifest.Layers
sameLayer := 0 sameLayer := 0
@ -895,10 +817,10 @@ func baseImageList(ctx context.Context, image string, digest *string, metaDB mTy
} }
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime), deref(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
), ),
} }
@ -926,12 +848,12 @@ func baseImageList(ctx context.Context, image string, digest *string, metaDB mTy
} }
// we need all available tags // we need all available tags
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, filterBaseImages(searchedImage)) fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, filterBaseImages(searchedImage))
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
baseList, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap, baseList, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList,
skip, cveInfo, mTypes.Filter{}, pageInput) skip, cveInfo, mTypes.Filter{}, pageInput)
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
@ -947,25 +869,20 @@ func baseImageList(ctx context.Context, image string, digest *string, metaDB mTy
} }
func filterBaseImages(image *gql_generated.ImageSummary) mTypes.FilterFunc { func filterBaseImages(image *gql_generated.ImageSummary) mTypes.FilterFunc {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
var addImageToList bool var addImageToList bool
var manifestContent ispec.Manifest manifest := imageMeta.Manifests[0]
err := json.Unmarshal(manifestMeta.ManifestBlob, &manifestContent)
if err != nil {
return false
}
for i := range image.Manifests { for i := range image.Manifests {
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String() manifestDigest := manifest.Digest.String()
if manifestDigest == *image.Manifests[i].Digest { if manifestDigest == *image.Manifests[i].Digest {
return false return false
} }
addImageToList = true addImageToList = true
for _, l := range manifestContent.Layers { for _, l := range manifest.Manifest.Layers {
foundLayer := false foundLayer := false
for _, k := range image.Manifests[i].Layers { for _, k := range image.Manifests[i].Layers {
@ -996,7 +913,7 @@ func validateGlobalSearchInput(query string, filter *gql_generated.Filter,
requestedPage *gql_generated.PageInput, requestedPage *gql_generated.PageInput,
) error { ) error {
if len(query) > querySizeLimit { if len(query) > querySizeLimit {
return fmt.Errorf("global-search: max string size limit exeeded for query parameter. max=%d current=%d %w", return fmt.Errorf("global-search: max string size limit exceeded for query parameter. max=%d current=%d %w",
querySizeLimit, len(query), zerr.ErrInvalidRequestParams) querySizeLimit, len(query), zerr.ErrInvalidRequestParams)
} }
@ -1020,14 +937,14 @@ func checkFilter(filter *gql_generated.Filter) error {
for _, arch := range filter.Arch { for _, arch := range filter.Arch {
if len(*arch) > querySizeLimit { if len(*arch) > querySizeLimit {
return fmt.Errorf("global-search: max string size limit exeeded for arch parameter. max=%d current=%d %w", return fmt.Errorf("global-search: max string size limit exceeded for arch parameter. max=%d current=%d %w",
querySizeLimit, len(*arch), zerr.ErrInvalidRequestParams) querySizeLimit, len(*arch), zerr.ErrInvalidRequestParams)
} }
} }
for _, osSys := range filter.Os { for _, osSys := range filter.Os {
if len(*osSys) > querySizeLimit { if len(*osSys) > querySizeLimit {
return fmt.Errorf("global-search: max string size limit exeeded for os parameter. max=%d current=%d %w", return fmt.Errorf("global-search: max string size limit exceeded for os parameter. max=%d current=%d %w",
querySizeLimit, len(*osSys), zerr.ErrInvalidRequestParams) querySizeLimit, len(*osSys), zerr.ErrInvalidRequestParams)
} }
} }
@ -1119,92 +1036,28 @@ func expandedRepoInfo(ctx context.Context, repo string, metaDB mTypes.MetaDB, cv
return &gql_generated.RepoInfo{}, nil //nolint:nilerr // don't give details to a potential attacker return &gql_generated.RepoInfo{}, nil //nolint:nilerr // don't give details to a potential attacker
} }
repoMeta, err := metaDB.GetUserRepoMeta(ctx, repo) repoMeta, err := metaDB.GetRepoMeta(ctx, repo)
if err != nil { if err != nil {
log.Error().Err(err).Str("repository", repo).Msg("resolver: can't retrieve repoMeta for repo") log.Error().Err(err).Str("repository", repo).Msg("resolver: can't retrieve repoMeta for repo")
return &gql_generated.RepoInfo{}, err return &gql_generated.RepoInfo{}, err
} }
var ( tagsDigests := []string{}
manifestMetaMap = map[string]mTypes.ManifestMetadata{}
indexDataMap = map[string]mTypes.IndexData{}
)
for tag, descriptor := range repoMeta.Tags { for i := range repoMeta.Tags {
switch descriptor.MediaType { if i == "" {
case ispec.MediaTypeImageManifest:
digest := descriptor.Digest
if _, alreadyDownloaded := manifestMetaMap[digest]; alreadyDownloaded {
continue continue
} }
manifestData, err := metaDB.GetManifestData(godigest.Digest(digest)) tagsDigests = append(tagsDigests, repoMeta.Tags[i].Digest)
}
imageMetaMap, err := metaDB.FilterImageMeta(ctx, tagsDigests)
if err != nil { if err != nil {
graphql.AddError(ctx, fmt.Errorf("resolver: failed to get manifest meta for image %s:%s with manifest digest %s %w", log.Error().Err(err).Str("repository", repo).Msg("resolver: can't retrieve imageMeta for repo")
repo, tag, digest, err))
continue return &gql_generated.RepoInfo{}, err
}
manifestMetaMap[digest] = mTypes.ManifestMetadata{
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob,
}
case ispec.MediaTypeImageIndex:
digest := descriptor.Digest
if _, alreadyDownloaded := indexDataMap[digest]; alreadyDownloaded {
continue
}
indexData, err := metaDB.GetIndexData(godigest.Digest(digest))
if err != nil {
graphql.AddError(ctx, fmt.Errorf("resolver: failed to get manifest meta for image %s:%s with manifest digest %s %w",
repo, tag, digest, err))
continue
}
var indexContent ispec.Index
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
graphql.AddError(ctx, fmt.Errorf("resolver: failed to unmarshal index content for image %s:%s with digest %s %w",
repo, tag, digest, err))
continue
}
var errorOccured bool
for _, descriptor := range indexContent.Manifests {
manifestData, err := metaDB.GetManifestData(descriptor.Digest)
if err != nil {
graphql.AddError(ctx,
fmt.Errorf("resolver: failed to get manifest meta with digest '%s' for multiarch image %s:%s %w",
digest, repo, tag, err),
)
errorOccured = true
break
}
manifestMetaMap[descriptor.Digest.String()] = mTypes.ManifestMetadata{
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob,
}
}
if errorOccured {
continue
}
indexDataMap[digest] = indexData
default:
}
} }
skip := convert.SkipQGLField{ skip := convert.SkipQGLField{
@ -1212,7 +1065,7 @@ func expandedRepoInfo(ctx context.Context, repo string, metaDB mTypes.MetaDB, cv
canSkipField(convert.GetPreloads(ctx), "Images.Vulnerabilities"), canSkipField(convert.GetPreloads(ctx), "Images.Vulnerabilities"),
} }
repoSummary, imageSummaries := convert.RepoMeta2ExpandedRepoInfo(ctx, repoMeta, manifestMetaMap, indexDataMap, repoSummary, imageSummaries := convert.RepoMeta2ExpandedRepoInfo(ctx, repoMeta, imageMetaMap,
skip, cveInfo, log) skip, cveInfo, log)
dateSortedImages := make(timeSlice, 0, len(imageSummaries)) dateSortedImages := make(timeSlice, 0, len(imageSummaries))
@ -1239,7 +1092,7 @@ func (p timeSlice) Swap(i, j int) {
p[i], p[j] = p[j], p[i] p[i], p[j] = p[j], p[i]
} }
func safeDereferencing[T any](pointer *T, defaultVal T) T { func deref[T any](pointer *T, defaultVal T) T {
if pointer != nil { if pointer != nil {
return *pointer return *pointer
} }
@ -1263,23 +1116,28 @@ func getImageList(ctx context.Context, repo string, metaDB mTypes.MetaDB, cveInf
} }
pageInput := pagination.PageInput{ pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0), Limit: deref(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0), Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria( SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaRelevance), deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
), ),
} }
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, var matchRepoName mTypes.FilterRepoTagFunc
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return repoMeta.Name == repo || repo == "" if repo == "" {
}) matchRepoName = mTypes.AcceptAllRepoTag
} else {
matchRepoName = func(repoName, tag string) bool { return repoName == repo }
}
imageMeta, err := metaDB.FilterTags(ctx, matchRepoName, mTypes.AcceptAllImageMeta)
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }
imageList, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, imageList, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, imageMeta, skip,
indexDataMap, skip, cveInfo, mTypes.Filter{}, pageInput) cveInfo, mTypes.Filter{}, pageInput)
if err != nil { if err != nil {
return &gql_generated.PaginatedImagesResult{}, err return &gql_generated.PaginatedImagesResult{}, err
} }

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,6 @@ import (
"net/url" "net/url"
"os" "os"
"path" "path"
"regexp"
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
@ -305,7 +304,7 @@ func getMockCveScanner(metaDB mTypes.MetaDB) cveinfo.Scanner {
imageDir := repo imageDir := repo
inputTag := reference inputTag := reference
repoMeta, err := metaDB.GetRepoMeta(imageDir) repoMeta, err := metaDB.GetRepoMeta(context.Background(), imageDir)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -328,19 +327,12 @@ func getMockCveScanner(metaDB mTypes.MetaDB) cveinfo.Scanner {
return false, err return false, err
} }
manifestData, err := metaDB.GetManifestData(manifestDigest) manifestData, err := metaDB.GetImageMeta(manifestDigest)
if err != nil { if err != nil {
return false, err return false, err
} }
var manifestContent ispec.Manifest for _, imageLayer := range manifestData.Manifests[0].Manifest.Layers {
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
return false, zerr.ErrScanNotSupported
}
for _, imageLayer := range manifestContent.Layers {
switch imageLayer.MediaType { switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer): case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
@ -1070,24 +1062,17 @@ func TestGetReferrersGQL(t *testing.T) {
defer ctlrManager.StopServer() defer ctlrManager.StopServer()
// Upload the index referrer // Upload the index referrer
targetImg := CreateRandomImage()
targetImg, err := deprecated.GetRandomImage() //nolint:staticcheck
So(err, ShouldBeNil)
targetDigest := targetImg.Digest() targetDigest := targetImg.Digest()
err = UploadImage(targetImg, baseURL, "repo", targetDigest.String()) err := UploadImage(targetImg, baseURL, "repo", targetImg.DigestStr())
So(err, ShouldBeNil)
indexReferrer, err := deprecated.GetRandomMultiarchImage("ref") //nolint:staticcheck
So(err, ShouldBeNil) So(err, ShouldBeNil)
artifactType := "com.artifact.art/type" artifactType := "com.artifact.art/type"
indexReferrer.Index.ArtifactType = artifactType indexReferrer := CreateMultiarchWith().RandomImages(2).
indexReferrer.Index.Subject = &ispec.Descriptor{ ArtifactType(artifactType).
MediaType: ispec.MediaTypeImageManifest, Subject(targetImg.DescriptorRef()).
Digest: targetDigest, Build()
}
indexReferrerDigest := indexReferrer.Digest() indexReferrerDigest := indexReferrer.Digest()
err = UploadMultiarchImage(indexReferrer, baseURL, "repo", "ref") err = UploadMultiarchImage(indexReferrer, baseURL, "repo", "ref")
@ -3203,7 +3188,9 @@ func TestGlobalSearch(t *testing.T) {
Vendors Vendors
NewestImage { NewestImage {
RepoName Tag LastUpdated Size RepoName Tag LastUpdated Size
Digest
Manifests{ Manifests{
Digest ConfigDigest
LastUpdated Size LastUpdated Size
Platform { Os Arch } Platform { Os Arch }
History { History {
@ -4495,67 +4482,24 @@ func TestMetaDBWhenPushingImages(t *testing.T) {
ctlrManager.StartAndWait(port) ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer() defer ctlrManager.StopServer()
Convey("SetManifestMeta fails", func() {
ctlr.MetaDB = mocks.MetaDBMock{
SetManifestDataFn: func(manifestDigest godigest.Digest, mm mTypes.ManifestData) error {
return ErrTestError
},
}
config1, layers1, manifest1, err := deprecated.GetImageComponents(100) //nolint:staticcheck
So(err, ShouldBeNil)
configBlob, err := json.Marshal(config1)
So(err, ShouldBeNil)
ctlr.StoreController.DefaultStore = mocks.MockedImageStore{
NewBlobUploadFn: ctlr.StoreController.DefaultStore.NewBlobUpload,
PutBlobChunkFn: ctlr.StoreController.DefaultStore.PutBlobChunk,
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
return configBlob, nil
},
DeleteImageManifestFn: func(repo, reference string, dc bool) error {
return ErrTestError
},
}
err = UploadImage(
Image{
Manifest: manifest1,
Config: config1,
Layers: layers1,
}, baseURL, "repo1", "1.0.1",
)
So(err, ShouldNotBeNil)
})
Convey("SetManifestMeta succeeds but SetRepoReference fails", func() { Convey("SetManifestMeta succeeds but SetRepoReference fails", func() {
ctlr.MetaDB = mocks.MetaDBMock{ ctlr.MetaDB = mocks.MetaDBMock{
SetRepoReferenceFn: func(repo, reference string, manifestDigest godigest.Digest, mediaType string) error { SetRepoReferenceFn: func(repo, reference string, imageMeta mTypes.ImageMeta) error {
return ErrTestError return ErrTestError
}, },
} }
config1, layers1, manifest1, err := deprecated.GetImageComponents(100) //nolint:staticcheck image := CreateRandomImage()
So(err, ShouldBeNil)
configBlob, err := json.Marshal(config1)
So(err, ShouldBeNil)
ctlr.StoreController.DefaultStore = mocks.MockedImageStore{ ctlr.StoreController.DefaultStore = mocks.MockedImageStore{
NewBlobUploadFn: ctlr.StoreController.DefaultStore.NewBlobUpload, NewBlobUploadFn: ctlr.StoreController.DefaultStore.NewBlobUpload,
PutBlobChunkFn: ctlr.StoreController.DefaultStore.PutBlobChunk, PutBlobChunkFn: ctlr.StoreController.DefaultStore.PutBlobChunk,
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) { GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
return configBlob, nil return image.ConfigDescriptor.Data, nil
}, },
} }
err = UploadImage( err := UploadImage(image, baseURL, "repo1", "1.0.1")
Image{
Manifest: manifest1,
Config: config1,
Layers: layers1,
}, baseURL, "repo1", "1.0.1",
)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
}) })
@ -4590,15 +4534,9 @@ func RunMetaDBIndexTests(baseURL, port string) {
Convey("Push test index", func() { Convey("Push test index", func() {
const repo = "repo" const repo = "repo"
multiarchImage, err := deprecated.GetRandomMultiarchImage("tag1") //nolint:staticcheck multiarchImage := CreateRandomMultiarch()
So(err, ShouldBeNil)
indexBlob, err := json.Marshal(multiarchImage.Index) err := UploadMultiarchImage(multiarchImage, baseURL, repo, "tag1")
So(err, ShouldBeNil)
indexDigest := godigest.FromBytes(indexBlob)
err = UploadMultiarchImage(multiarchImage, baseURL, repo, "tag1")
So(err, ShouldBeNil) So(err, ShouldBeNil)
query := ` query := `
@ -4634,7 +4572,7 @@ func RunMetaDBIndexTests(baseURL, port string) {
responseImage := responseImages[0] responseImage := responseImages[0]
So(len(responseImage.Manifests), ShouldEqual, 3) So(len(responseImage.Manifests), ShouldEqual, 3)
err = signature.SignImageUsingCosign(fmt.Sprintf("repo@%s", indexDigest), port) err = signature.SignImageUsingCosign(fmt.Sprintf("repo@%s", multiarchImage.DigestStr()), port)
So(err, ShouldBeNil) So(err, ShouldBeNil)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query)) resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
@ -4654,7 +4592,7 @@ func RunMetaDBIndexTests(baseURL, port string) {
So(responseImage.IsSigned, ShouldBeTrue) So(responseImage.IsSigned, ShouldBeTrue)
// remove signature // remove signature
cosignTag := "sha256-" + indexDigest.Encoded() + ".sig" cosignTag := "sha256-" + multiarchImage.Digest().Encoded() + ".sig"
_, err = resty.R().Delete(baseURL + "/v2/" + "repo" + "/manifests/" + cosignTag) _, err = resty.R().Delete(baseURL + "/v2/" + "repo" + "/manifests/" + cosignTag)
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -5409,9 +5347,7 @@ func TestMetaDBWhenDeletingImages(t *testing.T) {
for _, manifest := range indexContent.Manifests { for _, manifest := range indexContent.Manifests {
tag := manifest.Annotations[ispec.AnnotationRefName] tag := manifest.Annotations[ispec.AnnotationRefName]
cosignTagRule := regexp.MustCompile(`sha256\-.+\.sig`) if zcommon.IsCosignTag(tag) {
if cosignTagRule.MatchString(tag) {
signatureTag = tag signatureTag = tag
} }
} }
@ -5685,7 +5621,10 @@ func TestMetaDBWhenDeletingImages(t *testing.T) {
} }
ctlr.MetaDB = mocks.MetaDBMock{ ctlr.MetaDB = mocks.MetaDBMock{
RemoveRepoReferenceFn: func(repo, reference string, manifestDigest godigest.Digest) error { return ErrTestError }, RemoveRepoReferenceFn: func(repo, reference string, manifestDigest godigest.Digest,
) error {
return ErrTestError
},
} }
resp, err = resty.R().Delete(baseURL + "/v2/" + "repo1" + "/manifests/" + resp, err = resty.R().Delete(baseURL + "/v2/" + "repo1" + "/manifests/" +
@ -6438,16 +6377,6 @@ func TestUploadingArtifactsWithDifferentMediaType(t *testing.T) {
err = UploadImage(defaultImage, baseURL, "repo", "default-image") err = UploadImage(defaultImage, baseURL, "repo", "default-image")
So(err, ShouldBeNil) So(err, ShouldBeNil)
manifestData, err := ctlr.MetaDB.GetManifestData(imageWithIncompatibleConfig.ManifestDescriptor.Digest)
So(err, ShouldBeNil)
So(manifestData.ConfigBlob, ShouldEqual, imageWithIncompatibleConfig.ConfigDescriptor.Data)
So(manifestData.ManifestBlob, ShouldEqual, imageWithIncompatibleConfig.ManifestDescriptor.Data)
manifestData, err = ctlr.MetaDB.GetManifestData(defaultImage.ManifestDescriptor.Digest)
So(err, ShouldBeNil)
So(manifestData.ConfigBlob, ShouldEqual, defaultImage.ConfigDescriptor.Data)
So(manifestData.ManifestBlob, ShouldEqual, defaultImage.ManifestDescriptor.Data)
query := ` query := `
{ {
GlobalSearch(query:"repo:incompatible-image"){ GlobalSearch(query:"repo:incompatible-image"){

View File

@ -18,13 +18,11 @@ import (
"zotregistry.io/zot/pkg/api/constants" "zotregistry.io/zot/pkg/api/constants"
"zotregistry.io/zot/pkg/common" "zotregistry.io/zot/pkg/common"
extconf "zotregistry.io/zot/pkg/extensions/config" extconf "zotregistry.io/zot/pkg/extensions/config"
"zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/local"
test "zotregistry.io/zot/pkg/test/common" test "zotregistry.io/zot/pkg/test/common"
"zotregistry.io/zot/pkg/test/deprecated" "zotregistry.io/zot/pkg/test/deprecated"
. "zotregistry.io/zot/pkg/test/image-utils" . "zotregistry.io/zot/pkg/test/image-utils"
. "zotregistry.io/zot/pkg/test/oci-utils"
) )
//nolint:dupl //nolint:dupl
@ -535,25 +533,15 @@ func TestChangingRepoState(t *testing.T) {
ctlr := api.NewController(conf) ctlr := api.NewController(conf)
img, err := deprecated.GetRandomImage() //nolint:staticcheck img := CreateRandomImage()
storeCtlr := GetDefaultStoreController(conf.Storage.RootDirectory, log.NewLogger("debug", ""))
err := WriteImageToFileSystem(img, accesibleRepo, "tag", storeCtlr)
if err != nil { if err != nil {
t.FailNow() t.FailNow()
} }
// ------ Create the test repos err = WriteImageToFileSystem(img, forbiddenRepo, "tag", storeCtlr)
defaultStore := local.NewImageStore(conf.Storage.RootDirectory, false, false,
log.NewLogger("debug", ""), monitoring.NewMetricsServer(false, log.NewLogger("debug", "")), nil, nil)
err = WriteImageToFileSystem(img, accesibleRepo, "tag", storage.StoreController{
DefaultStore: defaultStore,
})
if err != nil {
t.FailNow()
}
err = WriteImageToFileSystem(img, forbiddenRepo, "tag", storage.StoreController{
DefaultStore: defaultStore,
})
if err != nil { if err != nil {
t.FailNow() t.FailNow()
} }

View File

@ -153,21 +153,9 @@ func (ref CosignReference) SyncReferences(ctx context.Context, localRepo, remote
ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr). ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr).
Msg("metaDB: trying to sync cosign reference for image") Msg("metaDB: trying to sync cosign reference for image")
isSig, sigType, signedManifestDig, err := storage.CheckIsImageSignature(localRepo, manifestBuf,
cosignTag)
if err != nil {
return refsDigests, fmt.Errorf("failed to check if cosign reference '%s@%s' is a signature: %w", localRepo,
cosignTag, err)
}
if isSig {
err = addSigToMeta(ref.metaDB, localRepo, sigType, cosignTag, signedManifestDig, referenceDigest,
manifestBuf, imageStore, ref.log)
} else {
err = meta.SetImageMetaFromInput(localRepo, cosignTag, ispec.MediaTypeImageManifest, err = meta.SetImageMetaFromInput(localRepo, cosignTag, ispec.MediaTypeImageManifest,
referenceDigest, manifestBuf, ref.storeController.GetImageStore(localRepo), referenceDigest, manifestBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log) ref.metaDB, ref.log)
}
if err != nil { if err != nil {
return refsDigests, fmt.Errorf("failed to set metadata for cosign reference in '%s@%s': %w", return refsDigests, fmt.Errorf("failed to set metadata for cosign reference in '%s@%s': %w",

View File

@ -137,22 +137,9 @@ func (ref OciReferences) SyncReferences(ctx context.Context, localRepo, remoteRe
ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr). ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr).
Msg("metaDB: trying to add oci references for image") Msg("metaDB: trying to add oci references for image")
isSig, sigType, signedManifestDig, err := storage.CheckIsImageSignature(localRepo, referenceBuf,
referrer.Digest.String())
if err != nil {
return refsDigests, fmt.Errorf("failed to check if oci reference '%s@%s' is a signature: %w", localRepo,
referrer.Digest.String(), err)
}
if isSig {
err = addSigToMeta(ref.metaDB, localRepo, sigType, referrer.Digest.String(), signedManifestDig, referenceDigest,
referenceBuf, imageStore, ref.log)
} else {
err = meta.SetImageMetaFromInput(localRepo, referenceDigest.String(), referrer.MediaType, err = meta.SetImageMetaFromInput(localRepo, referenceDigest.String(), referrer.MediaType,
referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo), referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log) ref.metaDB, ref.log)
}
if err != nil { if err != nil {
return refsDigests, fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w", return refsDigests, fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w",
localRepo, subjectDigestStr, err) localRepo, subjectDigestStr, err)

View File

@ -113,22 +113,9 @@ func (ref TagReferences) SyncReferences(ctx context.Context, localRepo, remoteRe
ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr). ref.log.Debug().Str("repository", localRepo).Str("subject", subjectDigestStr).
Msg("metaDB: trying to add oci references for image") Msg("metaDB: trying to add oci references for image")
isSig, sigType, signedManifestDig, err := storage.CheckIsImageSignature(localRepo, referenceBuf,
referrer.Digest.String())
if err != nil {
return refsDigests, fmt.Errorf("failed to check if oci reference '%s@%s' is a signature: %w", localRepo,
referrer.Digest.String(), err)
}
if isSig {
err = addSigToMeta(ref.metaDB, localRepo, sigType, referrer.Digest.String(), signedManifestDig, referenceDigest,
referenceBuf, imageStore, ref.log)
} else {
err = meta.SetImageMetaFromInput(localRepo, referenceDigest.String(), referrer.MediaType, err = meta.SetImageMetaFromInput(localRepo, referenceDigest.String(), referrer.MediaType,
referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo), referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log) ref.metaDB, ref.log)
}
if err != nil { if err != nil {
return refsDigests, fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w", return refsDigests, fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w",
localRepo, subjectDigestStr, err) localRepo, subjectDigestStr, err)

View File

@ -27,6 +27,7 @@ import (
"zotregistry.io/zot/pkg/extensions/monitoring" "zotregistry.io/zot/pkg/extensions/monitoring"
client "zotregistry.io/zot/pkg/extensions/sync/httpclient" client "zotregistry.io/zot/pkg/extensions/sync/httpclient"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/cache" "zotregistry.io/zot/pkg/storage/cache"
storageConstants "zotregistry.io/zot/pkg/storage/constants" storageConstants "zotregistry.io/zot/pkg/storage/constants"
@ -336,8 +337,8 @@ func TestLocalRegistry(t *testing.T) {
Convey("trigger metaDB error on index manifest in CommitImage()", func() { Convey("trigger metaDB error on index manifest in CommitImage()", func() {
registry := NewLocalRegistry(storage.StoreController{DefaultStore: syncImgStore}, mocks.MetaDBMock{ registry := NewLocalRegistry(storage.StoreController{DefaultStore: syncImgStore}, mocks.MetaDBMock{
SetRepoReferenceFn: func(repo, Reference string, manifestDigest godigest.Digest, mediaType string) error { SetRepoReferenceFn: func(repo string, reference string, imageMeta mTypes.ImageMeta) error {
if Reference == "1.0" { if reference == "1.0" {
return zerr.ErrRepoMetaNotFound return zerr.ErrRepoMetaNotFound
} }
@ -351,7 +352,7 @@ func TestLocalRegistry(t *testing.T) {
Convey("trigger metaDB error on image manifest in CommitImage()", func() { Convey("trigger metaDB error on image manifest in CommitImage()", func() {
registry := NewLocalRegistry(storage.StoreController{DefaultStore: syncImgStore}, mocks.MetaDBMock{ registry := NewLocalRegistry(storage.StoreController{DefaultStore: syncImgStore}, mocks.MetaDBMock{
SetRepoReferenceFn: func(repo, Reference string, manifestDigest godigest.Digest, mediaType string) error { SetRepoReferenceFn: func(repo, reference string, imageMeta mTypes.ImageMeta) error {
return zerr.ErrRepoMetaNotFound return zerr.ErrRepoMetaNotFound
}, },
}, log) }, log)

View File

@ -877,9 +877,7 @@ func TestOnDemand(t *testing.T) {
return nil return nil
}, },
SetRepoReferenceFn: func(repo, reference string, manifestDigest godigest.Digest, SetRepoReferenceFn: func(repo, reference string, imageMeta mTypes.ImageMeta) error {
mediaType string,
) error {
if strings.HasPrefix(reference, "sha256-") && if strings.HasPrefix(reference, "sha256-") &&
(strings.HasSuffix(reference, remote.SignatureTagSuffix) || (strings.HasSuffix(reference, remote.SignatureTagSuffix) ||
strings.HasSuffix(reference, remote.SBOMTagSuffix)) || strings.HasSuffix(reference, remote.SBOMTagSuffix)) ||
@ -1019,8 +1017,8 @@ func TestOnDemand(t *testing.T) {
// metadb fails for syncReferrersTag" // metadb fails for syncReferrersTag"
dctlr.MetaDB = mocks.MetaDBMock{ dctlr.MetaDB = mocks.MetaDBMock{
SetManifestDataFn: func(manifestDigest godigest.Digest, mm mTypes.ManifestData) error { SetRepoReferenceFn: func(repo, reference string, imageMeta mTypes.ImageMeta) error {
if manifestDigest.String() == ociRefImage.ManifestDescriptor.Digest.String() { if imageMeta.Digest.String() == ociRefImage.ManifestDescriptor.Digest.String() {
return sync.ErrTestError return sync.ErrTestError
} }
@ -4670,7 +4668,7 @@ func TestSyncedSignaturesMetaDB(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusOK) So(resp.StatusCode(), ShouldEqual, http.StatusOK)
repoMeta, err := dctlr.MetaDB.GetRepoMeta(repoName) repoMeta, err := dctlr.MetaDB.GetRepoMeta(context.Background(), repoName)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(repoMeta.Tags, ShouldContainKey, tag) So(repoMeta.Tags, ShouldContainKey, tag)
So(len(repoMeta.Tags), ShouldEqual, 1) So(len(repoMeta.Tags), ShouldEqual, 1)

File diff suppressed because it is too large Load Diff

View File

@ -4,29 +4,25 @@ import (
"context" "context"
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
"encoding/json"
"math" "math"
"testing" "testing"
"time" "time"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
zerr "zotregistry.io/zot/errors" zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/boltdb" "zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
reqCtx "zotregistry.io/zot/pkg/requestcontext" reqCtx "zotregistry.io/zot/pkg/requestcontext"
. "zotregistry.io/zot/pkg/test/image-utils"
) )
type imgTrustStore struct{} type imgTrustStore struct{}
func (its imgTrustStore) VerifySignature( func (its imgTrustStore) VerifySignature(
signatureType string, rawSignature []byte, sigKey string, manifestDigest digest.Digest, manifestContent []byte, signatureType string, rawSignature []byte, sigKey string, manifestDigest digest.Digest, imageMeta mTypes.ImageMeta,
repo string, repo string,
) (string, time.Time, bool, error) { ) (string, time.Time, bool, error) {
return "", time.Time{}, false, nil return "", time.Time{}, false, nil
@ -47,14 +43,6 @@ func TestWrapperErrors(t *testing.T) {
boltdbWrapper.SetImageTrustStore(imgTrustStore{}) boltdbWrapper.SetImageTrustStore(imgTrustStore{})
repoMeta := mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{},
Signatures: map[string]mTypes.ManifestSignatures{},
}
repoMetaBlob, err := json.Marshal(repoMeta)
So(err, ShouldBeNil)
userAc := reqCtx.NewUserAccessControl() userAc := reqCtx.NewUserAccessControl()
userAc.SetUsername("test") userAc.SetUsername("test")
@ -245,604 +233,6 @@ func TestWrapperErrors(t *testing.T) {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
Convey("GetManifestData", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
dataBuck := tx.Bucket([]byte(boltdb.ManifestDataBucket))
return dataBuck.Put([]byte("digest1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
_, err = boltdbWrapper.GetManifestData("digest1")
So(err, ShouldNotBeNil)
_, err = boltdbWrapper.GetManifestMeta("repo1", "digest1")
So(err, ShouldNotBeNil)
})
Convey("SetManifestMeta", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
dataBuck := tx.Bucket([]byte(boltdb.ManifestDataBucket))
err := dataBuck.Put([]byte("digest1"), repoMetaBlob)
if err != nil {
return err
}
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.SetManifestMeta("repo1", "digest1", mTypes.ManifestMetadata{})
So(err, ShouldNotBeNil)
_, err = boltdbWrapper.GetManifestMeta("repo1", "digest1")
So(err, ShouldNotBeNil)
})
Convey("FilterRepos", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
buck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
err := buck.Put([]byte("badRepo"), []byte("bad repo"))
So(err, ShouldBeNil)
return nil
})
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.FilterRepos(context.Background(),
func(repoMeta mTypes.RepoMetadata) bool { return true })
So(err, ShouldNotBeNil)
})
Convey("SetReferrer", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.SetReferrer("repo", "ref", mTypes.ReferrerInfo{})
So(err, ShouldNotBeNil)
})
Convey("DeleteReferrer", func() {
Convey("RepoMeta not found", func() {
err := boltdbWrapper.DeleteReferrer("r", "dig", "dig")
So(err, ShouldNotBeNil)
})
Convey("bad repo meta blob", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.DeleteReferrer("repo", "dig", "dig")
So(err, ShouldNotBeNil)
})
})
Convey("SetRepoReference", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.SetRepoReference("repo1", "tag", "digest", ispec.MediaTypeImageManifest)
So(err, ShouldNotBeNil)
})
Convey("GetRepoMeta", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
_, err = boltdbWrapper.GetRepoMeta("repo1")
So(err, ShouldNotBeNil)
})
Convey("DeleteRepoTag", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.DeleteRepoTag("repo1", "tag")
So(err, ShouldNotBeNil)
})
Convey("GetReferrersInfo", func() {
_, err = boltdbWrapper.GetReferrersInfo("repo1", "tag", nil)
So(err, ShouldNotBeNil)
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
_, err = boltdbWrapper.GetReferrersInfo("repo1", "tag", nil)
So(err, ShouldNotBeNil)
})
Convey("IncrementRepoStars", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.IncrementRepoStars("repo2")
So(err, ShouldNotBeNil)
err = boltdbWrapper.IncrementRepoStars("repo1")
So(err, ShouldNotBeNil)
})
Convey("DecrementRepoStars", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.DecrementRepoStars("repo2")
So(err, ShouldNotBeNil)
err = boltdbWrapper.DecrementRepoStars("repo1")
So(err, ShouldNotBeNil)
})
Convey("GetRepoStars", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
_, err = boltdbWrapper.GetRepoStars("repo1")
So(err, ShouldNotBeNil)
})
Convey("GetMultipleRepoMeta", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
_, err = boltdbWrapper.GetMultipleRepoMeta(context.TODO(), func(repoMeta mTypes.RepoMetadata) bool {
return true
})
So(err, ShouldNotBeNil)
})
Convey("IncrementImageDownloads", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.IncrementImageDownloads("repo2", "tag")
So(err, ShouldNotBeNil)
err = boltdbWrapper.IncrementImageDownloads("repo1", "tag")
So(err, ShouldNotBeNil)
err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), repoMetaBlob)
})
So(err, ShouldBeNil)
err = boltdbWrapper.IncrementImageDownloads("repo1", "tag")
So(err, ShouldNotBeNil)
})
Convey("AddManifestSignature", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.AddManifestSignature("repo1", digest.FromString("dig"),
mTypes.SignatureMetadata{})
So(err, ShouldNotBeNil)
err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), repoMetaBlob)
})
So(err, ShouldBeNil)
// signatures not found
err = boltdbWrapper.AddManifestSignature("repo1", digest.FromString("dig"),
mTypes.SignatureMetadata{})
So(err, ShouldBeNil)
//
err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
repoMeta := mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{},
Signatures: map[string]mTypes.ManifestSignatures{
"digest1": {
"cosgin": {{}},
},
"digest2": {
"notation": {{}},
},
},
}
repoMetaBlob, err := json.Marshal(repoMeta)
So(err, ShouldBeNil)
return repoBuck.Put([]byte("repo1"), repoMetaBlob)
})
So(err, ShouldBeNil)
err = boltdbWrapper.AddManifestSignature("repo1", digest.FromString("dig"),
mTypes.SignatureMetadata{
SignatureType: "cosign",
SignatureDigest: "digest1",
})
So(err, ShouldBeNil)
err = boltdbWrapper.AddManifestSignature("repo1", digest.FromString("dig"),
mTypes.SignatureMetadata{
SignatureType: "cosign",
SignatureDigest: "digest2",
})
So(err, ShouldBeNil)
repoData, err := boltdbWrapper.GetRepoMeta("repo1")
So(err, ShouldBeNil)
So(len(repoData.Signatures[string(digest.FromString("dig"))][zcommon.CosignSignature]),
ShouldEqual, 1)
So(repoData.Signatures[string(digest.FromString("dig"))][zcommon.CosignSignature][0].SignatureManifestDigest,
ShouldEqual, "digest2")
err = boltdbWrapper.AddManifestSignature("repo1", digest.FromString("dig"),
mTypes.SignatureMetadata{
SignatureType: "notation",
SignatureDigest: "digest2",
})
So(err, ShouldBeNil)
})
Convey("DeleteSignature", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.DeleteSignature("repo2", digest.FromString("dig"),
mTypes.SignatureMetadata{})
So(err, ShouldNotBeNil)
err = boltdbWrapper.DeleteSignature("repo1", digest.FromString("dig"),
mTypes.SignatureMetadata{})
So(err, ShouldNotBeNil)
err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
repoMeta := mTypes.RepoMetadata{
Tags: map[string]mTypes.Descriptor{},
Signatures: map[string]mTypes.ManifestSignatures{
"digest1": {
"cosgin": []mTypes.SignatureInfo{
{
SignatureManifestDigest: "sigDigest1",
},
{
SignatureManifestDigest: "sigDigest2",
},
},
},
"digest2": {
"notation": {{}},
},
},
}
repoMetaBlob, err := json.Marshal(repoMeta)
So(err, ShouldBeNil)
return repoBuck.Put([]byte("repo1"), repoMetaBlob)
})
So(err, ShouldBeNil)
err = boltdbWrapper.DeleteSignature("repo1", "digest1",
mTypes.SignatureMetadata{
SignatureType: "cosgin",
SignatureDigest: "sigDigest2",
})
So(err, ShouldBeNil)
})
Convey("SearchRepos", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.SearchRepos(context.Background(), "")
So(err, ShouldNotBeNil)
err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
dataBuck := tx.Bucket([]byte(boltdb.ManifestDataBucket))
err := dataBuck.Put([]byte("dig1"), []byte("wrong json"))
if err != nil {
return err
}
repoMeta := mTypes.RepoMetadata{
Name: "repo1",
Tags: map[string]mTypes.Descriptor{
"tag1": {Digest: "dig1", MediaType: ispec.MediaTypeImageManifest},
},
Signatures: map[string]mTypes.ManifestSignatures{},
}
repoMetaBlob, err := json.Marshal(repoMeta)
So(err, ShouldBeNil)
err = repoBuck.Put([]byte("repo1"), repoMetaBlob)
if err != nil {
return err
}
repoMeta = mTypes.RepoMetadata{
Name: "repo2",
Tags: map[string]mTypes.Descriptor{
"tag2": {Digest: "dig2", MediaType: ispec.MediaTypeImageManifest},
},
Signatures: map[string]mTypes.ManifestSignatures{},
}
repoMetaBlob, err = json.Marshal(repoMeta)
So(err, ShouldBeNil)
return repoBuck.Put([]byte("repo2"), repoMetaBlob)
})
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.SearchRepos(context.Background(), "repo1")
So(err, ShouldNotBeNil)
_, _, _, err = boltdbWrapper.SearchRepos(context.Background(), "repo2")
So(err, ShouldNotBeNil)
})
Convey("Index Errors", func() {
Convey("Bad index data", func() {
indexDigest := digest.FromString("indexDigest")
err := boltdbWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = setBadIndexData(boltdbWrapper.DB, indexDigest.String())
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.SearchRepos(ctx, "")
So(err, ShouldNotBeNil)
_, _, _, err = boltdbWrapper.SearchTags(ctx, "repo:")
So(err, ShouldNotBeNil)
})
Convey("Bad indexBlob in IndexData", func() {
indexDigest := digest.FromString("indexDigest")
err := boltdbWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = boltdbWrapper.SetIndexData(indexDigest, mTypes.IndexData{
IndexBlob: []byte("bad json"),
})
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.SearchRepos(ctx, "")
So(err, ShouldNotBeNil)
_, _, _, err = boltdbWrapper.SearchTags(ctx, "repo:")
So(err, ShouldNotBeNil)
})
})
Convey("SearchTags", func() {
ctx := context.Background()
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.SearchTags(ctx, "")
So(err, ShouldNotBeNil)
_, _, _, err = boltdbWrapper.SearchTags(ctx, "repo1:")
So(err, ShouldNotBeNil)
err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
dataBuck := tx.Bucket([]byte(boltdb.ManifestDataBucket))
manifestMeta := mTypes.ManifestMetadata{
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("wrong json"),
Signatures: mTypes.ManifestSignatures{},
}
manifestMetaBlob, err := json.Marshal(manifestMeta)
if err != nil {
return err
}
err = dataBuck.Put([]byte("dig1"), manifestMetaBlob)
if err != nil {
return err
}
err = dataBuck.Put([]byte("wrongManifestData"), []byte("wrong json"))
if err != nil {
return err
}
// manifest data doesn't exist
repoMeta = mTypes.RepoMetadata{
Name: "repo1",
Tags: map[string]mTypes.Descriptor{
"tag2": {Digest: "dig2", MediaType: ispec.MediaTypeImageManifest},
},
Signatures: map[string]mTypes.ManifestSignatures{},
}
repoMetaBlob, err = json.Marshal(repoMeta)
So(err, ShouldBeNil)
err = repoBuck.Put([]byte("repo1"), repoMetaBlob)
if err != nil {
return err
}
// manifest data is wrong
repoMeta = mTypes.RepoMetadata{
Name: "repo2",
Tags: map[string]mTypes.Descriptor{
"tag2": {Digest: "wrongManifestData", MediaType: ispec.MediaTypeImageManifest},
},
Signatures: map[string]mTypes.ManifestSignatures{},
}
repoMetaBlob, err = json.Marshal(repoMeta)
So(err, ShouldBeNil)
err = repoBuck.Put([]byte("repo2"), repoMetaBlob)
if err != nil {
return err
}
repoMeta = mTypes.RepoMetadata{
Name: "repo3",
Tags: map[string]mTypes.Descriptor{
"tag1": {Digest: "dig1", MediaType: ispec.MediaTypeImageManifest},
},
Signatures: map[string]mTypes.ManifestSignatures{},
}
repoMetaBlob, err = json.Marshal(repoMeta)
So(err, ShouldBeNil)
return repoBuck.Put([]byte("repo3"), repoMetaBlob)
})
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.SearchTags(ctx, "repo1:")
So(err, ShouldNotBeNil)
_, _, _, err = boltdbWrapper.SearchTags(ctx, "repo2:")
So(err, ShouldNotBeNil)
})
Convey("FilterTags Index errors", func() {
Convey("FilterTags bad IndexData", func() {
indexDigest := digest.FromString("indexDigest")
err := boltdbWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = setBadIndexData(boltdbWrapper.DB, indexDigest.String())
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return true })
So(err, ShouldNotBeNil)
})
Convey("FilterTags bad indexBlob in IndexData", func() {
indexDigest := digest.FromString("indexDigest")
err := boltdbWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = boltdbWrapper.SetIndexData(indexDigest, mTypes.IndexData{
IndexBlob: []byte("bad json"),
})
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return true })
So(err, ShouldNotBeNil)
})
Convey("FilterTags didn't match any index manifest", func() {
var (
indexDigest = digest.FromString("indexDigest")
manifestDigestFromIndex1 = digest.FromString("manifestDigestFromIndex1")
manifestDigestFromIndex2 = digest.FromString("manifestDigestFromIndex2")
)
err := boltdbWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
indexBlob, err := GetIndexBlobWithManifests([]digest.Digest{
manifestDigestFromIndex1, manifestDigestFromIndex2,
})
So(err, ShouldBeNil)
err = boltdbWrapper.SetIndexData(indexDigest, mTypes.IndexData{
IndexBlob: indexBlob,
})
So(err, ShouldBeNil)
err = boltdbWrapper.SetManifestData(manifestDigestFromIndex1, mTypes.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
err = boltdbWrapper.SetManifestData(manifestDigestFromIndex2, mTypes.ManifestData{
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return false })
So(err, ShouldBeNil)
})
})
Convey("ToggleStarRepo bad context errors", func() { Convey("ToggleStarRepo bad context errors", func() {
uacKey := reqCtx.GetContextKey() uacKey := reqCtx.GetContextKey()
ctx := context.WithValue(context.Background(), uacKey, "bad context") ctx := context.WithValue(context.Background(), uacKey, "bad context")
@ -860,7 +250,7 @@ func TestWrapperErrors(t *testing.T) {
ctx := userAc.DeriveContext(context.Background()) ctx := userAc.DeriveContext(context.Background())
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error { err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket)) repoBuck := tx.Bucket([]byte(boltdb.RepoMetaBuck))
err := repoBuck.Put([]byte("repo"), []byte("bad repo")) err := repoBuck.Put([]byte("repo"), []byte("bad repo"))
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -976,23 +366,6 @@ func TestWrapperErrors(t *testing.T) {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
Convey("Unsuported type", func() {
digest := digest.FromString("digest")
err := boltdbWrapper.SetRepoReference("repo", "tag1", digest, "invalid type") //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.SearchRepos(ctx, "")
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.SearchTags(ctx, "repo:")
So(err, ShouldBeNil)
_, _, _, err = boltdbWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return true })
So(err, ShouldBeNil)
})
Convey("GetUserRepoMeta unmarshal error", func() { Convey("GetUserRepoMeta unmarshal error", func() {
userAc := reqCtx.NewUserAccessControl() userAc := reqCtx.NewUserAccessControl()
userAc.SetUsername("username") userAc.SetUsername("username")
@ -1002,7 +375,7 @@ func TestWrapperErrors(t *testing.T) {
ctx := userAc.DeriveContext(context.Background()) ctx := userAc.DeriveContext(context.Background())
err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error { err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket)) repoBuck := tx.Bucket([]byte(boltdb.RepoMetaBuck))
err := repoBuck.Put([]byte("repo"), []byte("bad repo")) err := repoBuck.Put([]byte("repo"), []byte("bad repo"))
So(err, ShouldBeNil) So(err, ShouldBeNil)
@ -1011,78 +384,8 @@ func TestWrapperErrors(t *testing.T) {
}) })
So(err, ShouldBeNil) So(err, ShouldBeNil)
_, err := boltdbWrapper.GetUserRepoMeta(ctx, "repo") _, err := boltdbWrapper.GetRepoMeta(ctx, "repo")
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
Convey("UpdateSignaturesValidity", func() {
Convey("manifestMeta of signed manifest not found", func() {
err := boltdbWrapper.UpdateSignaturesValidity("repo", digest.FromString("dig"))
So(err, ShouldBeNil)
})
Convey("repoMeta of signed manifest not found", func() {
// repo Meta not found
err := boltdbWrapper.SetManifestData(digest.FromString("dig"), mTypes.ManifestData{
ManifestBlob: []byte("Bad Manifest"),
ConfigBlob: []byte("Bad Manifest"),
})
So(err, ShouldBeNil)
err = boltdbWrapper.UpdateSignaturesValidity("repo", digest.FromString("dig"))
So(err, ShouldNotBeNil)
})
Convey("manifest - bad content", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
dataBuck := tx.Bucket([]byte(boltdb.ManifestDataBucket))
return dataBuck.Put([]byte("digest1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.UpdateSignaturesValidity("repo1", "digest1")
So(err, ShouldNotBeNil)
})
Convey("index - bad content", func() {
err := boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
dataBuck := tx.Bucket([]byte(boltdb.IndexDataBucket))
return dataBuck.Put([]byte("digest1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.UpdateSignaturesValidity("repo1", "digest1")
So(err, ShouldNotBeNil)
})
Convey("repo - bad content", func() {
// repo Meta not found
err := boltdbWrapper.SetManifestData(digest.FromString("dig"), mTypes.ManifestData{
ManifestBlob: []byte("Bad Manifest"),
ConfigBlob: []byte("Bad Manifest"),
})
So(err, ShouldBeNil)
err = boltdbWrapper.DB.Update(func(tx *bbolt.Tx) error {
repoBuck := tx.Bucket([]byte(boltdb.RepoMetadataBucket))
return repoBuck.Put([]byte("repo1"), []byte("wrong json"))
})
So(err, ShouldBeNil)
err = boltdbWrapper.UpdateSignaturesValidity("repo1", digest.FromString("dig"))
So(err, ShouldNotBeNil)
})
})
})
}
func setBadIndexData(dB *bbolt.DB, digest string) error {
return dB.Update(func(tx *bbolt.Tx) error {
indexDataBuck := tx.Bucket([]byte(boltdb.IndexDataBucket))
return indexDataBuck.Put([]byte(digest), []byte("bad json"))
}) })
} }

View File

@ -2,9 +2,9 @@ package boltdb
// MetadataDB. // MetadataDB.
const ( const (
ManifestDataBucket = "ManifestData" ImageMetaBuck = "ImageMeta"
IndexDataBucket = "IndexData" RepoMetaBuck = "RepoMeta"
RepoMetadataBucket = "RepoMetadata" RepoBlobsBuck = "RepoBlobsMeta"
UserDataBucket = "UserData" UserDataBucket = "UserData"
VersionBucket = "Version" VersionBucket = "Version"
UserAPIKeysBucket = "UserAPIKeys" UserAPIKeysBucket = "UserAPIKeys"

View File

@ -1,8 +1,6 @@
package common package common
import ( import (
"encoding/json"
"fmt"
"strings" "strings"
"time" "time"
@ -10,28 +8,23 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
zerr "zotregistry.io/zot/errors" zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common"
mConvert "zotregistry.io/zot/pkg/meta/convert"
proto_go "zotregistry.io/zot/pkg/meta/proto/gen"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
) )
func UpdateManifestMeta(repoMeta mTypes.RepoMetadata, manifestDigest godigest.Digest, func SignatureAlreadyExists(signatureSlice []mTypes.SignatureInfo, sm mTypes.SignatureMetadata) bool {
manifestMeta mTypes.ManifestMetadata, for _, sigInfo := range signatureSlice {
) mTypes.RepoMetadata { if sm.SignatureDigest == sigInfo.SignatureManifestDigest {
updatedRepoMeta := repoMeta return true
}
updatedStatistics := repoMeta.Statistics[manifestDigest.String()]
updatedStatistics.DownloadCount = manifestMeta.DownloadCount
updatedRepoMeta.Statistics[manifestDigest.String()] = updatedStatistics
if manifestMeta.Signatures == nil {
manifestMeta.Signatures = mTypes.ManifestSignatures{}
} }
updatedRepoMeta.Signatures[manifestDigest.String()] = manifestMeta.Signatures return false
return updatedRepoMeta
} }
func SignatureAlreadyExists(signatureSlice []mTypes.SignatureInfo, sm mTypes.SignatureMetadata) bool { func ProtoSignatureAlreadyExists(signatureSlice []*proto_go.SignatureInfo, sm mTypes.SignatureMetadata) bool {
for _, sigInfo := range signatureSlice { for _, sigInfo := range signatureSlice {
if sm.SignatureDigest == sigInfo.SignatureManifestDigest { if sm.SignatureDigest == sigInfo.SignatureManifestDigest {
return true return true
@ -74,7 +67,7 @@ const (
) )
// RankRepoName associates a rank to a given repoName given a searchText. // RankRepoName associates a rank to a given repoName given a searchText.
// The imporance of the value grows inversly proportional to the int value it has. // The importance of the value grows inversely proportional to the int value it has.
// For example: rank(1) > rank(10) > rank(100)... // For example: rank(1) > rank(10) > rank(100)...
func RankRepoName(searchText string, repoName string) int { func RankRepoName(searchText string, repoName string) int {
searchText = strings.Trim(searchText, "/") searchText = strings.Trim(searchText, "/")
@ -89,7 +82,7 @@ func RankRepoName(searchText string, repoName string) int {
return perfectMatchPriority return perfectMatchPriority
} }
// searchText containst just 1 diretory name // searchText contains just 1 directory name
if len(searchTextSlice) == 1 { if len(searchTextSlice) == 1 {
lastNameInRepoPath := repoNameSlice[len(repoNameSlice)-1] lastNameInRepoPath := repoNameSlice[len(repoNameSlice)-1]
@ -157,21 +150,6 @@ func GetRepoTag(searchText string) (string, string, error) {
return repo, tag, nil return repo, tag, nil
} }
func GetReferredSubject(descriptorBlob []byte) (godigest.Digest, bool) {
var manifest ispec.Manifest
err := json.Unmarshal(descriptorBlob, &manifest)
if err != nil {
return "", false
}
if manifest.Subject == nil || manifest.Subject.Digest.String() == "" {
return "", false
}
return manifest.Subject.Digest, true
}
func MatchesArtifactTypes(descriptorMediaType string, artifactTypes []string) bool { func MatchesArtifactTypes(descriptorMediaType string, artifactTypes []string) bool {
if len(artifactTypes) == 0 { if len(artifactTypes) == 0 {
return true return true
@ -208,139 +186,199 @@ func CheckImageLastUpdated(repoLastUpdated time.Time, isSigned bool, noImageChec
return repoLastUpdated, noImageChecked, isSigned return repoLastUpdated, noImageChecked, isSigned
} }
func FilterDataByRepo(foundRepos []mTypes.RepoMetadata, manifestMetadataMap map[string]mTypes.ManifestMetadata, func AddImageMetaToRepoMeta(repoMeta *proto_go.RepoMeta, repoBlobs *proto_go.RepoBlobs, reference string,
indexDataMap map[string]mTypes.IndexData, imageMeta mTypes.ImageMeta,
) (map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error) { ) (*proto_go.RepoMeta, *proto_go.RepoBlobs, error) {
var ( switch imageMeta.MediaType {
foundManifestMetadataMap = make(map[string]mTypes.ManifestMetadata)
foundindexDataMap = make(map[string]mTypes.IndexData)
)
// keep just the manifestMeta we need
for _, repoMeta := range foundRepos {
for _, descriptor := range repoMeta.Tags {
switch descriptor.MediaType {
case ispec.MediaTypeImageManifest: case ispec.MediaTypeImageManifest:
foundManifestMetadataMap[descriptor.Digest] = manifestMetadataMap[descriptor.Digest] manifestData := imageMeta.Manifests[0]
vendor := GetVendor(manifestData.Manifest.Annotations)
if vendor == "" {
vendor = GetVendor(manifestData.Manifest.Annotations)
}
vendors := []string{}
if vendor != "" {
vendors = append(vendors, vendor)
}
platforms := []*proto_go.Platform{getProtoPlatform(&manifestData.Config.Platform)}
if platforms[0].OS == "" && platforms[0].Architecture == "" {
platforms = []*proto_go.Platform{}
}
subBlobs := []string{manifestData.Manifest.Config.Digest.String()}
repoBlobs.Blobs[manifestData.Manifest.Config.Digest.String()] = &proto_go.BlobInfo{
Size: manifestData.Manifest.Config.Size,
}
for _, layer := range manifestData.Manifest.Layers {
subBlobs = append(subBlobs, layer.Digest.String())
repoBlobs.Blobs[layer.Digest.String()] = &proto_go.BlobInfo{Size: layer.Size}
}
lastUpdated := zcommon.GetImageLastUpdated(manifestData.Config)
repoBlobs.Blobs[imageMeta.Digest.String()] = &proto_go.BlobInfo{
Size: imageMeta.Size,
Vendors: vendors,
Platforms: platforms,
SubBlobs: subBlobs,
LastUpdated: mConvert.GetProtoTime(&lastUpdated),
}
case ispec.MediaTypeImageIndex: case ispec.MediaTypeImageIndex:
indexData := indexDataMap[descriptor.Digest] subBlobs := []string{}
for _, manifest := range imageMeta.Index.Manifests {
var indexContent ispec.Index subBlobs = append(subBlobs, manifest.Digest.String())
err := json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
return map[string]mTypes.ManifestMetadata{}, map[string]mTypes.IndexData{},
fmt.Errorf("metadb: error while getting manifest data for digest %s %w", descriptor.Digest, err)
} }
for _, manifestDescriptor := range indexContent.Manifests { repoBlobs.Blobs[imageMeta.Digest.String()] = &proto_go.BlobInfo{
manifestDigest := manifestDescriptor.Digest.String() Size: imageMeta.Size,
SubBlobs: subBlobs,
foundManifestMetadataMap[manifestDigest] = manifestMetadataMap[manifestDigest] }
} }
foundindexDataMap[descriptor.Digest] = indexData // update info only when a tag is added
default: if zcommon.IsDigest(reference) {
return repoMeta, repoBlobs, nil
}
size, platforms, vendors := recalculateAggregateFields(repoMeta, repoBlobs)
repoMeta.Vendors = vendors
repoMeta.Platforms = platforms
repoMeta.Size = int32(size)
imageBlobInfo := repoBlobs.Blobs[imageMeta.Digest.String()]
repoMeta.LastUpdatedImage = mConvert.GetProtoEarlierUpdatedImage(repoMeta.LastUpdatedImage,
&proto_go.RepoLastUpdatedImage{
LastUpdated: imageBlobInfo.LastUpdated,
MediaType: imageMeta.MediaType,
Digest: imageMeta.Digest.String(),
Tag: reference,
})
return repoMeta, repoBlobs, nil
}
func RemoveImageFromRepoMeta(repoMeta *proto_go.RepoMeta, repoBlobs *proto_go.RepoBlobs, ref string,
) (*proto_go.RepoMeta, *proto_go.RepoBlobs, error) {
var updatedLastImage *proto_go.RepoLastUpdatedImage
updatedBlobs := map[string]*proto_go.BlobInfo{}
updatedSize := int64(0)
updatedVendors := []string{}
updatedPlatforms := []*proto_go.Platform{}
for tag, descriptor := range repoMeta.Tags {
if descriptor.Digest == "" {
continue continue
} }
queue := []string{descriptor.Digest}
mConvert.GetProtoEarlierUpdatedImage(updatedLastImage, &proto_go.RepoLastUpdatedImage{
LastUpdated: repoBlobs.Blobs[descriptor.Digest].LastUpdated,
MediaType: descriptor.MediaType,
Digest: descriptor.Digest,
Tag: tag,
})
for len(queue) > 0 {
currentBlob := queue[0]
queue = queue[1:]
if _, found := updatedBlobs[currentBlob]; !found {
blobInfo := repoBlobs.Blobs[currentBlob]
updatedBlobs[currentBlob] = blobInfo
updatedSize += blobInfo.Size
updatedVendors = mConvert.AddVendors(updatedVendors, blobInfo.Vendors)
updatedPlatforms = mConvert.AddProtoPlatforms(updatedPlatforms, blobInfo.Platforms)
queue = append(queue, blobInfo.SubBlobs...)
}
} }
} }
return foundManifestMetadataMap, foundindexDataMap, nil repoMeta.Size = int32(updatedSize)
repoMeta.Vendors = updatedVendors
repoMeta.Platforms = updatedPlatforms
repoMeta.LastUpdatedImage = updatedLastImage
repoBlobs.Blobs = updatedBlobs
return repoMeta, repoBlobs, nil
} }
func FetchDataForRepos(metaDB mTypes.MetaDB, foundRepos []mTypes.RepoMetadata, func recalculateAggregateFields(repoMeta *proto_go.RepoMeta, repoBlobs *proto_go.RepoBlobs,
) (map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error) { ) (int64, []*proto_go.Platform, []string) {
foundManifestMetadataMap := map[string]mTypes.ManifestMetadata{} size := int64(0)
foundIndexDataMap := map[string]mTypes.IndexData{} platforms := []*proto_go.Platform{}
vendors := []string{}
blobsMap := map[string]struct{}{}
for idx := range foundRepos { for _, descriptor := range repoMeta.Tags {
for _, descriptor := range foundRepos[idx].Tags { if descriptor.Digest == "" {
switch descriptor.MediaType { continue
case ispec.MediaTypeImageManifest:
manifestData, err := metaDB.GetManifestData(godigest.Digest(descriptor.Digest))
if err != nil {
return map[string]mTypes.ManifestMetadata{}, map[string]mTypes.IndexData{}, err
} }
foundManifestMetadataMap[descriptor.Digest] = mTypes.ManifestMetadata{ queue := []string{descriptor.Digest}
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob, for len(queue) > 0 {
} currentBlob := queue[0]
case ispec.MediaTypeImageIndex: queue = queue[1:]
indexData, err := metaDB.GetIndexData(godigest.Digest(descriptor.Digest))
if err != nil { if _, found := blobsMap[currentBlob]; !found {
return map[string]mTypes.ManifestMetadata{}, map[string]mTypes.IndexData{}, err blobInfo := repoBlobs.Blobs[currentBlob]
if blobInfo == nil {
continue
} }
var indexContent ispec.Index blobsMap[currentBlob] = struct{}{}
size += blobInfo.Size
vendors = mConvert.AddVendors(vendors, blobInfo.Vendors)
platforms = mConvert.AddProtoPlatforms(platforms, blobInfo.Platforms)
err = json.Unmarshal(indexData.IndexBlob, &indexContent) queue = append(queue, blobInfo.SubBlobs...)
if err != nil {
return map[string]mTypes.ManifestMetadata{},
map[string]mTypes.IndexData{},
fmt.Errorf("metadb: error while getting index data for digest %s %w", descriptor.Digest, err)
}
for _, manifestDescriptor := range indexContent.Manifests {
manifestDigest := manifestDescriptor.Digest.String()
manifestData, err := metaDB.GetManifestData(manifestDescriptor.Digest)
if err != nil {
return map[string]mTypes.ManifestMetadata{}, map[string]mTypes.IndexData{}, err
}
foundManifestMetadataMap[manifestDigest] = mTypes.ManifestMetadata{
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob,
}
}
foundIndexDataMap[descriptor.Digest] = indexData
} }
} }
} }
return foundManifestMetadataMap, foundIndexDataMap, nil return size, platforms, vendors
} }
// FindMediaTypeForDigest will look into the buckets for a certain digest. Depending on which bucket that func getProtoPlatform(platform *ispec.Platform) *proto_go.Platform {
// digest is found the corresponding mediatype is returned. if platform == nil {
func FindMediaTypeForDigest(metaDB mTypes.MetaDB, digest godigest.Digest) (bool, string) { return nil
_, err := metaDB.GetManifestData(digest)
if err == nil {
return true, ispec.MediaTypeImageManifest
} }
_, err = metaDB.GetIndexData(digest) return &proto_go.Platform{
if err == nil { Architecture: getArch(platform.Architecture, platform.Variant),
return true, ispec.MediaTypeImageIndex OS: platform.OS,
} }
return false, ""
} }
func GetImageDescriptor(metaDB mTypes.MetaDB, repo, tag string) (mTypes.Descriptor, error) { func getArch(arch string, variant string) string {
repoMeta, err := metaDB.GetRepoMeta(repo) if variant != "" {
if err != nil { arch = arch + "/" + variant
return mTypes.Descriptor{}, err
} }
imageDescriptor, ok := repoMeta.Tags[tag] return arch
}
func GetVendor(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationVendor, "org.label-schema.vendor")
}
func GetAnnotationValue(annotations map[string]string, annotationKey, labelKey string) string {
value, ok := annotations[annotationKey]
if !ok || value == "" {
value, ok = annotations[labelKey]
if !ok { if !ok {
return mTypes.Descriptor{}, zerr.ErrTagMetaNotFound value = ""
}
} }
return imageDescriptor, nil return value
}
func InitializeImageConfig(blob []byte) ispec.Image {
var configContent ispec.Image
err := json.Unmarshal(blob, &configContent)
if err != nil {
return ispec.Image{}
}
return configContent
} }

View File

@ -5,23 +5,15 @@ import (
"testing" "testing"
"time" "time"
"github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/meta/common" "zotregistry.io/zot/pkg/meta/common"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/test/mocks"
) )
var ErrTestError = errors.New("test error") var ErrTestError = errors.New("test error")
func TestUtils(t *testing.T) { func TestUtils(t *testing.T) {
Convey("GetReferredSubject", t, func() {
_, err := common.GetReferredSubject([]byte("bad json"))
So(err, ShouldNotBeNil)
})
Convey("MatchesArtifactTypes", t, func() { Convey("MatchesArtifactTypes", t, func() {
res := common.MatchesArtifactTypes("", nil) res := common.MatchesArtifactTypes("", nil)
So(res, ShouldBeTrue) So(res, ShouldBeTrue)
@ -116,145 +108,4 @@ func TestUtils(t *testing.T) {
So(res, ShouldEqual, false) So(res, ShouldEqual, false)
}) })
Convey("FilterDataByRepo", t, func() {
Convey("Functionality", func() {
_, _, err := common.FilterDataByRepo(
[]mTypes.RepoMetadata{{
Tags: map[string]mTypes.Descriptor{
"manifest": {
Digest: "manifestDigest",
MediaType: ispec.MediaTypeImageManifest,
},
"index": {
Digest: "indexDigest",
MediaType: ispec.MediaTypeImageIndex,
},
"rand": {
Digest: "randDigest",
MediaType: "rand",
},
},
}},
map[string]mTypes.ManifestMetadata{},
map[string]mTypes.IndexData{
"indexDigest": {
IndexBlob: []byte(`{
"manifests": [
{
"digest": "manifestDigest"
}
]
}`),
},
},
)
So(err, ShouldBeNil)
})
Convey("Errors", func() {
// Unmarshal index data error
_, _, err := common.FilterDataByRepo(
[]mTypes.RepoMetadata{{
Tags: map[string]mTypes.Descriptor{
"tag": {
Digest: "indexDigest",
MediaType: ispec.MediaTypeImageIndex,
},
},
}},
map[string]mTypes.ManifestMetadata{},
map[string]mTypes.IndexData{
"indexDigest": {
IndexBlob: []byte("bad blob"),
},
},
)
So(err, ShouldNotBeNil)
})
})
Convey("FetchDataForRepos", t, func() {
Convey("Errors", func() {
// Unmarshal index data error
_, _, err := common.FetchDataForRepos(
mocks.MetaDBMock{
GetIndexDataFn: func(indexDigest digest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{
IndexBlob: []byte("bad blob"),
}, nil
},
},
[]mTypes.RepoMetadata{{
Tags: map[string]mTypes.Descriptor{
"tag": {
Digest: "indexDigest",
MediaType: ispec.MediaTypeImageIndex,
},
},
}},
)
So(err, ShouldNotBeNil)
})
})
}
func TestFetchDataForRepos(t *testing.T) {
Convey("GetReferredSubject", t, func() {
mockMetaDB := mocks.MetaDBMock{}
Convey("GetManifestData errors", func() {
mockMetaDB.GetManifestDataFn = func(manifestDigest digest.Digest) (mTypes.ManifestData, error) {
return mTypes.ManifestData{}, ErrTestError
}
_, _, err := common.FetchDataForRepos(mockMetaDB, []mTypes.RepoMetadata{
{
Tags: map[string]mTypes.Descriptor{
"tag1": {Digest: "dig1", MediaType: ispec.MediaTypeImageManifest},
},
},
})
So(err, ShouldNotBeNil)
})
Convey("GetIndexData errors", func() {
mockMetaDB.GetIndexDataFn = func(indexDigest digest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{}, ErrTestError
}
_, _, err := common.FetchDataForRepos(mockMetaDB, []mTypes.RepoMetadata{
{
Tags: map[string]mTypes.Descriptor{
"tag1": {Digest: "dig1", MediaType: ispec.MediaTypeImageIndex},
},
},
})
So(err, ShouldNotBeNil)
})
Convey("GetIndexData ok, GetManifestData errors", func() {
mockMetaDB.GetIndexDataFn = func(indexDigest digest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{
IndexBlob: []byte(`{
"manifests": [
{"digest": "dig1"}
]
}`),
}, nil
}
mockMetaDB.GetManifestDataFn = func(manifestDigest digest.Digest) (mTypes.ManifestData, error) {
return mTypes.ManifestData{}, ErrTestError
}
_, _, err := common.FetchDataForRepos(mockMetaDB, []mTypes.RepoMetadata{
{
Tags: map[string]mTypes.Descriptor{
"tag1": {Digest: "dig1", MediaType: ispec.MediaTypeImageIndex},
},
},
})
So(err, ShouldNotBeNil)
})
})
} }

611
pkg/meta/convert/convert.go Normal file
View File

@ -0,0 +1,611 @@
package convert
import (
"time"
godigest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"google.golang.org/protobuf/types/known/timestamppb"
"zotregistry.io/zot/pkg/common"
proto_go "zotregistry.io/zot/pkg/meta/proto/gen"
mTypes "zotregistry.io/zot/pkg/meta/types"
)
func GetHistory(history []*proto_go.History) []ispec.History {
if history == nil {
return nil
}
results := make([]ispec.History, 0, len(history))
for _, his := range history {
results = append(results, ispec.History{
Created: ref(his.Created.AsTime()),
CreatedBy: deref(his.CreatedBy, ""),
Author: deref(his.Author, ""),
Comment: deref(his.Comment, ""),
EmptyLayer: deref(his.EmptyLayer, false),
})
}
return results
}
func GetImageArtifactType(imageMeta *proto_go.ImageMeta) string {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
manifestArtifactType := deref(imageMeta.Manifests[0].Manifest.ArtifactType, "")
if manifestArtifactType != "" {
return manifestArtifactType
}
return imageMeta.Manifests[0].Manifest.Config.MediaType
case ispec.MediaTypeImageIndex:
return deref(imageMeta.Index.Index.ArtifactType, "")
default:
return ""
}
}
func GetImageManifestSize(imageMeta *proto_go.ImageMeta) int64 {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
return imageMeta.Manifests[0].Size
case ispec.MediaTypeImageIndex:
return imageMeta.Index.Size
default:
return 0
}
}
func GetImageDigest(imageMeta *proto_go.ImageMeta) godigest.Digest {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
return godigest.Digest(imageMeta.Manifests[0].Digest)
case ispec.MediaTypeImageIndex:
return godigest.Digest(imageMeta.Index.Digest)
default:
return ""
}
}
func GetImageDigestStr(imageMeta *proto_go.ImageMeta) string {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
return imageMeta.Manifests[0].Digest
case ispec.MediaTypeImageIndex:
return imageMeta.Index.Digest
default:
return ""
}
}
func GetImageAnnotations(imageMeta *proto_go.ImageMeta) map[string]string {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
return imageMeta.Manifests[0].Manifest.Annotations
case ispec.MediaTypeImageIndex:
return imageMeta.Index.Index.Annotations
default:
return map[string]string{}
}
}
func GetImageSubject(imageMeta *proto_go.ImageMeta) *ispec.Descriptor {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
if imageMeta.Manifests[0].Manifest.Subject == nil {
return nil
}
return GetDescriptorRef(imageMeta.Manifests[0].Manifest.Subject)
case ispec.MediaTypeImageIndex:
if imageMeta.Index.Index.Subject == nil {
return nil
}
return GetDescriptorRef(imageMeta.Index.Index.Subject)
default:
return nil
}
}
func GetDescriptorRef(descriptor *proto_go.Descriptor) *ispec.Descriptor {
if descriptor == nil {
return nil
}
platform := GetPlatformRef(descriptor.Platform)
return &ispec.Descriptor{
MediaType: descriptor.MediaType,
Digest: godigest.Digest(descriptor.Digest),
Size: descriptor.Size,
URLs: descriptor.URLs,
Data: descriptor.Data,
Platform: platform,
ArtifactType: deref(descriptor.ArtifactType, ""),
Annotations: descriptor.Annotations,
}
}
func GetPlatform(platform *proto_go.Platform) ispec.Platform {
if platform == nil {
return ispec.Platform{}
}
return ispec.Platform{
Architecture: platform.Architecture,
OS: platform.OS,
OSVersion: deref(platform.OSVersion, ""),
OSFeatures: platform.OSFeatures,
Variant: deref(platform.Variant, ""),
}
}
func GetPlatformRef(platform *proto_go.Platform) *ispec.Platform {
if platform == nil {
return nil
}
return &ispec.Platform{
Architecture: platform.Architecture,
OS: platform.OS,
OSVersion: deref(platform.OSVersion, ""),
OSFeatures: platform.OSFeatures,
Variant: deref(platform.Variant, ""),
}
}
func GetLayers(descriptors []*proto_go.Descriptor) []ispec.Descriptor {
results := make([]ispec.Descriptor, 0, len(descriptors))
for _, desc := range descriptors {
results = append(results, ispec.Descriptor{
MediaType: desc.MediaType,
Digest: godigest.Digest(desc.Digest),
Size: desc.Size,
})
}
return results
}
func GetSubject(subj *proto_go.Descriptor) *ispec.Descriptor {
if subj == nil {
return nil
}
return &ispec.Descriptor{
MediaType: subj.MediaType,
Digest: godigest.Digest(subj.Digest),
Size: subj.Size,
}
}
func GetReferrers(refs map[string]*proto_go.ReferrersInfo) map[string][]mTypes.ReferrerInfo {
results := map[string][]mTypes.ReferrerInfo{}
for digest, ref := range refs {
referrers := []mTypes.ReferrerInfo{}
for _, dbRef := range ref.List {
referrers = append(referrers, mTypes.ReferrerInfo{
Digest: dbRef.Digest,
MediaType: dbRef.MediaType,
ArtifactType: dbRef.ArtifactType,
Size: int(dbRef.Size),
Annotations: dbRef.Annotations,
})
}
results[digest] = referrers
}
return results
}
func GetImageReferrers(refs *proto_go.ReferrersInfo) []mTypes.ReferrerInfo {
if refs == nil {
return []mTypes.ReferrerInfo{}
}
results := []mTypes.ReferrerInfo{}
for _, dbRef := range refs.List {
results = append(results, mTypes.ReferrerInfo{
Digest: dbRef.Digest,
MediaType: dbRef.MediaType,
ArtifactType: dbRef.ArtifactType,
Size: int(dbRef.Size),
Annotations: dbRef.Annotations,
})
}
return results
}
func GetSignatures(sigs map[string]*proto_go.ManifestSignatures) map[string]mTypes.ManifestSignatures {
results := map[string]mTypes.ManifestSignatures{}
for digest, dbSignatures := range sigs {
imageSignatures := mTypes.ManifestSignatures{}
for signatureName, signatureInfo := range dbSignatures.Map {
imageSignatures[signatureName] = GetSignaturesInfo(signatureInfo.List)
}
results[digest] = imageSignatures
}
return results
}
func GetImageSignatures(sigs *proto_go.ManifestSignatures) mTypes.ManifestSignatures {
if sigs == nil {
return mTypes.ManifestSignatures{}
}
results := mTypes.ManifestSignatures{}
for signatureName, signatureInfo := range sigs.Map {
results[signatureName] = GetSignaturesInfo(signatureInfo.List)
}
return results
}
func GetSignaturesInfo(sigsInfo []*proto_go.SignatureInfo) []mTypes.SignatureInfo {
results := []mTypes.SignatureInfo{}
for _, siginfo := range sigsInfo {
results = append(results, mTypes.SignatureInfo{
SignatureManifestDigest: siginfo.SignatureManifestDigest,
LayersInfo: GetLayersInfo(siginfo.LayersInfo),
})
}
return results
}
func GetLayersInfo(layersInfo []*proto_go.LayersInfo) []mTypes.LayerInfo {
results := []mTypes.LayerInfo{}
for _, layerInfo := range layersInfo {
date := time.Time{}
if layerInfo.Date != nil {
date = layerInfo.Date.AsTime()
}
results = append(results, mTypes.LayerInfo{
LayerDigest: layerInfo.LayerDigest,
LayerContent: layerInfo.LayerContent,
SignatureKey: layerInfo.SignatureKey,
Signer: layerInfo.Signer,
Date: date,
})
}
return results
}
func GetStatisticsMap(stats map[string]*proto_go.DescriptorStatistics) map[string]mTypes.DescriptorStatistics {
results := map[string]mTypes.DescriptorStatistics{}
for digest, stat := range stats {
results[digest] = mTypes.DescriptorStatistics{
DownloadCount: int(stat.DownloadCount),
}
}
return results
}
func GetImageStatistics(stats *proto_go.DescriptorStatistics) mTypes.DescriptorStatistics {
if stats == nil {
return mTypes.DescriptorStatistics{}
}
return mTypes.DescriptorStatistics{
DownloadCount: int(stats.DownloadCount),
}
}
func GetImageManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64,
digest godigest.Digest,
) mTypes.ImageMeta {
return mTypes.ImageMeta{
MediaType: ispec.MediaTypeImageManifest,
Digest: digest,
Size: size,
Manifests: []mTypes.ManifestData{
{
Digest: digest,
Size: size,
Config: configContent,
Manifest: manifestContent,
},
},
}
}
func GetImageIndexMeta(indexContent ispec.Index, size int64, digest godigest.Digest) mTypes.ImageMeta {
return mTypes.ImageMeta{
MediaType: ispec.MediaTypeImageIndex,
Index: &indexContent,
Manifests: GetManifests(indexContent.Manifests),
Size: size,
Digest: digest,
}
}
func GetTags(tags map[string]*proto_go.TagDescriptor) map[string]mTypes.Descriptor {
resultMap := map[string]mTypes.Descriptor{}
for tag, tagDescriptor := range tags {
resultMap[tag] = mTypes.Descriptor{
Digest: tagDescriptor.Digest,
MediaType: tagDescriptor.MediaType,
}
}
return resultMap
}
func GetManifests(descriptors []ispec.Descriptor) []mTypes.ManifestData {
manifestList := []mTypes.ManifestData{}
for _, manifest := range descriptors {
manifestList = append(manifestList, mTypes.ManifestData{
Digest: manifest.Digest,
Size: manifest.Size,
})
}
return manifestList
}
func GetTime(time *timestamppb.Timestamp) *time.Time {
if time == nil {
return nil
}
return ref(time.AsTime())
}
func GetFullImageMetaFromProto(tag string, protoRepoMeta *proto_go.RepoMeta, protoImageMeta *proto_go.ImageMeta,
) mTypes.FullImageMeta {
imageMeta := GetImageMeta(protoImageMeta)
imageDigest := imageMeta.Digest.String()
return mTypes.FullImageMeta{
Repo: protoRepoMeta.Name,
Tag: tag,
MediaType: imageMeta.MediaType,
Digest: imageMeta.Digest,
Size: imageMeta.Size,
Index: imageMeta.Index,
Manifests: GetFullManifestData(protoRepoMeta, imageMeta.Manifests),
IsStarred: protoRepoMeta.IsStarred,
IsBookmarked: protoRepoMeta.IsBookmarked,
Referrers: GetImageReferrers(protoRepoMeta.Referrers[imageDigest]),
Statistics: GetImageStatistics(protoRepoMeta.Statistics[imageDigest]),
Signatures: GetImageSignatures(protoRepoMeta.Signatures[imageDigest]),
}
}
func GetFullManifestData(protoRepoMeta *proto_go.RepoMeta, manifestData []mTypes.ManifestData,
) []mTypes.FullManifestMeta {
results := []mTypes.FullManifestMeta{}
for i := range manifestData {
results = append(results, mTypes.FullManifestMeta{
ManifestData: manifestData[i],
Referrers: GetImageReferrers(protoRepoMeta.Referrers[manifestData[i].Digest.String()]),
Statistics: GetImageStatistics(protoRepoMeta.Statistics[manifestData[i].Digest.String()]),
Signatures: GetImageSignatures(protoRepoMeta.Signatures[manifestData[i].Digest.String()]),
})
}
return results
}
func GetRepoMeta(protoRepoMeta *proto_go.RepoMeta) mTypes.RepoMeta {
repoDownloads := int32(0)
for _, descriptor := range protoRepoMeta.Tags {
if statistic := protoRepoMeta.Statistics[descriptor.Digest]; statistic != nil {
repoDownloads += statistic.DownloadCount
}
}
return mTypes.RepoMeta{
Name: protoRepoMeta.Name,
Tags: GetTags(protoRepoMeta.Tags),
Rank: int(protoRepoMeta.Rank),
Size: int64(protoRepoMeta.Size),
Platforms: GetPlatforms(protoRepoMeta.Platforms),
Vendors: protoRepoMeta.Vendors,
IsStarred: protoRepoMeta.IsStarred,
IsBookmarked: protoRepoMeta.IsBookmarked,
StarCount: int(protoRepoMeta.Stars),
DownloadCount: int(repoDownloads),
LastUpdatedImage: GetLastUpdatedImage(protoRepoMeta.LastUpdatedImage),
Statistics: GetStatisticsMap(protoRepoMeta.Statistics),
Signatures: GetSignatures(protoRepoMeta.Signatures),
Referrers: GetReferrers(protoRepoMeta.Referrers),
}
}
func GetPlatforms(platforms []*proto_go.Platform) []ispec.Platform {
result := []ispec.Platform{}
for i := range platforms {
result = append(result, GetPlatform(platforms[i]))
}
return result
}
func AddProtoPlatforms(platforms []*proto_go.Platform, newPlatforms []*proto_go.Platform) []*proto_go.Platform {
for _, newPlatform := range newPlatforms {
if !ContainsProtoPlatform(platforms, newPlatform) {
platforms = append(platforms, newPlatform)
}
}
return platforms
}
func ContainsProtoPlatform(platforms []*proto_go.Platform, platform *proto_go.Platform) bool {
for i := range platforms {
if platforms[i].OS == platform.OS && platforms[i].Architecture == platform.Architecture {
return true
}
}
return false
}
func AddVendors(vendors []string, newVendors []string) []string {
for _, newVendor := range newVendors {
if !common.Contains(vendors, newVendor) {
vendors = append(vendors, newVendor)
}
}
return vendors
}
func GetLastUpdatedImage(protoLastUpdated *proto_go.RepoLastUpdatedImage) *mTypes.LastUpdatedImage {
if protoLastUpdated == nil {
return nil
}
return &mTypes.LastUpdatedImage{
Descriptor: mTypes.Descriptor{
Digest: protoLastUpdated.Digest,
MediaType: protoLastUpdated.MediaType,
},
Tag: protoLastUpdated.Tag,
LastUpdated: GetTime(protoLastUpdated.LastUpdated),
}
}
func GetImageMeta(dbImageMeta *proto_go.ImageMeta) mTypes.ImageMeta {
imageMeta := mTypes.ImageMeta{
MediaType: dbImageMeta.MediaType,
Size: GetImageManifestSize(dbImageMeta),
Digest: GetImageDigest(dbImageMeta),
}
if dbImageMeta.MediaType == ispec.MediaTypeImageIndex {
manifests := make([]ispec.Descriptor, 0, len(dbImageMeta.Manifests))
for _, manifest := range dbImageMeta.Manifests {
manifests = append(manifests, ispec.Descriptor{
MediaType: deref(manifest.Manifest.MediaType, ""),
Digest: godigest.Digest(manifest.Digest),
Size: manifest.Size,
})
}
imageMeta.Index = &ispec.Index{
Versioned: specs.Versioned{SchemaVersion: int(dbImageMeta.Index.Index.Versioned.GetSchemaVersion())},
MediaType: ispec.MediaTypeImageIndex,
Manifests: manifests,
Subject: GetImageSubject(dbImageMeta),
ArtifactType: GetImageArtifactType(dbImageMeta),
Annotations: GetImageAnnotations(dbImageMeta),
}
}
manifestDataList := make([]mTypes.ManifestData, 0, len(dbImageMeta.Manifests))
for _, manifest := range dbImageMeta.Manifests {
manifestDataList = append(manifestDataList, mTypes.ManifestData{
Size: manifest.Size,
Digest: godigest.Digest(manifest.Digest),
Manifest: ispec.Manifest{
Versioned: specs.Versioned{SchemaVersion: int(manifest.Manifest.Versioned.GetSchemaVersion())},
MediaType: deref(manifest.Manifest.MediaType, ""),
ArtifactType: deref(manifest.Manifest.ArtifactType, ""),
Config: ispec.Descriptor{
MediaType: manifest.Manifest.Config.MediaType,
Size: manifest.Manifest.Config.Size,
Digest: godigest.Digest(manifest.Manifest.Config.Digest),
},
Layers: GetLayers(manifest.Manifest.Layers),
Subject: GetSubject(manifest.Manifest.Subject),
Annotations: manifest.Manifest.Annotations,
},
Config: ispec.Image{
Created: GetTime(manifest.Config.Created),
Author: deref(manifest.Config.Author, ""),
Platform: GetPlatform(manifest.Config.Platform),
Config: ispec.ImageConfig{
User: manifest.Config.Config.User,
ExposedPorts: GetExposedPorts(manifest.Config.Config.ExposedPorts),
Env: manifest.Config.Config.Env,
Entrypoint: manifest.Config.Config.Entrypoint,
Cmd: manifest.Config.Config.Cmd,
Volumes: GetConfigVolumes(manifest.Config.Config.Volumes),
WorkingDir: deref(manifest.Config.Config.WorkingDir, ""),
Labels: manifest.Config.Config.Labels,
StopSignal: deref(manifest.Config.Config.StopSignal, ""),
},
RootFS: ispec.RootFS{
Type: manifest.Config.RootFS.Type,
DiffIDs: GetDiffIDs(manifest.Config.RootFS.DiffIDs),
},
History: GetHistory(manifest.Config.History),
},
})
}
imageMeta.Manifests = manifestDataList
return imageMeta
}
func GetExposedPorts(exposedPorts map[string]*proto_go.EmptyMessage) map[string]struct{} {
if exposedPorts == nil {
return nil
}
result := map[string]struct{}{}
for key := range exposedPorts {
result[key] = struct{}{}
}
return result
}
func GetConfigVolumes(configVolumes map[string]*proto_go.EmptyMessage) map[string]struct{} {
if configVolumes == nil {
return nil
}
result := map[string]struct{}{}
for key := range configVolumes {
result[key] = struct{}{}
}
return result
}
func GetDiffIDs(diffIDs []string) []godigest.Digest {
result := make([]godigest.Digest, 0, len(diffIDs))
for i := range diffIDs {
result = append(result, godigest.Digest(diffIDs[i]))
}
return result
}

View File

@ -0,0 +1,392 @@
package convert
import (
"time"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"google.golang.org/protobuf/types/known/timestamppb"
"zotregistry.io/zot/pkg/common"
proto_go "zotregistry.io/zot/pkg/meta/proto/gen"
mTypes "zotregistry.io/zot/pkg/meta/types"
)
func GetProtoRepoMeta(repo mTypes.RepoMeta) *proto_go.RepoMeta {
return &proto_go.RepoMeta{
Name: repo.Name,
Tags: GetProtoTags(repo.Tags),
Statistics: GetProtoStatistics(repo.Statistics),
Signatures: GetProtoSignatures(repo.Signatures),
Referrers: GetProtoReferrers(repo.Referrers),
Size: int32(repo.Size),
Vendors: repo.Vendors,
Platforms: GetProtoPlatforms(repo.Platforms),
LastUpdatedImage: GetProtoLastUpdatedImage(repo.LastUpdatedImage),
}
}
func GetProtoImageMeta(imageMeta mTypes.ImageMeta) *proto_go.ImageMeta {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
if len(imageMeta.Manifests) == 0 {
return nil
}
manifestData := imageMeta.Manifests[0]
return GetProtoImageManifestData(manifestData.Manifest, manifestData.Config, manifestData.Size,
manifestData.Digest.String())
case ispec.MediaTypeImageIndex:
if imageMeta.Index == nil {
return nil
}
return GetProtoImageIndexMeta(*imageMeta.Index, imageMeta.Size, imageMeta.Digest.String())
default:
return nil
}
}
func GetProtoImageManifestData(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest string,
) *proto_go.ImageMeta {
return &proto_go.ImageMeta{
MediaType: ispec.MediaTypeImageManifest,
Manifests: []*proto_go.ManifestMeta{GetProtoManifestMeta(manifestContent, configContent, size, digest)},
Index: nil,
}
}
func GetProtoManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest string,
) *proto_go.ManifestMeta {
return &proto_go.ManifestMeta{
Digest: digest,
Size: size,
Manifest: &proto_go.Manifest{
Versioned: &proto_go.Versioned{SchemaVersion: int32(manifestContent.SchemaVersion)},
Config: &proto_go.Descriptor{
Digest: manifestContent.Config.Digest.String(),
Size: manifestContent.Config.Size,
MediaType: manifestContent.Config.MediaType,
},
MediaType: ref(ispec.MediaTypeImageManifest),
ArtifactType: &manifestContent.ArtifactType,
Layers: getProtoManifestLayers(manifestContent.Layers),
Subject: getProtoDesc(manifestContent.Subject),
Annotations: manifestContent.Annotations,
},
Config: &proto_go.Image{
Created: GetProtoTime(configContent.Created),
Author: &configContent.Author,
Platform: GetProtoPlatform(&configContent.Platform),
Config: &proto_go.ImageConfig{
User: configContent.Config.User,
ExposedPorts: getProtoExposedPorts(configContent.Config.ExposedPorts),
Env: configContent.Config.Env,
Entrypoint: configContent.Config.Entrypoint,
Cmd: configContent.Config.Cmd,
Volumes: getProtoConfigVolumes(configContent.Config.Volumes),
WorkingDir: &configContent.Config.WorkingDir,
Labels: configContent.Config.Labels,
StopSignal: &configContent.Config.StopSignal,
},
RootFS: &proto_go.RootFS{
Type: configContent.RootFS.Type,
DiffIDs: getProtoDiffIDs(configContent.RootFS.DiffIDs),
},
History: getProtoHistory(configContent.History),
},
}
}
func GetProtoImageIndexMeta(indexContent ispec.Index, size int64, digest string) *proto_go.ImageMeta {
return &proto_go.ImageMeta{
MediaType: ispec.MediaTypeImageIndex,
Index: &proto_go.IndexMeta{
Size: size,
Digest: digest,
Index: &proto_go.Index{
Versioned: &proto_go.Versioned{SchemaVersion: int32(indexContent.Versioned.SchemaVersion)},
MediaType: ref(ispec.MediaTypeImageIndex),
ArtifactType: ref(common.GetIndexArtifactType(indexContent)),
Manifests: getProtoManifestList(indexContent.Manifests),
Subject: getProtoDesc(indexContent.Subject),
Annotations: indexContent.Annotations,
},
},
}
}
func GetProtoStatistics(stats map[string]mTypes.DescriptorStatistics) map[string]*proto_go.DescriptorStatistics {
results := map[string]*proto_go.DescriptorStatistics{}
for digest, stat := range stats {
results[digest] = &proto_go.DescriptorStatistics{
DownloadCount: int32(stat.DownloadCount),
}
}
return results
}
func GetProtoPlatforms(platforms []ispec.Platform) []*proto_go.Platform {
result := []*proto_go.Platform{}
for i := range platforms {
result = append(result, &proto_go.Platform{
OS: platforms[i].OS,
Architecture: platforms[i].Architecture,
})
}
return result
}
func GetProtoReferrers(refs map[string][]mTypes.ReferrerInfo) map[string]*proto_go.ReferrersInfo {
results := map[string]*proto_go.ReferrersInfo{}
for digest, ref := range refs {
referrersInfoList := []*proto_go.ReferrerInfo{}
for _, dbRef := range ref {
referrersInfoList = append(referrersInfoList, GetProtoReferrerInfo(dbRef))
}
results[digest] = &proto_go.ReferrersInfo{List: referrersInfoList}
}
return results
}
func GetProtoSignatures(sigs map[string]mTypes.ManifestSignatures) map[string]*proto_go.ManifestSignatures {
results := map[string]*proto_go.ManifestSignatures{}
for digest, dbSignatures := range sigs {
imageSignatures := &proto_go.ManifestSignatures{Map: map[string]*proto_go.SignaturesInfo{}}
for signatureName, signatureInfo := range dbSignatures {
imageSignatures.Map[signatureName] = &proto_go.SignaturesInfo{List: GetProtoSignaturesInfo(signatureInfo)}
}
results[digest] = imageSignatures
}
return results
}
func GetProtoSignaturesInfo(sigsInfo []mTypes.SignatureInfo) []*proto_go.SignatureInfo {
results := []*proto_go.SignatureInfo{}
for _, sigInfo := range sigsInfo {
results = append(results, &proto_go.SignatureInfo{
SignatureManifestDigest: sigInfo.SignatureManifestDigest,
LayersInfo: GetProtoLayersInfo(sigInfo.LayersInfo),
})
}
return results
}
func GetProtoLayersInfo(layersInfo []mTypes.LayerInfo) []*proto_go.LayersInfo {
result := make([]*proto_go.LayersInfo, 0, len(layersInfo))
for _, layerInfo := range layersInfo {
result = append(result, &proto_go.LayersInfo{
LayerDigest: layerInfo.LayerDigest,
LayerContent: layerInfo.LayerContent,
SignatureKey: layerInfo.SignatureKey,
Signer: layerInfo.Signer,
Date: timestamppb.New(layerInfo.Date),
})
}
return result
}
func getProtoManifestLayers(layers []ispec.Descriptor) []*proto_go.Descriptor {
protoLayers := []*proto_go.Descriptor{}
for _, layer := range layers {
layer := layer
protoLayers = append(protoLayers, getProtoDesc(&layer))
}
return protoLayers
}
func getProtoDesc(descriptor *ispec.Descriptor) *proto_go.Descriptor {
if descriptor == nil {
return nil
}
return &proto_go.Descriptor{
MediaType: descriptor.MediaType,
Digest: descriptor.Digest.String(),
Size: descriptor.Size,
URLs: descriptor.URLs,
Annotations: descriptor.Annotations,
Data: descriptor.Data,
Platform: GetProtoPlatform(descriptor.Platform),
ArtifactType: &descriptor.ArtifactType,
}
}
func getProtoManifestList(manifests []ispec.Descriptor) []*proto_go.Descriptor {
result := make([]*proto_go.Descriptor, 0, len(manifests))
for _, manifest := range manifests {
result = append(result, &proto_go.Descriptor{
MediaType: manifest.MediaType,
Digest: manifest.Digest.String(),
Size: manifest.Size,
URLs: manifest.URLs,
Annotations: manifest.Annotations,
Data: manifest.Data,
Platform: GetProtoPlatform(manifest.Platform),
ArtifactType: ref(manifest.ArtifactType),
})
}
return result
}
func GetProtoPlatform(platform *ispec.Platform) *proto_go.Platform {
if platform == nil {
return nil
}
return &proto_go.Platform{
Architecture: platform.Architecture,
OS: platform.OS,
OSVersion: ref(platform.OSVersion),
OSFeatures: platform.OSFeatures,
Variant: ref(platform.Variant),
}
}
func getProtoHistory(historySlice []ispec.History) []*proto_go.History {
protoHistory := []*proto_go.History{}
for _, history := range historySlice {
history := history
protoHistory = append(protoHistory, &proto_go.History{
Created: GetProtoTime(history.Created),
CreatedBy: &history.CreatedBy,
Author: &history.Author,
Comment: &history.Comment,
EmptyLayer: &history.EmptyLayer,
})
}
return protoHistory
}
func getProtoDiffIDs(digests []godigest.Digest) []string {
digestsStr := []string{}
for _, digest := range digests {
digestsStr = append(digestsStr, digest.String())
}
return digestsStr
}
func getProtoExposedPorts(exposedPorts map[string]struct{}) map[string]*proto_go.EmptyMessage {
protoPorts := map[string]*proto_go.EmptyMessage{}
for i := range exposedPorts {
protoPorts[i] = &proto_go.EmptyMessage{}
}
return protoPorts
}
func getProtoConfigVolumes(volumes map[string]struct{}) map[string]*proto_go.EmptyMessage {
protoVolumes := map[string]*proto_go.EmptyMessage{}
for i := range volumes {
protoVolumes[i] = &proto_go.EmptyMessage{}
}
return protoVolumes
}
func GetProtoReferrerInfo(referrer mTypes.ReferrerInfo) *proto_go.ReferrerInfo {
return &proto_go.ReferrerInfo{
Digest: referrer.Digest,
MediaType: referrer.MediaType,
ArtifactType: referrer.ArtifactType,
Size: int64(referrer.Size),
Annotations: referrer.Annotations,
}
}
func GetProtoTime(time *time.Time) *timestamppb.Timestamp {
if time == nil {
return nil
}
return timestamppb.New(*time)
}
func GetProtoTags(tags map[string]mTypes.Descriptor) map[string]*proto_go.TagDescriptor {
resultMap := map[string]*proto_go.TagDescriptor{}
for tag, tagDescriptor := range tags {
resultMap[tag] = &proto_go.TagDescriptor{
Digest: tagDescriptor.Digest,
MediaType: tagDescriptor.MediaType,
}
}
return resultMap
}
func GetProtoLastUpdatedImage(lastUpdatedImage *mTypes.LastUpdatedImage) *proto_go.RepoLastUpdatedImage {
if lastUpdatedImage == nil {
return nil
}
return &proto_go.RepoLastUpdatedImage{
LastUpdated: GetProtoTime(lastUpdatedImage.LastUpdated),
MediaType: lastUpdatedImage.MediaType,
Digest: lastUpdatedImage.Digest,
Tag: lastUpdatedImage.Tag,
}
}
func GetProtoEarlierUpdatedImage(repoLastImage *proto_go.RepoLastUpdatedImage, lastImage *proto_go.RepoLastUpdatedImage,
) *proto_go.RepoLastUpdatedImage {
if repoLastImage == nil {
return lastImage
}
if lastImage == nil || lastImage.LastUpdated == nil {
return repoLastImage
}
if repoLastImage.LastUpdated == nil {
return lastImage
}
if repoLastImage.LastUpdated.AsTime().Before(lastImage.LastUpdated.AsTime()) {
return lastImage
}
return repoLastImage
}
func ref[T any](input T) *T {
ref := input
return &ref
}
func deref[T any](pointer *T, defaultVal T) T {
if pointer != nil {
return *pointer
}
return defaultVal
}

File diff suppressed because it is too large Load Diff

View File

@ -29,8 +29,6 @@ func TestWrapperErrors(t *testing.T) {
} }
repoMetaTablename := "RepoMetadataTable" + uuid.String() repoMetaTablename := "RepoMetadataTable" + uuid.String()
manifestDataTablename := "ManifestDataTable" + uuid.String()
indexDataTablename := "IndexDataTable" + uuid.String()
userDataTablename := "UserDataTable" + uuid.String() userDataTablename := "UserDataTable" + uuid.String()
apiKeyTablename := "ApiKeyTable" + uuid.String() apiKeyTablename := "ApiKeyTable" + uuid.String()
@ -56,8 +54,6 @@ func TestWrapperErrors(t *testing.T) {
dynamoWrapper := DynamoDB{ dynamoWrapper := DynamoDB{
Client: dynamodb.NewFromConfig(cfg), Client: dynamodb.NewFromConfig(cfg),
RepoMetaTablename: repoMetaTablename, RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename,
IndexDataTablename: indexDataTablename,
VersionTablename: versionTablename, VersionTablename: versionTablename,
UserDataTablename: userDataTablename, UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename, APIKeyTablename: apiKeyTablename,
@ -66,19 +62,13 @@ func TestWrapperErrors(t *testing.T) {
} }
// The table creation should fail as the endpoint is not configured correctly // The table creation should fail as the endpoint is not configured correctly
err = dynamoWrapper.createRepoMetaTable() err = dynamoWrapper.createTable(dynamoWrapper.RepoMetaTablename)
So(err, ShouldNotBeNil)
err = dynamoWrapper.createManifestDataTable()
So(err, ShouldNotBeNil)
err = dynamoWrapper.createIndexDataTable()
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
err = dynamoWrapper.createVersionTable() err = dynamoWrapper.createVersionTable()
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
err = dynamoWrapper.createAPIKeyTable() err = dynamoWrapper.createTable(dynamoWrapper.APIKeyTablename)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
@ -100,19 +90,14 @@ func TestWrapperErrors(t *testing.T) {
dynamoWrapper := DynamoDB{ dynamoWrapper := DynamoDB{
Client: dynamodb.NewFromConfig(cfg), Client: dynamodb.NewFromConfig(cfg),
RepoMetaTablename: repoMetaTablename, RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename,
VersionTablename: versionTablename, VersionTablename: versionTablename,
IndexDataTablename: indexDataTablename,
UserDataTablename: userDataTablename, UserDataTablename: userDataTablename,
Patches: version.GetDynamoDBPatches(), Patches: version.GetDynamoDBPatches(),
Log: log.Logger{Logger: zerolog.New(os.Stdout)}, Log: log.Logger{Logger: zerolog.New(os.Stdout)},
} }
// The tables were not created so delete calls fail, but dynamoWrapper should not error // The tables were not created so delete calls fail, but dynamoWrapper should not error
err = dynamoWrapper.deleteRepoMetaTable() err = dynamoWrapper.deleteTable(dynamoWrapper.RepoMetaTablename)
So(err, ShouldBeNil)
err = dynamoWrapper.deleteManifestDataTable()
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })
} }

View File

@ -3,7 +3,6 @@ package dynamodb_test
import ( import (
"context" "context"
"os" "os"
"strings"
"testing" "testing"
"github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws"
@ -12,8 +11,6 @@ import (
"github.com/aws/aws-sdk-go-v2/service/dynamodb" "github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types" "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
guuid "github.com/gofrs/uuid" guuid "github.com/gofrs/uuid"
"github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/rs/zerolog" "github.com/rs/zerolog"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
@ -40,9 +37,9 @@ func TestIterator(t *testing.T) {
} }
repoMetaTablename := "RepoMetadataTable" + uuid.String() repoMetaTablename := "RepoMetadataTable" + uuid.String()
manifestDataTablename := "ManifestDataTable" + uuid.String()
versionTablename := "Version" + uuid.String() versionTablename := "Version" + uuid.String()
indexDataTablename := "IndexDataTable" + uuid.String() imageMetaTablename := "ImageMeta" + uuid.String()
repoBlobsTablename := "RepoBlobs" + uuid.String()
userDataTablename := "UserDataTable" + uuid.String() userDataTablename := "UserDataTable" + uuid.String()
apiKeyTablename := "ApiKeyTable" + uuid.String() apiKeyTablename := "ApiKeyTable" + uuid.String()
@ -53,8 +50,8 @@ func TestIterator(t *testing.T) {
Endpoint: endpoint, Endpoint: endpoint,
Region: region, Region: region,
RepoMetaTablename: repoMetaTablename, RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename, ImageMetaTablename: imageMetaTablename,
IndexDataTablename: indexDataTablename, RepoBlobsInfoTablename: repoBlobsTablename,
VersionTablename: versionTablename, VersionTablename: versionTablename,
APIKeyTablename: apiKeyTablename, APIKeyTablename: apiKeyTablename,
UserDataTablename: userDataTablename, UserDataTablename: userDataTablename,
@ -65,21 +62,21 @@ func TestIterator(t *testing.T) {
dynamoWrapper, err := mdynamodb.New(client, params, log) dynamoWrapper, err := mdynamodb.New(client, params, log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(dynamoWrapper.ResetManifestDataTable(), ShouldBeNil) So(dynamoWrapper.ResetTable(dynamoWrapper.ImageMetaTablename), ShouldBeNil)
So(dynamoWrapper.ResetRepoMetaTable(), ShouldBeNil) So(dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename), ShouldBeNil)
err = dynamoWrapper.SetRepoReference("repo1", "tag1", "manifestType", "manifestDigest1") err = dynamoWrapper.SetRepoReference("repo1", "tag1", CreateRandomImage().AsImageMeta())
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = dynamoWrapper.SetRepoReference("repo2", "tag2", "manifestType", "manifestDigest2") err = dynamoWrapper.SetRepoReference("repo2", "tag2", CreateRandomImage().AsImageMeta())
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = dynamoWrapper.SetRepoReference("repo3", "tag3", "manifestType", "manifestDigest3") err = dynamoWrapper.SetRepoReference("repo3", "tag3", CreateRandomImage().AsImageMeta())
So(err, ShouldBeNil) So(err, ShouldBeNil)
repoMetaAttributeIterator := mdynamodb.NewBaseDynamoAttributesIterator( repoMetaAttributeIterator := mdynamodb.NewBaseDynamoAttributesIterator(
dynamoWrapper.Client, dynamoWrapper.Client,
repoMetaTablename, dynamoWrapper.RepoMetaTablename,
"RepoMetadata", "RepoMetadata",
1, 1,
log, log,
@ -143,12 +140,12 @@ func TestWrapperErrors(t *testing.T) {
} }
repoMetaTablename := "RepoMetadataTable" + uuid.String() repoMetaTablename := "RepoMetadataTable" + uuid.String()
manifestDataTablename := "ManifestDataTable" + uuid.String()
versionTablename := "Version" + uuid.String() versionTablename := "Version" + uuid.String()
indexDataTablename := "IndexDataTable" + uuid.String()
userDataTablename := "UserDataTable" + uuid.String() userDataTablename := "UserDataTable" + uuid.String()
apiKeyTablename := "ApiKeyTable" + uuid.String() apiKeyTablename := "ApiKeyTable" + uuid.String()
wrongTableName := "WRONG Tables" wrongTableName := "WRONG Tables"
imageMetaTablename := "ImageMeta" + uuid.String()
repoBlobsTablename := "RepoBlobs" + uuid.String()
log := log.NewLogger("debug", "") log := log.NewLogger("debug", "")
@ -157,8 +154,8 @@ func TestWrapperErrors(t *testing.T) {
Endpoint: endpoint, Endpoint: endpoint,
Region: region, Region: region,
RepoMetaTablename: repoMetaTablename, RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename, ImageMetaTablename: imageMetaTablename,
IndexDataTablename: indexDataTablename, RepoBlobsInfoTablename: repoBlobsTablename,
UserDataTablename: userDataTablename, UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename, APIKeyTablename: apiKeyTablename,
VersionTablename: versionTablename, VersionTablename: versionTablename,
@ -174,8 +171,9 @@ func TestWrapperErrors(t *testing.T) {
dynamoWrapper.SetImageTrustStore(imgTrustStore) dynamoWrapper.SetImageTrustStore(imgTrustStore)
So(dynamoWrapper.ResetManifestDataTable(), ShouldBeNil) //nolint:contextcheck So(dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename), ShouldBeNil) //nolint:contextcheck
So(dynamoWrapper.ResetRepoMetaTable(), ShouldBeNil) //nolint:contextcheck So(dynamoWrapper.ResetTable(dynamoWrapper.ImageMetaTablename), ShouldBeNil) //nolint:contextcheck
So(dynamoWrapper.ResetTable(dynamoWrapper.UserDataTablename), ShouldBeNil) //nolint:contextcheck
userAc := reqCtx.NewUserAccessControl() userAc := reqCtx.NewUserAccessControl()
userAc.SetUsername("test") userAc.SetUsername("test")
@ -240,7 +238,7 @@ func TestWrapperErrors(t *testing.T) {
status, err := dynamoWrapper.ToggleBookmarkRepo(ctx, "repo") status, err := dynamoWrapper.ToggleBookmarkRepo(ctx, "repo")
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(status, ShouldEqual, mTypes.NotChanged) So(status, ShouldEqual, mTypes.Added)
}) })
Convey("ToggleBookmarkRepo GetUserMeta client error", func() { Convey("ToggleBookmarkRepo GetUserMeta client error", func() {
@ -476,608 +474,6 @@ func TestWrapperErrors(t *testing.T) {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
Convey("SetManifestData", func() {
dynamoWrapper.ManifestDataTablename = wrongTableName
err := dynamoWrapper.SetManifestData("dig", mTypes.ManifestData{})
So(err, ShouldNotBeNil)
})
Convey("GetManifestData", func() {
dynamoWrapper.ManifestDataTablename = wrongTableName
_, err := dynamoWrapper.GetManifestData("dig")
So(err, ShouldNotBeNil)
})
Convey("GetManifestData unmarshal error", func() {
err := setBadManifestData(dynamoWrapper.Client, manifestDataTablename, "dig")
So(err, ShouldBeNil)
_, err = dynamoWrapper.GetManifestData("dig")
So(err, ShouldNotBeNil)
})
Convey("GetIndexData", func() {
dynamoWrapper.IndexDataTablename = wrongTableName
_, err := dynamoWrapper.GetIndexData("dig")
So(err, ShouldNotBeNil)
})
Convey("GetIndexData unmarshal error", func() {
err := setBadIndexData(dynamoWrapper.Client, indexDataTablename, "dig")
So(err, ShouldBeNil)
_, err = dynamoWrapper.GetManifestData("dig")
So(err, ShouldNotBeNil)
})
Convey("SetManifestMeta GetRepoMeta error", func() {
err := setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo1")
So(err, ShouldBeNil)
err = dynamoWrapper.SetManifestMeta("repo1", "dig", mTypes.ManifestMetadata{})
So(err, ShouldNotBeNil)
})
Convey("GetManifestMeta GetManifestData not found error", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag", "dig", "")
So(err, ShouldBeNil)
_, err = dynamoWrapper.GetManifestMeta("repo", "dig")
So(err, ShouldNotBeNil)
})
Convey("GetManifestMeta GetRepoMeta Not Found error", func() {
err := dynamoWrapper.SetManifestData("dig", mTypes.ManifestData{})
So(err, ShouldBeNil)
_, err = dynamoWrapper.GetManifestMeta("repoNotFound", "dig")
So(err, ShouldNotBeNil)
})
Convey("GetManifestMeta GetRepoMeta error", func() {
err := dynamoWrapper.SetManifestData("dig", mTypes.ManifestData{})
So(err, ShouldBeNil)
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo")
So(err, ShouldBeNil)
_, err = dynamoWrapper.GetManifestMeta("repo", "dig")
So(err, ShouldNotBeNil)
})
Convey("SetRepoReference client error", func() {
dynamoWrapper.RepoMetaTablename = badTablename
digest := digest.FromString("str")
err := dynamoWrapper.SetRepoReference("repo", digest.String(), digest, ispec.MediaTypeImageManifest)
So(err, ShouldNotBeNil)
})
Convey("SetReferrer client error", func() {
dynamoWrapper.RepoMetaTablename = badTablename
err := dynamoWrapper.SetReferrer("repo", "", mTypes.ReferrerInfo{})
So(err, ShouldNotBeNil)
})
Convey("SetReferrer bad repoMeta", func() {
err := setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo")
So(err, ShouldBeNil)
err = dynamoWrapper.SetReferrer("repo", "", mTypes.ReferrerInfo{})
So(err, ShouldNotBeNil)
})
Convey("GetReferrers client error", func() {
dynamoWrapper.RepoMetaTablename = badTablename
_, err := dynamoWrapper.GetReferrers("repo", "")
So(err, ShouldNotBeNil)
})
Convey("GetReferrers bad repoMeta", func() {
err := setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo")
So(err, ShouldBeNil)
_, err = dynamoWrapper.GetReferrers("repo", "")
So(err, ShouldNotBeNil)
})
Convey("DeleteReferrer client error", func() {
dynamoWrapper.RepoMetaTablename = badTablename
err := dynamoWrapper.DeleteReferrer("repo", "", "")
So(err, ShouldNotBeNil)
})
Convey("DeleteReferrer bad repoMeta", func() {
err := setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo")
So(err, ShouldBeNil)
err = dynamoWrapper.DeleteReferrer("repo", "", "")
So(err, ShouldNotBeNil)
})
Convey("GetReferrersInfo GetReferrers errors", func() {
dynamoWrapper.RepoMetaTablename = badTablename
_, err := dynamoWrapper.GetReferrersInfo("repo", "", nil)
So(err, ShouldNotBeNil)
})
Convey("GetReferrersInfo getData fails", func() {
dynamoWrapper.ManifestDataTablename = badTablename
err = dynamoWrapper.SetReferrer("repo", "rf", mTypes.ReferrerInfo{
Digest: "dig1",
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
err = dynamoWrapper.SetReferrer("repo", "rf", mTypes.ReferrerInfo{
Digest: "dig2",
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
_, err := dynamoWrapper.GetReferrersInfo("repo", "rf", nil)
So(err, ShouldBeNil)
})
Convey("GetReferrersInfo bad descriptor blob", func() {
err = dynamoWrapper.SetManifestData("dig3", mTypes.ManifestData{
ManifestBlob: []byte("bad json"),
})
So(err, ShouldBeNil)
err = dynamoWrapper.SetReferrer("repo", "rf", mTypes.ReferrerInfo{
Digest: "dig2",
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
err = dynamoWrapper.SetReferrer("repo", "rf", mTypes.ReferrerInfo{
Digest: "dig3",
MediaType: ispec.MediaTypeImageManifest,
})
So(err, ShouldBeNil)
_, err := dynamoWrapper.GetReferrersInfo("repo", "rf", nil)
So(err, ShouldBeNil)
})
Convey("IncrementRepoStars GetRepoMeta error", func() {
err = dynamoWrapper.IncrementRepoStars("repo")
So(err, ShouldNotBeNil)
})
Convey("DecrementRepoStars GetRepoMeta error", func() {
err = dynamoWrapper.DecrementRepoStars("repo")
So(err, ShouldNotBeNil)
})
Convey("DeleteRepoTag Client.GetItem error", func() {
strSlice := make([]string, 10000)
repoName := strings.Join(strSlice, ".")
err = dynamoWrapper.DeleteRepoTag(repoName, "tag")
So(err, ShouldNotBeNil)
})
Convey("DeleteRepoTag unmarshal error", func() {
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo")
So(err, ShouldBeNil)
err = dynamoWrapper.DeleteRepoTag("repo", "tag")
So(err, ShouldNotBeNil)
})
Convey("GetRepoMeta Client.GetItem error", func() {
strSlice := make([]string, 10000)
repoName := strings.Join(strSlice, ".")
_, err = dynamoWrapper.GetRepoMeta(repoName)
So(err, ShouldNotBeNil)
})
Convey("GetRepoMeta unmarshal error", func() {
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo")
So(err, ShouldBeNil)
_, err = dynamoWrapper.GetRepoMeta("repo")
So(err, ShouldNotBeNil)
})
Convey("IncrementImageDownloads GetRepoMeta error", func() {
err = dynamoWrapper.IncrementImageDownloads("repoNotFound", "")
So(err, ShouldNotBeNil)
})
Convey("IncrementImageDownloads tag not found error", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag", "dig", "")
So(err, ShouldBeNil)
err = dynamoWrapper.IncrementImageDownloads("repo", "notFoundTag")
So(err, ShouldNotBeNil)
})
Convey("UpdateSignaturesValidity GetManifestData error", func() {
err := setBadManifestData(dynamoWrapper.Client, manifestDataTablename, "dig")
So(err, ShouldBeNil)
err = dynamoWrapper.UpdateSignaturesValidity("repo", "dig")
So(err, ShouldNotBeNil)
err = dynamoWrapper.UpdateSignaturesValidity("repo", digest.FromString("dig"))
So(err, ShouldBeNil)
})
Convey("UpdateSignaturesValidity GetRepoMeta error", func() {
err := dynamoWrapper.SetManifestData("dig", mTypes.ManifestData{})
So(err, ShouldBeNil)
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo")
So(err, ShouldBeNil)
err = dynamoWrapper.UpdateSignaturesValidity("repo", "dig")
So(err, ShouldNotBeNil)
})
Convey("AddManifestSignature GetRepoMeta error", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag", "dig", "")
So(err, ShouldBeNil)
err = dynamoWrapper.AddManifestSignature("repoNotFound", "tag", mTypes.SignatureMetadata{})
So(err, ShouldNotBeNil)
})
Convey("AddManifestSignature ManifestSignatures signedManifestDigest not found error", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag", "dig", "")
So(err, ShouldBeNil)
err = dynamoWrapper.AddManifestSignature("repo", "tagNotFound", mTypes.SignatureMetadata{})
So(err, ShouldNotBeNil)
})
Convey("AddManifestSignature SignatureType metadb.NotationType", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag", "dig", "")
So(err, ShouldBeNil)
err = dynamoWrapper.AddManifestSignature("repo", "tagNotFound", mTypes.SignatureMetadata{
SignatureType: "notation",
})
So(err, ShouldBeNil)
})
Convey("DeleteSignature GetRepoMeta error", func() {
err = dynamoWrapper.DeleteSignature("repoNotFound", "tagNotFound", mTypes.SignatureMetadata{})
So(err, ShouldNotBeNil)
})
Convey("DeleteSignature sigDigest.SignatureManifestDigest != sigMeta.SignatureDigest true", func() {
err := setRepoMeta(dynamoWrapper.Client, repoMetaTablename, mTypes.RepoMetadata{
Name: "repo",
Signatures: map[string]mTypes.ManifestSignatures{
"tag1": {
"cosign": []mTypes.SignatureInfo{
{SignatureManifestDigest: "dig1"},
{SignatureManifestDigest: "dig2"},
},
},
},
})
So(err, ShouldBeNil)
err = dynamoWrapper.DeleteSignature("repo", "tag1", mTypes.SignatureMetadata{
SignatureDigest: "dig2",
SignatureType: "cosign",
})
So(err, ShouldBeNil)
})
Convey("GetMultipleRepoMeta unmarshal error", func() {
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo") //nolint:contextcheck
So(err, ShouldBeNil)
_, err = dynamoWrapper.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMetadata) bool { return true })
So(err, ShouldNotBeNil)
})
Convey("SearchRepos repoMeta unmarshal error", func() {
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo") //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchRepos(ctx, "")
So(err, ShouldNotBeNil)
})
Convey("SearchRepos bad tablename", func() {
dynamoWrapper.RepoMetaTablename = badTablename
_, _, _, err = dynamoWrapper.SearchRepos(ctx, "")
So(err, ShouldNotBeNil)
})
Convey("GetMultipleRepoMeta bad tablename", func() {
dynamoWrapper.RepoMetaTablename = badTablename
_, err = dynamoWrapper.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMetadata) bool { return true })
So(err, ShouldNotBeNil)
})
Convey("FilterTags bad tablename", func() {
dynamoWrapper.RepoMetaTablename = badTablename
_, _, _, err = dynamoWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return true
})
So(err, ShouldNotBeNil)
})
Convey("FilterRepos bad tablename", func() {
dynamoWrapper.RepoMetaTablename = badTablename
_, _, _, err = dynamoWrapper.FilterRepos(ctx, func(repoMeta mTypes.RepoMetadata) bool { return true })
So(err, ShouldNotBeNil)
})
Convey("SearchTags bad tablename", func() {
dynamoWrapper.RepoMetaTablename = badTablename
_, _, _, err = dynamoWrapper.SearchTags(ctx, "repo:tag")
So(err, ShouldNotBeNil)
})
Convey("SearchRepos GetManifestMeta error", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag1", "notFoundDigest", //nolint:contextcheck
ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchRepos(ctx, "")
So(err, ShouldNotBeNil)
})
Convey("Unsuported type", func() {
digest := digest.FromString("digest")
err := dynamoWrapper.SetRepoReference("repo", "tag1", digest, "invalid type") //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchRepos(ctx, "")
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchTags(ctx, "repo:")
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return true })
So(err, ShouldBeNil)
})
Convey("SearchRepos bad index data", func() {
indexDigest := digest.FromString("indexDigest")
err := dynamoWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = setBadIndexData(dynamoWrapper.Client, indexDataTablename, indexDigest.String()) //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchRepos(ctx, "")
So(err, ShouldNotBeNil)
})
Convey("SearchRepos bad indexBlob in IndexData", func() {
indexDigest := digest.FromString("indexDigest")
err := dynamoWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = dynamoWrapper.SetIndexData(indexDigest, mTypes.IndexData{ //nolint:contextcheck
IndexBlob: []byte("bad json"),
})
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchRepos(ctx, "")
So(err, ShouldNotBeNil)
})
Convey("SearchTags repoMeta unmarshal error", func() {
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo") //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchTags(ctx, "repo:")
So(err, ShouldNotBeNil)
})
Convey("SearchTags GetManifestMeta error", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag1", "manifestNotFound", //nolint:contextcheck
ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchTags(ctx, "repo:")
So(err, ShouldNotBeNil)
})
Convey("SearchTags bad index data", func() {
indexDigest := digest.FromString("indexDigest")
err := dynamoWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = setBadIndexData(dynamoWrapper.Client, indexDataTablename, indexDigest.String()) //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchTags(ctx, "repo:")
So(err, ShouldNotBeNil)
})
Convey("SearchTags bad indexBlob in IndexData", func() {
indexDigest := digest.FromString("indexDigest")
err := dynamoWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = dynamoWrapper.SetIndexData(indexDigest, mTypes.IndexData{ //nolint:contextcheck
IndexBlob: []byte("bad json"),
})
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.SearchTags(ctx, "repo:")
So(err, ShouldNotBeNil)
})
Convey("SearchRepos attr", func() {
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo") //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err := dynamoWrapper.SearchRepos(ctx, "repo")
So(err, ShouldNotBeNil)
})
Convey("FilterRepos attributevalue.Unmarshal(repoMetaAttribute) errors", func() {
dynamoWrapper.RepoMetaTablename = "bad-table-FilterRepos"
_, _, _, err := dynamoWrapper.FilterRepos(ctx, func(repoMeta mTypes.RepoMetadata) bool {
return true
})
So(err, ShouldNotBeNil)
})
Convey("SearchRepos bad RepoMeta table name", func() {
dynamoWrapper.RepoMetaTablename = "SearchRepos-bad-table"
_, _, _, err := dynamoWrapper.SearchRepos(ctx, "repo")
So(err, ShouldNotBeNil)
})
Convey("FilterTags repoMeta unmarshal error", func() {
err = setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo") //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return true
})
So(err, ShouldNotBeNil)
})
Convey("FilterTags bad RepoMeta table name", func() {
dynamoWrapper.RepoMetaTablename = "bad-table"
_, _, _, err := dynamoWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return true
})
So(err, ShouldNotBeNil)
})
Convey("FilterTags manifestMeta not found", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag1", "manifestNotFound", //nolint:contextcheck
ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return true
})
So(err, ShouldNotBeNil)
})
Convey("FilterTags manifestMeta unmarshal error", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag1", "dig", ispec.MediaTypeImageManifest) //nolint:contextcheck
So(err, ShouldBeNil)
err = setBadManifestData(dynamoWrapper.Client, manifestDataTablename, "dig") //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.FilterTags(
ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return true
})
So(err, ShouldNotBeNil)
})
Convey("FilterTags bad IndexData", func() {
indexDigest := digest.FromString("indexDigest")
err := dynamoWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = setBadIndexData(dynamoWrapper.Client, indexDataTablename, indexDigest.String()) //nolint:contextcheck
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return true })
So(err, ShouldNotBeNil)
})
Convey("FilterTags bad indexBlob in IndexData", func() {
indexDigest := digest.FromString("indexDigest")
err := dynamoWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
err = dynamoWrapper.SetIndexData(indexDigest, mTypes.IndexData{ //nolint:contextcheck
IndexBlob: []byte("bad json"),
})
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return true })
So(err, ShouldNotBeNil)
})
Convey("FilterTags didn't match any index manifest", func() {
var (
indexDigest = digest.FromString("indexDigest")
manifestDigestFromIndex1 = digest.FromString("manifestDigestFromIndex1")
manifestDigestFromIndex2 = digest.FromString("manifestDigestFromIndex2")
)
err := dynamoWrapper.SetRepoReference("repo", "tag1", indexDigest, ispec.MediaTypeImageIndex) //nolint:contextcheck
So(err, ShouldBeNil)
indexBlob, err := GetIndexBlobWithManifests([]digest.Digest{
manifestDigestFromIndex1, manifestDigestFromIndex2,
})
So(err, ShouldBeNil)
err = dynamoWrapper.SetIndexData(indexDigest, mTypes.IndexData{ //nolint:contextcheck
IndexBlob: indexBlob,
})
So(err, ShouldBeNil)
err = dynamoWrapper.SetManifestData(manifestDigestFromIndex1, mTypes.ManifestData{ //nolint:contextcheck
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
err = dynamoWrapper.SetManifestData(manifestDigestFromIndex2, mTypes.ManifestData{ //nolint:contextcheck
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("{}"),
})
So(err, ShouldBeNil)
_, _, _, err = dynamoWrapper.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { return false })
So(err, ShouldBeNil)
})
Convey("PatchDB dwr.getDBVersion errors", func() { Convey("PatchDB dwr.getDBVersion errors", func() {
dynamoWrapper.VersionTablename = badTablename dynamoWrapper.VersionTablename = badTablename
@ -1102,7 +498,7 @@ func TestWrapperErrors(t *testing.T) {
Convey("ResetRepoMetaTable client errors", func() { Convey("ResetRepoMetaTable client errors", func() {
dynamoWrapper.RepoMetaTablename = badTablename dynamoWrapper.RepoMetaTablename = badTablename
err := dynamoWrapper.ResetRepoMetaTable() err := dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
@ -1112,49 +508,6 @@ func TestWrapperErrors(t *testing.T) {
err := dynamoWrapper.PatchDB() err := dynamoWrapper.PatchDB()
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
Convey("GetUserRepoMeta client.GetItem error", func() {
dynamoWrapper.RepoMetaTablename = badTablename
_, err = dynamoWrapper.GetUserRepoMeta(ctx, "repo")
So(err, ShouldNotBeNil)
})
Convey("GetUserRepoMeta repoMeta not found", func() {
_, err = dynamoWrapper.GetUserRepoMeta(ctx, "unknown-repo-meta")
So(err, ShouldNotBeNil)
})
Convey("GetUserRepoMeta userMeta not found", func() {
err := dynamoWrapper.SetRepoReference("repo", "tag", digest.FromString("1"), ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
dynamoWrapper.UserDataTablename = badTablename
userAc := reqCtx.NewUserAccessControl()
userAc.SetUsername("username")
userAc.SetGlobPatterns("read", map[string]bool{
"repo": true,
})
ctx := userAc.DeriveContext(context.Background())
_, err = dynamoWrapper.GetUserRepoMeta(ctx, "repo")
So(err, ShouldNotBeNil)
})
Convey("GetUserRepoMeta unmarshal error", func() {
err := setBadRepoMeta(dynamoWrapper.Client, repoMetaTablename, "repo")
So(err, ShouldBeNil)
userAc := reqCtx.NewUserAccessControl()
userAc.SetUsername("username")
userAc.SetGlobPatterns("read", map[string]bool{
"repo": true,
})
ctx := userAc.DeriveContext(context.Background())
_, err = dynamoWrapper.GetUserRepoMeta(ctx, "repo")
So(err, ShouldNotBeNil)
})
}) })
Convey("NewDynamoDBWrapper errors", t, func() { Convey("NewDynamoDBWrapper errors", t, func() {
@ -1162,8 +515,8 @@ func TestWrapperErrors(t *testing.T) {
Endpoint: endpoint, Endpoint: endpoint,
Region: region, Region: region,
RepoMetaTablename: "", RepoMetaTablename: "",
ManifestDataTablename: manifestDataTablename, ImageMetaTablename: imageMetaTablename,
IndexDataTablename: indexDataTablename, RepoBlobsInfoTablename: repoBlobsTablename,
UserDataTablename: userDataTablename, UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename, APIKeyTablename: apiKeyTablename,
VersionTablename: versionTablename, VersionTablename: versionTablename,
@ -1178,40 +531,8 @@ func TestWrapperErrors(t *testing.T) {
Endpoint: endpoint, Endpoint: endpoint,
Region: region, Region: region,
RepoMetaTablename: repoMetaTablename, RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: "", ImageMetaTablename: imageMetaTablename,
IndexDataTablename: indexDataTablename, RepoBlobsInfoTablename: repoBlobsTablename,
UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename,
VersionTablename: versionTablename,
}
client, err = mdynamodb.GetDynamoClient(params)
So(err, ShouldBeNil)
_, err = mdynamodb.New(client, params, log)
So(err, ShouldNotBeNil)
params = mdynamodb.DBDriverParameters{ //nolint:contextcheck
Endpoint: endpoint,
Region: region,
RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename,
IndexDataTablename: "",
UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename,
VersionTablename: versionTablename,
}
client, err = mdynamodb.GetDynamoClient(params)
So(err, ShouldBeNil)
_, err = mdynamodb.New(client, params, log)
So(err, ShouldNotBeNil)
params = mdynamodb.DBDriverParameters{ //nolint:contextcheck
Endpoint: endpoint,
Region: region,
RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename,
IndexDataTablename: indexDataTablename,
UserDataTablename: userDataTablename, UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename, APIKeyTablename: apiKeyTablename,
VersionTablename: "", VersionTablename: "",
@ -1226,24 +547,8 @@ func TestWrapperErrors(t *testing.T) {
Endpoint: endpoint, Endpoint: endpoint,
Region: region, Region: region,
RepoMetaTablename: repoMetaTablename, RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename, ImageMetaTablename: imageMetaTablename,
IndexDataTablename: indexDataTablename, RepoBlobsInfoTablename: repoBlobsTablename,
VersionTablename: versionTablename,
UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename,
}
client, err = mdynamodb.GetDynamoClient(params)
So(err, ShouldBeNil)
_, err = mdynamodb.New(client, params, log)
So(err, ShouldBeNil)
params = mdynamodb.DBDriverParameters{ //nolint:contextcheck
Endpoint: endpoint,
Region: region,
RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename,
IndexDataTablename: indexDataTablename,
VersionTablename: versionTablename, VersionTablename: versionTablename,
UserDataTablename: "", UserDataTablename: "",
APIKeyTablename: apiKeyTablename, APIKeyTablename: apiKeyTablename,
@ -1258,8 +563,8 @@ func TestWrapperErrors(t *testing.T) {
Endpoint: endpoint, Endpoint: endpoint,
Region: region, Region: region,
RepoMetaTablename: repoMetaTablename, RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename, ImageMetaTablename: imageMetaTablename,
IndexDataTablename: indexDataTablename, RepoBlobsInfoTablename: repoBlobsTablename,
VersionTablename: versionTablename, VersionTablename: versionTablename,
UserDataTablename: userDataTablename, UserDataTablename: userDataTablename,
APIKeyTablename: "", APIKeyTablename: "",
@ -1272,81 +577,6 @@ func TestWrapperErrors(t *testing.T) {
}) })
} }
func setBadManifestData(client *dynamodb.Client, manifestDataTableName, digest string) error {
mdAttributeValue, err := attributevalue.Marshal("string")
if err != nil {
return err
}
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
ExpressionAttributeNames: map[string]string{
"#MD": "ManifestData",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":ManifestData": mdAttributeValue,
},
Key: map[string]types.AttributeValue{
"Digest": &types.AttributeValueMemberS{
Value: digest,
},
},
TableName: aws.String(manifestDataTableName),
UpdateExpression: aws.String("SET #MD = :ManifestData"),
})
return err
}
func setBadRepoMeta(client *dynamodb.Client, repoMetadataTableName, repoName string) error {
repoAttributeValue, err := attributevalue.Marshal("string")
if err != nil {
return err
}
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
ExpressionAttributeNames: map[string]string{
"#RM": "RepoMetadata",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":RepoMetadata": repoAttributeValue,
},
Key: map[string]types.AttributeValue{
"RepoName": &types.AttributeValueMemberS{
Value: repoName,
},
},
TableName: aws.String(repoMetadataTableName),
UpdateExpression: aws.String("SET #RM = :RepoMetadata"),
})
return err
}
func setBadIndexData(client *dynamodb.Client, indexDataTableName, digest string) error {
mdAttributeValue, err := attributevalue.Marshal("string")
if err != nil {
return err
}
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
ExpressionAttributeNames: map[string]string{
"#ID": "IndexData",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":IndexData": mdAttributeValue,
},
Key: map[string]types.AttributeValue{
"IndexDigest": &types.AttributeValueMemberS{
Value: digest,
},
},
TableName: aws.String(indexDataTableName),
UpdateExpression: aws.String("SET #ID = :IndexData"),
})
return err
}
func setBadUserData(client *dynamodb.Client, userDataTablename, userID string) error { func setBadUserData(client *dynamodb.Client, userDataTablename, userID string) error {
userAttributeValue, err := attributevalue.Marshal("string") userAttributeValue, err := attributevalue.Marshal("string")
if err != nil { if err != nil {
@ -1361,7 +591,7 @@ func setBadUserData(client *dynamodb.Client, userDataTablename, userID string) e
":UserData": userAttributeValue, ":UserData": userAttributeValue,
}, },
Key: map[string]types.AttributeValue{ Key: map[string]types.AttributeValue{
"Identity": &types.AttributeValueMemberS{ "Key": &types.AttributeValueMemberS{
Value: userID, Value: userID,
}, },
}, },
@ -1386,7 +616,7 @@ func setVersion(client *dynamodb.Client, versionTablename string, version string
":Version": mdAttributeValue, ":Version": mdAttributeValue,
}, },
Key: map[string]types.AttributeValue{ Key: map[string]types.AttributeValue{
"VersionKey": &types.AttributeValueMemberS{ "Key": &types.AttributeValueMemberS{
Value: "DBVersion", Value: "DBVersion",
}, },
}, },
@ -1396,28 +626,3 @@ func setVersion(client *dynamodb.Client, versionTablename string, version string
return err return err
} }
func setRepoMeta(client *dynamodb.Client, repoMetadataTableName string, repoMeta mTypes.RepoMetadata) error {
repoAttributeValue, err := attributevalue.Marshal(repoMeta)
if err != nil {
return err
}
_, err = client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{
ExpressionAttributeNames: map[string]string{
"#RM": "RepoMetadata",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":RepoMetadata": repoAttributeValue,
},
Key: map[string]types.AttributeValue{
"RepoName": &types.AttributeValueMemberS{
Value: repoMeta.Name,
},
},
TableName: aws.String(repoMetadataTableName),
UpdateExpression: aws.String("SET #RM = :RepoMetadata"),
})
return err
}

View File

@ -9,7 +9,7 @@ import (
) )
type DBDriverParameters struct { type DBDriverParameters struct {
Endpoint, Region, RepoMetaTablename, ManifestDataTablename, IndexDataTablename, Endpoint, Region, RepoMetaTablename, RepoBlobsInfoTablename, ImageMetaTablename,
UserDataTablename, APIKeyTablename, VersionTablename string UserDataTablename, APIKeyTablename, VersionTablename string
} }

View File

@ -2,10 +2,10 @@ package meta
import ( import (
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
zcommon "zotregistry.io/zot/pkg/common" zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/common"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage"
) )
@ -22,55 +22,9 @@ func OnUpdateManifest(repo, reference, mediaType string, digest godigest.Digest,
imgStore := storeController.GetImageStore(repo) imgStore := storeController.GetImageStore(repo)
// check if image is a signature err := SetImageMetaFromInput(repo, reference, mediaType, digest, body,
isSignature, signatureType, signedManifestDigest, err := storage.CheckIsImageSignature(repo, body, reference)
if err != nil {
log.Error().Err(err).Msg("can't check if image is a signature or not")
if err := imgStore.DeleteImageManifest(repo, reference, false); err != nil {
log.Error().Err(err).Str("manifest", reference).Str("repository", repo).Msg("couldn't remove image manifest in repo")
return err
}
return err
}
metadataSuccessfullySet := true
if isSignature {
layersInfo, errGetLayers := GetSignatureLayersInfo(repo, reference, digest.String(), signatureType, body,
imgStore, log)
if errGetLayers != nil {
metadataSuccessfullySet = false
err = errGetLayers
} else {
err = metaDB.AddManifestSignature(repo, signedManifestDigest, mTypes.SignatureMetadata{
SignatureType: signatureType,
SignatureDigest: digest.String(),
LayersInfo: layersInfo,
})
if err != nil {
log.Error().Err(err).Msg("metadb: error while putting repo meta")
metadataSuccessfullySet = false
} else {
err = metaDB.UpdateSignaturesValidity(repo, signedManifestDigest)
if err != nil {
log.Error().Err(err).Str("repository", repo).Str("reference", reference).Str("digest",
signedManifestDigest.String()).Msg("metadb: failed verify signatures validity for signed image")
metadataSuccessfullySet = false
}
}
}
} else {
err = SetImageMetaFromInput(repo, reference, mediaType, digest, body,
imgStore, metaDB, log) imgStore, metaDB, log)
if err != nil { if err != nil {
metadataSuccessfullySet = false
}
}
if !metadataSuccessfullySet {
log.Info().Str("tag", reference).Str("repository", repo).Msg("uploading image meta was unsuccessful for tag in repo") log.Info().Str("tag", reference).Str("repository", repo).Msg("uploading image meta was unsuccessful for tag in repo")
if err := imgStore.DeleteImageManifest(repo, reference, false); err != nil { if err := imgStore.DeleteImageManifest(repo, reference, false); err != nil {
@ -130,15 +84,6 @@ func OnDeleteManifest(repo, reference, mediaType string, digest godigest.Digest,
manageRepoMetaSuccessfully = false manageRepoMetaSuccessfully = false
} }
if referredDigest, hasSubject := common.GetReferredSubject(manifestBlob); hasSubject {
err := metaDB.DeleteReferrer(repo, referredDigest, digest)
if err != nil {
log.Error().Err(err).Msg("metadb: error while deleting referrer")
return err
}
}
} }
if !manageRepoMetaSuccessfully { if !manageRepoMetaSuccessfully {
@ -152,7 +97,7 @@ func OnDeleteManifest(repo, reference, mediaType string, digest godigest.Digest,
} }
// OnDeleteManifest is called when a manifest is downloaded. It increments the download couter on that manifest. // OnDeleteManifest is called when a manifest is downloaded. It increments the download couter on that manifest.
func OnGetManifest(name, reference string, body []byte, func OnGetManifest(name, reference, mediaType string, body []byte,
storeController storage.StoreController, metaDB mTypes.MetaDB, log log.Logger, storeController storage.StoreController, metaDB mTypes.MetaDB, log log.Logger,
) error { ) error {
// check if image is a signature // check if image is a signature
@ -163,15 +108,21 @@ func OnGetManifest(name, reference string, body []byte,
return err return err
} }
if !isSignature && !zcommon.IsReferrersTag(reference) { if isSignature || zcommon.IsReferrersTag(reference) {
err := metaDB.IncrementImageDownloads(name, reference) return nil
}
if !(mediaType == v1.MediaTypeImageManifest || mediaType == v1.MediaTypeImageIndex) {
return nil
}
err = metaDB.IncrementImageDownloads(name, reference)
if err != nil { if err != nil {
log.Error().Err(err).Str("repository", name).Str("reference", reference). log.Error().Err(err).Str("repository", name).Str("reference", reference).
Msg("unexpected error for image") Msg("unexpected error for image")
return err return err
} }
}
return nil return nil
} }

View File

@ -1,24 +1,19 @@
package meta_test package meta_test
import ( import (
"encoding/json" "context"
"errors" "errors"
"testing" "testing"
notreg "github.com/notaryproject/notation-go/registry"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/extensions/monitoring" "zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta" "zotregistry.io/zot/pkg/meta"
"zotregistry.io/zot/pkg/meta/boltdb" "zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/local" "zotregistry.io/zot/pkg/storage/local"
"zotregistry.io/zot/pkg/test/deprecated"
. "zotregistry.io/zot/pkg/test/image-utils" . "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks" "zotregistry.io/zot/pkg/test/mocks"
) )
@ -42,259 +37,38 @@ func TestOnUpdateManifest(t *testing.T) {
metaDB, err := boltdb.New(boltDriver, log) metaDB, err := boltdb.New(boltDriver, log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
config, layers, manifest, err := deprecated.GetRandomImageComponents(100) //nolint:staticcheck image := CreateDefaultImage()
err = WriteImageToFileSystem(CreateDefaultImage(), "repo", "tag1", storeController)
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = WriteImageToFileSystem( err = meta.OnUpdateManifest("repo", "tag1", ispec.MediaTypeImageManifest, image.Digest(),
Image{ image.ManifestDescriptor.Data, storeController, metaDB, log)
Config: config, Manifest: manifest, Layers: layers,
}, "repo", "tag1", storeController)
So(err, ShouldBeNil) So(err, ShouldBeNil)
manifestBlob, err := json.Marshal(manifest) repoMeta, err := metaDB.GetRepoMeta(context.Background(), "repo")
So(err, ShouldBeNil)
digest := godigest.FromBytes(manifestBlob)
err = meta.OnUpdateManifest("repo", "tag1", "", digest, manifestBlob, storeController, metaDB, log)
So(err, ShouldBeNil)
repoMeta, err := metaDB.GetRepoMeta("repo")
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(repoMeta.Tags, ShouldContainKey, "tag1") So(repoMeta.Tags, ShouldContainKey, "tag1")
}) })
Convey("metadataSuccessfullySet is false", t, func() {
rootDir := t.TempDir()
storeController := storage.StoreController{}
log := log.NewLogger("debug", "")
metrics := monitoring.NewMetricsServer(false, log)
storeController.DefaultStore = local.NewImageStore(rootDir, true, true, log, metrics, nil, nil)
metaDB := mocks.MetaDBMock{
SetManifestDataFn: func(manifestDigest godigest.Digest, mm mTypes.ManifestData) error {
return ErrTestError
},
}
err := meta.OnUpdateManifest("repo", "tag1", ispec.MediaTypeImageManifest, "digest",
[]byte("{}"), storeController, metaDB, log)
So(err, ShouldNotBeNil)
})
} }
func TestUpdateErrors(t *testing.T) { func TestUpdateErrors(t *testing.T) {
Convey("Update operations", t, func() { Convey("Update operations", t, func() {
Convey("On UpdateManifest", func() {
imageStore := mocks.MockedImageStore{} imageStore := mocks.MockedImageStore{}
storeController := storage.StoreController{DefaultStore: &imageStore} storeController := storage.StoreController{DefaultStore: &imageStore}
metaDB := mocks.MetaDBMock{} metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "") log := log.NewLogger("debug", "")
Convey("CheckIsImageSignature errors", func() { Convey("IsReferrersTag true update", func() {
badManifestBlob := []byte("bad")
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return []byte{}, "", "", zerr.ErrManifestNotFound
}
imageStore.DeleteImageManifestFn = func(repo, reference string, detectCollision bool) error {
return nil
}
err := meta.OnUpdateManifest("repo", "tag1", "digest", "media", badManifestBlob,
storeController, metaDB, log)
So(err, ShouldNotBeNil)
})
Convey("IsReferrersTag true", func() {
err := meta.OnUpdateManifest("repo", "sha256-123", "digest", "media", []byte("bad"), err := meta.OnUpdateManifest("repo", "sha256-123", "digest", "media", []byte("bad"),
storeController, metaDB, log) storeController, metaDB, log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })
Convey("IsReferrersTag true delete", func() {
Convey("GetSignatureLayersInfo errors", func() {
// get notation signature layers info
badNotationManifestContent := ispec.Manifest{
Subject: &ispec.Descriptor{
Digest: "123",
},
Config: ispec.Descriptor{MediaType: notreg.ArtifactTypeNotation},
}
badNotationManifestBlob, err := json.Marshal(badNotationManifestContent)
So(err, ShouldBeNil)
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return badNotationManifestBlob, "", "", nil
}
err = meta.OnUpdateManifest("repo", "tag1", "", "digest", badNotationManifestBlob,
storeController, metaDB, log)
So(err, ShouldNotBeNil)
})
Convey("UpdateSignaturesValidity", func() {
notationManifestContent := ispec.Manifest{
Subject: &ispec.Descriptor{
Digest: "123",
},
Config: ispec.Descriptor{MediaType: notreg.ArtifactTypeNotation},
Layers: []ispec.Descriptor{{
MediaType: ispec.MediaTypeImageLayer,
Digest: godigest.FromString("blob digest"),
}},
}
notationManifestBlob, err := json.Marshal(notationManifestContent)
So(err, ShouldBeNil)
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return notationManifestBlob, "", "", nil
}
imageStore.GetBlobContentFn = func(repo string, digest godigest.Digest) ([]byte, error) {
return []byte{}, nil
}
metaDB.UpdateSignaturesValidityFn = func(repo string, manifestDigest godigest.Digest) error {
return ErrTestError
}
err = meta.OnUpdateManifest("repo", "tag1", "", "digest", notationManifestBlob,
storeController, metaDB, log)
So(err, ShouldNotBeNil)
})
})
Convey("On DeleteManifest", func() {
imageStore := mocks.MockedImageStore{}
storeController := storage.StoreController{DefaultStore: &imageStore}
metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "")
Convey("CheckIsImageSignature errors", func() {
badManifestBlob := []byte("bad")
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return []byte{}, "", "", zerr.ErrManifestNotFound
}
err := meta.OnDeleteManifest("repo", "tag1", "digest", "media", badManifestBlob,
storeController, metaDB, log)
So(err, ShouldNotBeNil)
})
Convey("IsReferrersTag true", func() {
err := meta.OnDeleteManifest("repo", "sha256-123", "digest", "media", []byte("bad"), err := meta.OnDeleteManifest("repo", "sha256-123", "digest", "media", []byte("bad"),
storeController, metaDB, log) storeController, metaDB, log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })
Convey("DeleteReferrers errors", func() {
metaDB.DeleteReferrerFn = func(repo string, referredDigest, referrerDigest godigest.Digest) error {
return ErrTestError
}
err := meta.OnDeleteManifest("repo", "tag1", "digest", "media",
[]byte(`{"subject": {"digest": "dig"}}`),
storeController, metaDB, log)
So(err, ShouldNotBeNil)
})
})
Convey("On GetManifest", func() {
imageStore := mocks.MockedImageStore{}
storeController := storage.StoreController{DefaultStore: &imageStore}
metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "")
Convey("CheckIsImageSignature errors", func() {
badManifestBlob := []byte("bad")
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return []byte{}, "", "", zerr.ErrManifestNotFound
}
err := meta.OnGetManifest("repo", "tag1", badManifestBlob,
storeController, metaDB, log)
So(err, ShouldNotBeNil)
})
})
Convey("SetImageMetaFromInput", func() {
imageStore := mocks.MockedImageStore{}
metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "")
err := meta.SetImageMetaFromInput("repo", "ref", ispec.MediaTypeImageManifest, "digest",
[]byte("BadManifestBlob"), imageStore, metaDB, log)
So(err, ShouldNotBeNil)
// reference is digest
manifestContent := ispec.Manifest{}
manifestBlob, err := json.Marshal(manifestContent)
So(err, ShouldBeNil)
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return manifestBlob, "", "", nil
}
imageStore.GetBlobContentFn = func(repo string, digest godigest.Digest) ([]byte, error) {
return []byte("{}"), nil
}
err = meta.SetImageMetaFromInput("repo", string(godigest.FromString("reference")), "", "digest",
manifestBlob, imageStore, metaDB, log)
So(err, ShouldBeNil)
})
Convey("SetImageMetaFromInput SetData errors", func() {
imageStore := mocks.MockedImageStore{}
log := log.NewLogger("debug", "")
metaDB := mocks.MetaDBMock{
SetManifestDataFn: func(manifestDigest godigest.Digest, mm mTypes.ManifestData) error {
return ErrTestError
},
}
err := meta.SetImageMetaFromInput("repo", "ref", ispec.MediaTypeImageManifest, "digest",
[]byte("{}"), imageStore, metaDB, log)
So(err, ShouldNotBeNil)
})
Convey("SetImageMetaFromInput SetIndexData errors", func() {
imageStore := mocks.MockedImageStore{}
log := log.NewLogger("debug", "")
metaDB := mocks.MetaDBMock{
SetIndexDataFn: func(digest godigest.Digest, indexData mTypes.IndexData) error {
return ErrTestError
},
}
err := meta.SetImageMetaFromInput("repo", "ref", ispec.MediaTypeImageIndex, "digest",
[]byte("{}"), imageStore, metaDB, log)
So(err, ShouldNotBeNil)
})
Convey("SetImageMetaFromInput SetReferrer errors", func() {
imageStore := mocks.MockedImageStore{
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
return []byte("{}"), nil
},
}
log := log.NewLogger("debug", "")
metaDB := mocks.MetaDBMock{
SetReferrerFn: func(repo string, referredDigest godigest.Digest, referrer mTypes.ReferrerInfo) error {
return ErrTestError
},
}
err := meta.SetImageMetaFromInput("repo", "ref", ispec.MediaTypeImageManifest, "digest",
[]byte(`{"subject": {"digest": "subjDigest"}}`), imageStore, metaDB, log)
So(err, ShouldNotBeNil)
})
}) })
} }

View File

@ -81,10 +81,10 @@ func getDynamoParams(cacheDriverConfig map[string]interface{}, log log.Logger) m
repoMetaTablename, ok := toStringIfOk(cacheDriverConfig, "repometatablename", log) repoMetaTablename, ok := toStringIfOk(cacheDriverConfig, "repometatablename", log)
allParametersOk = allParametersOk && ok allParametersOk = allParametersOk && ok
manifestDataTablename, ok := toStringIfOk(cacheDriverConfig, "manifestdatatablename", log) repoBlobsInfoTablename, ok := toStringIfOk(cacheDriverConfig, "repoblobsinfotablename", log)
allParametersOk = allParametersOk && ok allParametersOk = allParametersOk && ok
indexDataTablename, ok := toStringIfOk(cacheDriverConfig, "indexdatatablename", log) imageMetaTablename, ok := toStringIfOk(cacheDriverConfig, "imagemetatablename", log)
allParametersOk = allParametersOk && ok allParametersOk = allParametersOk && ok
apiKeyTablename, ok := toStringIfOk(cacheDriverConfig, "apikeytablename", log) apiKeyTablename, ok := toStringIfOk(cacheDriverConfig, "apikeytablename", log)
@ -104,8 +104,8 @@ func getDynamoParams(cacheDriverConfig map[string]interface{}, log log.Logger) m
Endpoint: endpoint, Endpoint: endpoint,
Region: region, Region: region,
RepoMetaTablename: repoMetaTablename, RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename, RepoBlobsInfoTablename: repoBlobsInfoTablename,
IndexDataTablename: indexDataTablename, ImageMetaTablename: imageMetaTablename,
UserDataTablename: userDataTablename, UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename, APIKeyTablename: apiKeyTablename,
VersionTablename: versionTablename, VersionTablename: versionTablename,

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,6 @@ package meta
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"time" "time"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
@ -12,11 +11,17 @@ import (
zerr "zotregistry.io/zot/errors" zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common" zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/convert"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage"
storageTypes "zotregistry.io/zot/pkg/storage/types" storageTypes "zotregistry.io/zot/pkg/storage/types"
) )
const (
CosignType = "cosign"
NotationType = "notation"
)
// ParseStorage will sync all repos found in the rootdirectory of the oci layout that zot was deployed on with the // ParseStorage will sync all repos found in the rootdirectory of the oci layout that zot was deployed on with the
// ParseStorage database. // ParseStorage database.
func ParseStorage(metaDB mTypes.MetaDB, storeController storage.StoreController, log log.Logger) error { func ParseStorage(metaDB mTypes.MetaDB, storeController storage.StoreController, log log.Logger) error {
@ -31,7 +36,10 @@ func ParseStorage(metaDB mTypes.MetaDB, storeController storage.StoreController,
return err return err
} }
for _, repo := range allRepos { for i, repo := range allRepos {
log.Info().Int("total", len(allRepos)).Int("progress", i).Str("current-repo", repo).
Msgf("parsing next repo '%s'", repo)
err := ParseRepo(repo, metaDB, storeController, log) err := ParseRepo(repo, metaDB, storeController, log)
if err != nil { if err != nil {
log.Error().Err(err).Str("repository", repo).Msg("load-local-layout: failed to sync repo") log.Error().Err(err).Str("repository", repo).Msg("load-local-layout: failed to sync repo")
@ -70,75 +78,35 @@ func ParseRepo(repo string, metaDB mTypes.MetaDB, storeController storage.StoreC
return err return err
} }
err = resetRepoMeta(repo, metaDB, log) err = metaDB.ResetRepoReferences(repo)
if err != nil && !errors.Is(err, zerr.ErrRepoMetaNotFound) { if err != nil && !errors.Is(err, zerr.ErrRepoMetaNotFound) {
log.Error().Err(err).Str("repository", repo).Msg("load-repo: failed to reset tag field in RepoMetadata for repo") log.Error().Err(err).Str("repository", repo).Msg("load-repo: failed to reset tag field in RepoMetadata for repo")
return err return err
} }
for _, descriptor := range indexContent.Manifests { for _, manifest := range indexContent.Manifests {
tag := descriptor.Annotations[ispec.AnnotationRefName] tag := manifest.Annotations[ispec.AnnotationRefName]
if zcommon.IsReferrersTag(tag) { if zcommon.IsReferrersTag(tag) {
continue continue
} }
descriptorBlob, err := getCachedBlob(repo, descriptor, metaDB, imageStore, log) manifestBlob, _, _, err := imageStore.GetImageManifest(repo, manifest.Digest.String())
if err != nil { if err != nil {
log.Error().Err(err).Msg("load-repo: error checking manifestMeta in MetaDB") log.Error().Err(err).Str("repository", repo).Str("digest", manifest.Digest.String()).
Msg("load-repo: failed to get blob for image")
return err return err
} }
isSignature, signatureType, signedManifestDigest, err := storage.CheckIsImageSignature(repo,
descriptorBlob, tag)
if err != nil {
log.Error().Err(err).Str("repository", repo).Str("tag", tag).
Msg("load-repo: failed checking if image is signature for specified image")
return err
}
if isSignature {
layers, err := GetSignatureLayersInfo(repo, tag, descriptor.Digest.String(), signatureType,
descriptorBlob, imageStore, log)
if err != nil {
return err
}
err = metaDB.AddManifestSignature(repo, signedManifestDigest,
mTypes.SignatureMetadata{
SignatureType: signatureType,
SignatureDigest: descriptor.Digest.String(),
LayersInfo: layers,
})
if err != nil {
log.Error().Err(err).Str("repository", repo).Str("tag", tag).
Str("manifestDigest", signedManifestDigest.String()).
Msg("load-repo: failed set signature meta for signed image")
return err
}
err = metaDB.UpdateSignaturesValidity(repo, signedManifestDigest)
if err != nil {
log.Error().Err(err).Str("repository", repo).Str("reference", tag).Str("digest", signedManifestDigest.String()).Msg(
"load-repo: failed verify signatures validity for signed image")
return err
}
continue
}
reference := tag reference := tag
if tag == "" { if tag == "" {
reference = descriptor.Digest.String() reference = manifest.Digest.String()
} }
err = SetImageMetaFromInput(repo, reference, descriptor.MediaType, descriptor.Digest, descriptorBlob, err = SetImageMetaFromInput(repo, reference, manifest.MediaType, manifest.Digest, manifestBlob,
imageStore, metaDB, log) imageStore, metaDB, log)
if err != nil { if err != nil {
log.Error().Err(err).Str("repository", repo).Str("tag", tag). log.Error().Err(err).Str("repository", repo).Str("tag", tag).
@ -151,32 +119,6 @@ func ParseRepo(repo string, metaDB mTypes.MetaDB, storeController storage.StoreC
return nil return nil
} }
// resetRepoMeta will delete all tags and non-user related information from a RepoMetadata.
// It is used to recalculate and keep MetaDB consistent with the layout in case of unexpected changes.
func resetRepoMeta(repo string, metaDB mTypes.MetaDB, log log.Logger) error {
repoMeta, err := metaDB.GetRepoMeta(repo)
if err != nil && !errors.Is(err, zerr.ErrRepoMetaNotFound) {
log.Error().Err(err).Str("repository", repo).Msg("load-repo: failed to get RepoMeta for repo")
return err
}
if errors.Is(err, zerr.ErrRepoMetaNotFound) {
log.Info().Str("repository", repo).Msg("load-repo: RepoMeta not found for repo, new RepoMeta will be created")
return nil
}
return metaDB.SetRepoMeta(repo, mTypes.RepoMetadata{
Name: repoMeta.Name,
Tags: map[string]mTypes.Descriptor{},
Statistics: repoMeta.Statistics,
Signatures: map[string]mTypes.ManifestSignatures{},
Referrers: map[string][]mTypes.ReferrerInfo{},
Stars: repoMeta.Stars,
})
}
func getAllRepos(storeController storage.StoreController) ([]string, error) { func getAllRepos(storeController storage.StoreController) ([]string, error) {
allRepos, err := storeController.DefaultStore.GetRepositories() allRepos, err := storeController.DefaultStore.GetRepositories()
if err != nil { if err != nil {
@ -197,43 +139,6 @@ func getAllRepos(storeController storage.StoreController) ([]string, error) {
return allRepos, nil return allRepos, nil
} }
func getCachedBlob(repo string, descriptor ispec.Descriptor, metaDB mTypes.MetaDB,
imageStore storageTypes.ImageStore, log log.Logger,
) ([]byte, error) {
digest := descriptor.Digest
descriptorBlob, err := getCachedBlobFromMetaDB(descriptor, metaDB)
if err != nil || len(descriptorBlob) == 0 {
descriptorBlob, _, _, err = imageStore.GetImageManifest(repo, digest.String())
if err != nil {
log.Error().Err(err).Str("repository", repo).Str("digest", digest.String()).
Msg("load-repo: failed to get blob for image")
return nil, err
}
return descriptorBlob, nil
}
return descriptorBlob, nil
}
func getCachedBlobFromMetaDB(descriptor ispec.Descriptor, metaDB mTypes.MetaDB) ([]byte, error) {
switch descriptor.MediaType {
case ispec.MediaTypeImageManifest:
manifestData, err := metaDB.GetManifestData(descriptor.Digest)
return manifestData.ManifestBlob, err
case ispec.MediaTypeImageIndex:
indexData, err := metaDB.GetIndexData(descriptor.Digest)
return indexData.IndexBlob, err
}
return nil, nil
}
func GetSignatureLayersInfo(repo, tag, manifestDigest, signatureType string, manifestBlob []byte, func GetSignatureLayersInfo(repo, tag, manifestDigest, signatureType string, manifestBlob []byte,
imageStore storageTypes.ImageStore, log log.Logger, imageStore storageTypes.ImageStore, log log.Logger,
) ([]mTypes.LayerInfo, error) { ) ([]mTypes.LayerInfo, error) {
@ -341,92 +246,82 @@ func getNotationSignatureLayersInfo(
return layers, nil return layers, nil
} }
// NewManifestMeta takes raw data about an image and createa a new ManifestMetadate object. // SetMetadataFromInput tries to set manifest metadata and update repo metadata by adding the current tag
func NewManifestData(repoName string, manifestBlob []byte, imageStore storageTypes.ImageStore, // (in case the reference is a tag). The function expects image manifests and indexes (multi arch images).
) (mTypes.ManifestData, error) { func SetImageMetaFromInput(repo, reference, mediaType string, digest godigest.Digest, blob []byte,
var ( imageStore storageTypes.ImageStore, metaDB mTypes.MetaDB, log log.Logger,
manifestContent ispec.Manifest ) error {
configContent ispec.Image var imageMeta mTypes.ImageMeta
manifestData mTypes.ManifestData
)
err := json.Unmarshal(manifestBlob, &manifestContent) switch mediaType {
case ispec.MediaTypeImageManifest:
manifestContent := ispec.Manifest{}
configContent := ispec.Image{}
err := json.Unmarshal(blob, &manifestContent)
if err != nil { if err != nil {
return mTypes.ManifestData{}, err return err
}
var lockLatency time.Time
imageStore.RLock(&lockLatency)
defer imageStore.RUnlock(&lockLatency)
configBlob, err := imageStore.GetBlobContent(repoName, manifestContent.Config.Digest)
if err != nil {
return mTypes.ManifestData{}, err
} }
if manifestContent.Config.MediaType == ispec.MediaTypeImageConfig { if manifestContent.Config.MediaType == ispec.MediaTypeImageConfig {
configBlob, err := imageStore.GetBlobContent(repo, manifestContent.Config.Digest)
if err != nil {
return err
}
err = json.Unmarshal(configBlob, &configContent) err = json.Unmarshal(configBlob, &configContent)
if err != nil { if err != nil {
return mTypes.ManifestData{}, err return err
} }
} }
manifestData.ManifestBlob = manifestBlob if isSig, sigType, signedManifestDigest := isSignature(reference, manifestContent); isSig {
manifestData.ConfigBlob = configBlob layers, err := GetSignatureLayersInfo(repo, reference, digest.String(), sigType,
blob, imageStore, log)
return manifestData, nil
}
func NewIndexData(repoName string, indexBlob []byte, imageStore storageTypes.ImageStore,
) mTypes.IndexData {
indexData := mTypes.IndexData{}
indexData.IndexBlob = indexBlob
return indexData
}
// SetMetadataFromInput tries to set manifest metadata and update repo metadata by adding the current tag
// (in case the reference is a tag). The function expects image manifests and indexes (multi arch images).
func SetImageMetaFromInput(repo, reference, mediaType string, digest godigest.Digest, descriptorBlob []byte,
imageStore storageTypes.ImageStore, metaDB mTypes.MetaDB, log log.Logger,
) error {
switch mediaType {
case ispec.MediaTypeImageManifest:
imageData, err := NewManifestData(repo, descriptorBlob, imageStore)
if err != nil { if err != nil {
return err return err
} }
err = metaDB.SetManifestData(digest, imageData) err = metaDB.AddManifestSignature(repo, signedManifestDigest,
mTypes.SignatureMetadata{
SignatureType: sigType,
SignatureDigest: digest.String(),
LayersInfo: layers,
})
if err != nil { if err != nil {
log.Error().Err(err).Msg("metadb: error while putting manifest meta") log.Error().Err(err).Str("repository", repo).Str("tag", reference).
Str("manifestDigest", signedManifestDigest.String()).
Msg("load-repo: failed set signature meta for signed image")
return err return err
} }
err = metaDB.UpdateSignaturesValidity(repo, signedManifestDigest)
if err != nil {
log.Error().Err(err).Str("repository", repo).Str("reference", reference).Str("digest",
signedManifestDigest.String()).Msg("load-repo: failed verify signatures validity for signed image")
return err
}
return nil
}
imageMeta = convert.GetImageManifestMeta(manifestContent, configContent, int64(len(blob)), digest)
case ispec.MediaTypeImageIndex: case ispec.MediaTypeImageIndex:
indexData := NewIndexData(repo, descriptorBlob, imageStore) indexContent := ispec.Index{}
err := metaDB.SetIndexData(digest, indexData) err := json.Unmarshal(blob, &indexContent)
if err != nil { if err != nil {
log.Error().Err(err).Msg("metadb: error while putting index data")
return err return err
} }
imageMeta = convert.GetImageIndexMeta(indexContent, int64(len(blob)), digest)
default:
return nil
} }
referredDigest, referrerInfo, hasSubject, err := GetReferredInfo(descriptorBlob, digest.String(), mediaType) err := metaDB.SetRepoReference(repo, reference, imageMeta)
if hasSubject && err == nil {
err := metaDB.SetReferrer(repo, referredDigest, referrerInfo)
if err != nil {
log.Error().Err(err).Msg("metadb: error while settingg referrer")
return err
}
}
err = metaDB.SetRepoReference(repo, reference, digest, mediaType)
if err != nil { if err != nil {
log.Error().Err(err).Msg("metadb: error while putting repo meta") log.Error().Err(err).Msg("metadb: error while putting repo meta")
@ -436,55 +331,24 @@ func SetImageMetaFromInput(repo, reference, mediaType string, digest godigest.Di
return nil return nil
} }
func GetReferredInfo(descriptorBlob []byte, referrerDigest, mediaType string, func isSignature(reference string, manifestContent ispec.Manifest) (bool, string, godigest.Digest) {
) (godigest.Digest, mTypes.ReferrerInfo, bool, error) { manifestArtifactType := zcommon.GetManifestArtifactType(manifestContent)
var (
referrerInfo mTypes.ReferrerInfo
referrerSubject *ispec.Descriptor
)
switch mediaType { // check notation signature
case ispec.MediaTypeImageManifest: if manifestArtifactType == zcommon.ArtifactTypeNotation && manifestContent.Subject != nil {
var manifestContent ispec.Manifest return true, NotationType, manifestContent.Subject.Digest
err := json.Unmarshal(descriptorBlob, &manifestContent)
if err != nil {
return "", referrerInfo, false,
fmt.Errorf("metadb: can't unmarshal manifest for digest %s: %w", referrerDigest, err)
} }
referrerSubject = manifestContent.Subject if tag := reference; zcommon.IsCosignTag(reference) {
prefixLen := len("sha256-")
digestLen := 64
signedImageManifestDigestEncoded := tag[prefixLen : prefixLen+digestLen]
referrerInfo = mTypes.ReferrerInfo{ signedImageManifestDigest := godigest.NewDigestFromEncoded(godigest.SHA256,
Digest: referrerDigest, signedImageManifestDigestEncoded)
MediaType: mediaType,
ArtifactType: zcommon.GetManifestArtifactType(manifestContent),
Size: len(descriptorBlob),
Annotations: manifestContent.Annotations,
}
case ispec.MediaTypeImageIndex:
var indexContent ispec.Index
err := json.Unmarshal(descriptorBlob, &indexContent) return true, CosignType, signedImageManifestDigest
if err != nil {
return "", referrerInfo, false,
fmt.Errorf("metadb: can't unmarshal manifest for digest %s: %w", referrerDigest, err)
} }
referrerSubject = indexContent.Subject return false, "", ""
referrerInfo = mTypes.ReferrerInfo{
Digest: referrerDigest,
MediaType: mediaType,
ArtifactType: zcommon.GetIndexArtifactType(indexContent),
Size: len(descriptorBlob),
Annotations: indexContent.Annotations,
}
}
if referrerSubject == nil || referrerSubject.Digest.String() == "" {
return "", mTypes.ReferrerInfo{}, false, nil
}
return referrerSubject.Digest, referrerInfo, true, nil
} }

View File

@ -13,7 +13,6 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common" zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/monitoring" "zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/log"
@ -97,50 +96,6 @@ func TestParseStorageErrors(t *testing.T) {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
Convey("resetRepoMetaTags errors", func() {
imageStore.GetIndexContentFn = func(repo string) ([]byte, error) {
return []byte("{}"), nil
}
Convey("metaDB.GetRepoMeta errors", func() {
metaDB.GetRepoMetaFn = func(repo string) (mTypes.RepoMetadata, error) {
return mTypes.RepoMetadata{}, ErrTestError
}
err := meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
})
})
Convey("isManifestMetaPresent errors", func() {
indexContent := ispec.Index{
Manifests: []ispec.Descriptor{
{
Digest: godigest.FromString("manifest1"),
MediaType: ispec.MediaTypeImageManifest,
Annotations: map[string]string{
ispec.AnnotationRefName: "tag1",
},
},
},
}
indexBlob, err := json.Marshal(indexContent)
So(err, ShouldBeNil)
imageStore.GetIndexContentFn = func(repo string) ([]byte, error) {
return indexBlob, nil
}
Convey("metaDB.GetManifestMeta errors", func() {
metaDB.GetManifestMetaFn = func(repo string, manifestDigest godigest.Digest) (mTypes.ManifestMetadata, error) {
return mTypes.ManifestMetadata{}, ErrTestError
}
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
})
})
Convey("manifestMetaIsPresent true", func() { Convey("manifestMetaIsPresent true", func() {
indexContent := ispec.Index{ indexContent := ispec.Index{
Manifests: []ispec.Descriptor{ Manifests: []ispec.Descriptor{
@ -161,7 +116,7 @@ func TestParseStorageErrors(t *testing.T) {
} }
Convey("metaDB.SetRepoReference", func() { Convey("metaDB.SetRepoReference", func() {
metaDB.SetRepoReferenceFn = func(repo, tag string, manifestDigest godigest.Digest, mediaType string) error { metaDB.SetRepoReferenceFn = func(repo, reference string, imageMeta mTypes.ImageMeta) error {
return ErrTestError return ErrTestError
} }
@ -169,212 +124,6 @@ func TestParseStorageErrors(t *testing.T) {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
}) })
Convey("manifestMetaIsPresent false", func() {
indexContent := ispec.Index{
Manifests: []ispec.Descriptor{
{
Digest: godigest.FromString("manifest1"),
MediaType: ispec.MediaTypeImageManifest,
Annotations: map[string]string{
ispec.AnnotationRefName: "tag1",
},
},
},
}
indexBlob, err := json.Marshal(indexContent)
So(err, ShouldBeNil)
imageStore.GetIndexContentFn = func(repo string) ([]byte, error) {
return indexBlob, nil
}
metaDB.GetManifestMetaFn = func(repo string, manifestDigest godigest.Digest) (mTypes.ManifestMetadata, error) {
return mTypes.ManifestMetadata{}, zerr.ErrManifestMetaNotFound
}
Convey("GetImageManifest errors", func() {
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return nil, "", "", ErrTestError
}
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
})
Convey("CheckIsImageSignature errors", func() {
// CheckIsImageSignature will fail because of a invalid json
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return []byte("Invalid JSON"), "", "", nil
}
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
})
Convey("CheckIsImageSignature -> not signature", func() {
manifestContent := ispec.Manifest{}
manifestBlob, err := json.Marshal(manifestContent)
So(err, ShouldBeNil)
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return manifestBlob, "", "", nil
}
Convey("imgStore.GetBlobContent errors", func() {
imageStore.GetBlobContentFn = func(repo string, digest godigest.Digest) ([]byte, error) {
return nil, ErrTestError
}
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
})
})
Convey("CheckIsImageSignature -> is signature", func() {
manifestContent := ispec.Manifest{
Subject: &ispec.Descriptor{
Digest: "123",
},
ArtifactType: "application/vnd.cncf.notary.signature",
Layers: []ispec.Descriptor{{MediaType: ispec.MediaTypeImageLayer}},
}
manifestBlob, err := json.Marshal(manifestContent)
So(err, ShouldBeNil)
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return manifestBlob, "", "", nil
}
metaDB.AddManifestSignatureFn = func(repo string, signedManifestDigest godigest.Digest,
sm mTypes.SignatureMetadata,
) error {
return ErrTestError
}
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
metaDB.AddManifestSignatureFn = func(repo string, signedManifestDigest godigest.Digest,
sm mTypes.SignatureMetadata,
) error {
return nil
}
metaDB.UpdateSignaturesValidityFn = func(repo string, signedManifestDigest godigest.Digest,
) error {
return ErrTestError
}
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
})
Convey("GetSignatureLayersInfo errors", func() {
// get notation signature layers info
badNotationManifestContent := ispec.Manifest{
Subject: &ispec.Descriptor{
Digest: "123",
},
ArtifactType: "application/vnd.cncf.notary.signature",
}
badNotationManifestBlob, err := json.Marshal(badNotationManifestContent)
So(err, ShouldBeNil)
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return badNotationManifestBlob, "", "", nil
}
// wrong number of layers of notation manifest
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
notationManifestContent := ispec.Manifest{
Subject: &ispec.Descriptor{
Digest: "123",
},
ArtifactType: "application/vnd.cncf.notary.signature",
Layers: []ispec.Descriptor{{MediaType: ispec.MediaTypeImageLayer}},
}
notationManifestBlob, err := json.Marshal(notationManifestContent)
So(err, ShouldBeNil)
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return notationManifestBlob, "", "", nil
}
imageStore.GetBlobContentFn = func(repo string, digest godigest.Digest) ([]byte, error) {
return []byte{}, ErrTestError
}
// unable to get layer content
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
_, _, cosignManifestContent, _ := deprecated.GetRandomImageComponents(10) //nolint:staticcheck
_, _, signedManifest, _ := deprecated.GetRandomImageComponents(10) //nolint:staticcheck
signatureTag, err := signature.GetCosignSignatureTagForManifest(signedManifest)
So(err, ShouldBeNil)
cosignManifestContent.Annotations = map[string]string{ispec.AnnotationRefName: signatureTag}
cosignManifestBlob, err := json.Marshal(cosignManifestContent)
So(err, ShouldBeNil)
imageStore.GetImageManifestFn = func(repo, reference string) ([]byte, godigest.Digest, string, error) {
return cosignManifestBlob, "", "", nil
}
indexContent := ispec.Index{
Manifests: []ispec.Descriptor{
{
Digest: godigest.FromString("cosignSig"),
MediaType: ispec.MediaTypeImageManifest,
Annotations: map[string]string{
ispec.AnnotationRefName: signatureTag,
},
},
},
}
indexBlob, err := json.Marshal(indexContent)
So(err, ShouldBeNil)
imageStore.GetIndexContentFn = func(repo string) ([]byte, error) {
return indexBlob, nil
}
// unable to get layer content
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldNotBeNil)
})
Convey("IsReferrersTag -> true", func() {
indexContent := ispec.Index{
Manifests: []ispec.Descriptor{
{
Digest: godigest.FromString("indx1"),
MediaType: ispec.MediaTypeImageIndex,
Annotations: map[string]string{
ispec.AnnotationRefName: "sha256-123",
},
},
},
}
indexBlob, err := json.Marshal(indexContent)
So(err, ShouldBeNil)
imageStore.GetIndexContentFn = func(repo string) ([]byte, error) {
return indexBlob, nil
}
metaDB.SetIndexDataFn = func(digest godigest.Digest, indexData mTypes.IndexData) error {
return ErrTestError
}
err = meta.ParseRepo("repo", metaDB, storeController, log)
So(err, ShouldBeNil)
})
})
}) })
} }
@ -404,8 +153,8 @@ func TestParseStorageDynamoWrapper(t *testing.T) {
Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"), Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"),
Region: "us-east-2", Region: "us-east-2",
RepoMetaTablename: "RepoMetadataTable", RepoMetaTablename: "RepoMetadataTable",
ManifestDataTablename: "ManifestDataTable", RepoBlobsInfoTablename: "RepoBlobsInfoTablename",
IndexDataTablename: "IndexDataTable", ImageMetaTablename: "ImageMetaTablename",
UserDataTablename: "UserDataTable", UserDataTablename: "UserDataTable",
APIKeyTablename: "ApiKeyTable", APIKeyTablename: "ApiKeyTable",
VersionTablename: "Version", VersionTablename: "Version",
@ -417,10 +166,13 @@ func TestParseStorageDynamoWrapper(t *testing.T) {
dynamoWrapper, err := dynamodb.New(dynamoClient, params, log.NewLogger("debug", "")) dynamoWrapper, err := dynamodb.New(dynamoClient, params, log.NewLogger("debug", ""))
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = dynamoWrapper.ResetManifestDataTable() err = dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename)
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = dynamoWrapper.ResetRepoMetaTable() err = dynamoWrapper.ResetTable(dynamoWrapper.RepoBlobsTablename)
So(err, ShouldBeNil)
err = dynamoWrapper.ResetTable(dynamoWrapper.ImageMetaTablename)
So(err, ShouldBeNil) So(err, ShouldBeNil)
RunParseStorageTests(rootDir, dynamoWrapper) RunParseStorageTests(rootDir, dynamoWrapper)
@ -496,20 +248,20 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
repos, err := metaDB.GetMultipleRepoMeta(context.Background(), repos, err := metaDB.GetMultipleRepoMeta(context.Background(),
func(repoMeta mTypes.RepoMetadata) bool { return true }) func(repoMeta mTypes.RepoMeta) bool { return true })
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1) So(len(repos), ShouldEqual, 1)
So(len(repos[0].Tags), ShouldEqual, 2) So(len(repos[0].Tags), ShouldEqual, 2)
for _, descriptor := range repos[0].Tags { ctx := context.Background()
manifestMeta, err := metaDB.GetManifestMeta(repo, godigest.Digest(descriptor.Digest))
for tag, descriptor := range repos[0].Tags {
imageManifestData, err := metaDB.GetFullImageMeta(ctx, repo, tag)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(manifestMeta.ManifestBlob, ShouldNotBeNil)
So(manifestMeta.ConfigBlob, ShouldNotBeNil)
if descriptor.Digest == signedManifestDigest.String() { if descriptor.Digest == signedManifestDigest.String() {
So(manifestMeta.Signatures, ShouldNotBeEmpty) So(imageManifestData.Signatures, ShouldNotBeEmpty)
} }
} }
}) })
@ -555,10 +307,8 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
err = meta.ParseStorage(metaDB, storeController, log.NewLogger("debug", "")) err = meta.ParseStorage(metaDB, storeController, log.NewLogger("debug", ""))
So(err, ShouldBeNil) So(err, ShouldBeNil)
repos, err := metaDB.GetMultipleRepoMeta( repos, err := metaDB.GetMultipleRepoMeta(context.Background(),
context.Background(), func(repoMeta mTypes.RepoMeta) bool { return true })
func(repoMeta mTypes.RepoMetadata) bool { return true },
)
So(err, ShouldBeNil) So(err, ShouldBeNil)
for _, desc := range repos[0].Tags { for _, desc := range repos[0].Tags {
@ -577,15 +327,12 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
storeController := storage.StoreController{DefaultStore: imageStore} storeController := storage.StoreController{DefaultStore: imageStore}
// add an image // add an image
image, err := deprecated.GetRandomImage() //nolint:staticcheck image := CreateRandomImage() //nolint:staticcheck
err := WriteImageToFileSystem(image, repo, "tag", storeController)
So(err, ShouldBeNil) So(err, ShouldBeNil)
manifestDigest := image.Digest() err = metaDB.SetRepoReference(repo, "tag", image.AsImageMeta())
err = WriteImageToFileSystem(image, repo, "tag", storeController)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo, "tag", manifestDigest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = metaDB.IncrementRepoStars(repo) err = metaDB.IncrementRepoStars(repo)
@ -597,30 +344,20 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
err = metaDB.IncrementImageDownloads(repo, "tag") err = metaDB.IncrementImageDownloads(repo, "tag")
So(err, ShouldBeNil) So(err, ShouldBeNil)
repoMeta, err := metaDB.GetRepoMeta(repo) repoMeta, err := metaDB.GetRepoMeta(context.Background(), repo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(repoMeta.Statistics[manifestDigest.String()].DownloadCount, ShouldEqual, 3) So(repoMeta.Statistics[image.DigestStr()].DownloadCount, ShouldEqual, 3)
So(repoMeta.Stars, ShouldEqual, 1) So(repoMeta.StarCount, ShouldEqual, 1)
err = meta.ParseStorage(metaDB, storeController, log.NewLogger("debug", "")) err = meta.ParseStorage(metaDB, storeController, log.NewLogger("debug", ""))
So(err, ShouldBeNil) So(err, ShouldBeNil)
repoMeta, err = metaDB.GetRepoMeta(repo) repoMeta, err = metaDB.GetRepoMeta(context.Background(), repo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(repoMeta.Statistics[manifestDigest.String()].DownloadCount, ShouldEqual, 3) So(repoMeta.Statistics[image.DigestStr()].DownloadCount, ShouldEqual, 3)
So(repoMeta.Stars, ShouldEqual, 1) So(repoMeta.StarCount, ShouldEqual, 1)
})
}
func TestGetReferredInfo(t *testing.T) {
Convey("GetReferredInfo error", t, func() {
_, _, _, err := meta.GetReferredInfo([]byte("bad json"), "digest", ispec.MediaTypeImageManifest)
So(err, ShouldNotBeNil)
_, _, _, err = meta.GetReferredInfo([]byte("bad json"), "digest", ispec.MediaTypeImageIndex)
So(err, ShouldNotBeNil)
}) })
} }

View File

@ -0,0 +1,628 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc v4.24.4
// source: oci/config.proto
package gen
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Image struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Created *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=Created,proto3,oneof" json:"Created,omitempty"`
Author *string `protobuf:"bytes,2,opt,name=Author,proto3,oneof" json:"Author,omitempty"`
Platform *Platform `protobuf:"bytes,3,opt,name=Platform,proto3" json:"Platform,omitempty"`
Config *ImageConfig `protobuf:"bytes,4,opt,name=Config,proto3,oneof" json:"Config,omitempty"`
RootFS *RootFS `protobuf:"bytes,5,opt,name=RootFS,proto3,oneof" json:"RootFS,omitempty"`
History []*History `protobuf:"bytes,6,rep,name=History,proto3" json:"History,omitempty"`
}
func (x *Image) Reset() {
*x = Image{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Image) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Image) ProtoMessage() {}
func (x *Image) ProtoReflect() protoreflect.Message {
mi := &file_oci_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Image.ProtoReflect.Descriptor instead.
func (*Image) Descriptor() ([]byte, []int) {
return file_oci_config_proto_rawDescGZIP(), []int{0}
}
func (x *Image) GetCreated() *timestamppb.Timestamp {
if x != nil {
return x.Created
}
return nil
}
func (x *Image) GetAuthor() string {
if x != nil && x.Author != nil {
return *x.Author
}
return ""
}
func (x *Image) GetPlatform() *Platform {
if x != nil {
return x.Platform
}
return nil
}
func (x *Image) GetConfig() *ImageConfig {
if x != nil {
return x.Config
}
return nil
}
func (x *Image) GetRootFS() *RootFS {
if x != nil {
return x.RootFS
}
return nil
}
func (x *Image) GetHistory() []*History {
if x != nil {
return x.History
}
return nil
}
type ImageConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ExposedPorts map[string]*EmptyMessage `protobuf:"bytes,1,rep,name=ExposedPorts,proto3" json:"ExposedPorts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Volumes map[string]*EmptyMessage `protobuf:"bytes,2,rep,name=Volumes,proto3" json:"Volumes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Labels map[string]string `protobuf:"bytes,3,rep,name=Labels,proto3" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
User string `protobuf:"bytes,4,opt,name=User,proto3" json:"User,omitempty"`
Env []string `protobuf:"bytes,5,rep,name=Env,proto3" json:"Env,omitempty"`
Entrypoint []string `protobuf:"bytes,6,rep,name=Entrypoint,proto3" json:"Entrypoint,omitempty"`
Cmd []string `protobuf:"bytes,7,rep,name=Cmd,proto3" json:"Cmd,omitempty"`
WorkingDir *string `protobuf:"bytes,8,opt,name=WorkingDir,proto3,oneof" json:"WorkingDir,omitempty"`
StopSignal *string `protobuf:"bytes,9,opt,name=StopSignal,proto3,oneof" json:"StopSignal,omitempty"`
ArgsEscaped bool `protobuf:"varint,10,opt,name=ArgsEscaped,proto3" json:"ArgsEscaped,omitempty"`
}
func (x *ImageConfig) Reset() {
*x = ImageConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageConfig) ProtoMessage() {}
func (x *ImageConfig) ProtoReflect() protoreflect.Message {
mi := &file_oci_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageConfig.ProtoReflect.Descriptor instead.
func (*ImageConfig) Descriptor() ([]byte, []int) {
return file_oci_config_proto_rawDescGZIP(), []int{1}
}
func (x *ImageConfig) GetExposedPorts() map[string]*EmptyMessage {
if x != nil {
return x.ExposedPorts
}
return nil
}
func (x *ImageConfig) GetVolumes() map[string]*EmptyMessage {
if x != nil {
return x.Volumes
}
return nil
}
func (x *ImageConfig) GetLabels() map[string]string {
if x != nil {
return x.Labels
}
return nil
}
func (x *ImageConfig) GetUser() string {
if x != nil {
return x.User
}
return ""
}
func (x *ImageConfig) GetEnv() []string {
if x != nil {
return x.Env
}
return nil
}
func (x *ImageConfig) GetEntrypoint() []string {
if x != nil {
return x.Entrypoint
}
return nil
}
func (x *ImageConfig) GetCmd() []string {
if x != nil {
return x.Cmd
}
return nil
}
func (x *ImageConfig) GetWorkingDir() string {
if x != nil && x.WorkingDir != nil {
return *x.WorkingDir
}
return ""
}
func (x *ImageConfig) GetStopSignal() string {
if x != nil && x.StopSignal != nil {
return *x.StopSignal
}
return ""
}
func (x *ImageConfig) GetArgsEscaped() bool {
if x != nil {
return x.ArgsEscaped
}
return false
}
type RootFS struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"`
DiffIDs []string `protobuf:"bytes,2,rep,name=DiffIDs,proto3" json:"DiffIDs,omitempty"`
}
func (x *RootFS) Reset() {
*x = RootFS{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RootFS) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RootFS) ProtoMessage() {}
func (x *RootFS) ProtoReflect() protoreflect.Message {
mi := &file_oci_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RootFS.ProtoReflect.Descriptor instead.
func (*RootFS) Descriptor() ([]byte, []int) {
return file_oci_config_proto_rawDescGZIP(), []int{2}
}
func (x *RootFS) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *RootFS) GetDiffIDs() []string {
if x != nil {
return x.DiffIDs
}
return nil
}
type History struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Created *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=Created,proto3,oneof" json:"Created,omitempty"`
CreatedBy *string `protobuf:"bytes,2,opt,name=CreatedBy,proto3,oneof" json:"CreatedBy,omitempty"`
Author *string `protobuf:"bytes,3,opt,name=Author,proto3,oneof" json:"Author,omitempty"`
Comment *string `protobuf:"bytes,4,opt,name=Comment,proto3,oneof" json:"Comment,omitempty"`
EmptyLayer *bool `protobuf:"varint,5,opt,name=EmptyLayer,proto3,oneof" json:"EmptyLayer,omitempty"`
}
func (x *History) Reset() {
*x = History{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *History) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*History) ProtoMessage() {}
func (x *History) ProtoReflect() protoreflect.Message {
mi := &file_oci_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use History.ProtoReflect.Descriptor instead.
func (*History) Descriptor() ([]byte, []int) {
return file_oci_config_proto_rawDescGZIP(), []int{3}
}
func (x *History) GetCreated() *timestamppb.Timestamp {
if x != nil {
return x.Created
}
return nil
}
func (x *History) GetCreatedBy() string {
if x != nil && x.CreatedBy != nil {
return *x.CreatedBy
}
return ""
}
func (x *History) GetAuthor() string {
if x != nil && x.Author != nil {
return *x.Author
}
return ""
}
func (x *History) GetComment() string {
if x != nil && x.Comment != nil {
return *x.Comment
}
return ""
}
func (x *History) GetEmptyLayer() bool {
if x != nil && x.EmptyLayer != nil {
return *x.EmptyLayer
}
return false
}
type EmptyMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *EmptyMessage) Reset() {
*x = EmptyMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EmptyMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EmptyMessage) ProtoMessage() {}
func (x *EmptyMessage) ProtoReflect() protoreflect.Message {
mi := &file_oci_config_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EmptyMessage.ProtoReflect.Descriptor instead.
func (*EmptyMessage) Descriptor() ([]byte, []int) {
return file_oci_config_proto_rawDescGZIP(), []int{4}
}
var File_oci_config_proto protoreflect.FileDescriptor
var file_oci_config_proto_rawDesc = []byte{
0x0a, 0x10, 0x6f, 0x63, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x06, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x1a, 0x13, 0x6f, 0x63, 0x69, 0x2f,
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
0x14, 0x6f, 0x63, 0x69, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc4, 0x02, 0x0a, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12,
0x39, 0x0a, 0x07, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x07,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x41, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x06, 0x41, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66,
0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6f, 0x63, 0x69, 0x5f,
0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x50, 0x6c, 0x61,
0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x30, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x49,
0x6d, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x02, 0x52, 0x06, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x88, 0x01, 0x01, 0x12, 0x2b, 0x0a, 0x06, 0x52, 0x6f, 0x6f, 0x74, 0x46,
0x53, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31,
0x2e, 0x52, 0x6f, 0x6f, 0x74, 0x46, 0x53, 0x48, 0x03, 0x52, 0x06, 0x52, 0x6f, 0x6f, 0x74, 0x46,
0x53, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x07, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18,
0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x48,
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x07, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x42,
0x0a, 0x0a, 0x08, 0x5f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x5f,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x52, 0x6f, 0x6f, 0x74, 0x46, 0x53, 0x22, 0x93, 0x05, 0x0a,
0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x49, 0x0a, 0x0c,
0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x61, 0x67,
0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x50,
0x6f, 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x45, 0x78, 0x70, 0x6f, 0x73,
0x65, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x07, 0x56, 0x6f, 0x6c, 0x75, 0x6d,
0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76,
0x31, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x56, 0x6f,
0x6c, 0x75, 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x56, 0x6f, 0x6c, 0x75,
0x6d, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x61,
0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04,
0x55, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72,
0x12, 0x10, 0x0a, 0x03, 0x45, 0x6e, 0x76, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x45,
0x6e, 0x76, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69,
0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x43, 0x6d, 0x64, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52,
0x03, 0x43, 0x6d, 0x64, 0x12, 0x23, 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x44,
0x69, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x57, 0x6f, 0x72, 0x6b,
0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0a, 0x53, 0x74, 0x6f,
0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52,
0x0a, 0x53, 0x74, 0x6f, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20,
0x0a, 0x0b, 0x41, 0x72, 0x67, 0x73, 0x45, 0x73, 0x63, 0x61, 0x70, 0x65, 0x64, 0x18, 0x0a, 0x20,
0x01, 0x28, 0x08, 0x52, 0x0b, 0x41, 0x72, 0x67, 0x73, 0x45, 0x73, 0x63, 0x61, 0x70, 0x65, 0x64,
0x1a, 0x55, 0x0a, 0x11, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x50, 0x0a, 0x0c, 0x56, 0x6f, 0x6c, 0x75, 0x6d,
0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76,
0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62,
0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x57, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67,
0x44, 0x69, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x53, 0x74, 0x6f, 0x70, 0x53, 0x69, 0x67, 0x6e,
0x61, 0x6c, 0x22, 0x36, 0x0a, 0x06, 0x52, 0x6f, 0x6f, 0x74, 0x46, 0x53, 0x12, 0x12, 0x0a, 0x04,
0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65,
0x12, 0x18, 0x0a, 0x07, 0x44, 0x69, 0x66, 0x66, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x09, 0x52, 0x07, 0x44, 0x69, 0x66, 0x66, 0x49, 0x44, 0x73, 0x22, 0x88, 0x02, 0x0a, 0x07, 0x48,
0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x39, 0x0a, 0x07, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x07, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x88, 0x01,
0x01, 0x12, 0x21, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42,
0x79, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x06, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x88, 0x01,
0x01, 0x12, 0x1d, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x48, 0x03, 0x52, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01,
0x12, 0x23, 0x0a, 0x0a, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05,
0x20, 0x01, 0x28, 0x08, 0x48, 0x04, 0x52, 0x0a, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4c, 0x61, 0x79,
0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x42,
0x09, 0x0a, 0x07, 0x5f, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x43,
0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x45, 0x6d, 0x70, 0x74, 0x79,
0x4c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x0e, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_oci_config_proto_rawDescOnce sync.Once
file_oci_config_proto_rawDescData = file_oci_config_proto_rawDesc
)
func file_oci_config_proto_rawDescGZIP() []byte {
file_oci_config_proto_rawDescOnce.Do(func() {
file_oci_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_oci_config_proto_rawDescData)
})
return file_oci_config_proto_rawDescData
}
var file_oci_config_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_oci_config_proto_goTypes = []interface{}{
(*Image)(nil), // 0: oci_v1.Image
(*ImageConfig)(nil), // 1: oci_v1.ImageConfig
(*RootFS)(nil), // 2: oci_v1.RootFS
(*History)(nil), // 3: oci_v1.History
(*EmptyMessage)(nil), // 4: oci_v1.EmptyMessage
nil, // 5: oci_v1.ImageConfig.ExposedPortsEntry
nil, // 6: oci_v1.ImageConfig.VolumesEntry
nil, // 7: oci_v1.ImageConfig.LabelsEntry
(*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp
(*Platform)(nil), // 9: oci_v1.Platform
}
var file_oci_config_proto_depIdxs = []int32{
8, // 0: oci_v1.Image.Created:type_name -> google.protobuf.Timestamp
9, // 1: oci_v1.Image.Platform:type_name -> oci_v1.Platform
1, // 2: oci_v1.Image.Config:type_name -> oci_v1.ImageConfig
2, // 3: oci_v1.Image.RootFS:type_name -> oci_v1.RootFS
3, // 4: oci_v1.Image.History:type_name -> oci_v1.History
5, // 5: oci_v1.ImageConfig.ExposedPorts:type_name -> oci_v1.ImageConfig.ExposedPortsEntry
6, // 6: oci_v1.ImageConfig.Volumes:type_name -> oci_v1.ImageConfig.VolumesEntry
7, // 7: oci_v1.ImageConfig.Labels:type_name -> oci_v1.ImageConfig.LabelsEntry
8, // 8: oci_v1.History.Created:type_name -> google.protobuf.Timestamp
4, // 9: oci_v1.ImageConfig.ExposedPortsEntry.value:type_name -> oci_v1.EmptyMessage
4, // 10: oci_v1.ImageConfig.VolumesEntry.value:type_name -> oci_v1.EmptyMessage
11, // [11:11] is the sub-list for method output_type
11, // [11:11] is the sub-list for method input_type
11, // [11:11] is the sub-list for extension type_name
11, // [11:11] is the sub-list for extension extendee
0, // [0:11] is the sub-list for field type_name
}
func init() { file_oci_config_proto_init() }
func file_oci_config_proto_init() {
if File_oci_config_proto != nil {
return
}
file_oci_descriptor_proto_init()
if !protoimpl.UnsafeEnabled {
file_oci_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Image); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_oci_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_oci_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RootFS); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_oci_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*History); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_oci_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EmptyMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_oci_config_proto_msgTypes[0].OneofWrappers = []interface{}{}
file_oci_config_proto_msgTypes[1].OneofWrappers = []interface{}{}
file_oci_config_proto_msgTypes[3].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_oci_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 8,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_oci_config_proto_goTypes,
DependencyIndexes: file_oci_config_proto_depIdxs,
MessageInfos: file_oci_config_proto_msgTypes,
}.Build()
File_oci_config_proto = out.File
file_oci_config_proto_rawDesc = nil
file_oci_config_proto_goTypes = nil
file_oci_config_proto_depIdxs = nil
}

View File

@ -0,0 +1,328 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc v4.24.4
// source: oci/descriptor.proto
package gen
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Descriptor struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MediaType string `protobuf:"bytes,1,opt,name=MediaType,proto3" json:"MediaType,omitempty"`
Digest string `protobuf:"bytes,2,opt,name=Digest,proto3" json:"Digest,omitempty"`
Size int64 `protobuf:"varint,3,opt,name=Size,proto3" json:"Size,omitempty"`
URLs []string `protobuf:"bytes,4,rep,name=URLs,proto3" json:"URLs,omitempty"`
Data []byte `protobuf:"bytes,5,opt,name=Data,proto3" json:"Data,omitempty"`
Platform *Platform `protobuf:"bytes,6,opt,name=Platform,proto3,oneof" json:"Platform,omitempty"`
ArtifactType *string `protobuf:"bytes,7,opt,name=ArtifactType,proto3,oneof" json:"ArtifactType,omitempty"`
Annotations map[string]string `protobuf:"bytes,8,rep,name=Annotations,proto3" json:"Annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *Descriptor) Reset() {
*x = Descriptor{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_descriptor_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Descriptor) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Descriptor) ProtoMessage() {}
func (x *Descriptor) ProtoReflect() protoreflect.Message {
mi := &file_oci_descriptor_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Descriptor.ProtoReflect.Descriptor instead.
func (*Descriptor) Descriptor() ([]byte, []int) {
return file_oci_descriptor_proto_rawDescGZIP(), []int{0}
}
func (x *Descriptor) GetMediaType() string {
if x != nil {
return x.MediaType
}
return ""
}
func (x *Descriptor) GetDigest() string {
if x != nil {
return x.Digest
}
return ""
}
func (x *Descriptor) GetSize() int64 {
if x != nil {
return x.Size
}
return 0
}
func (x *Descriptor) GetURLs() []string {
if x != nil {
return x.URLs
}
return nil
}
func (x *Descriptor) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
func (x *Descriptor) GetPlatform() *Platform {
if x != nil {
return x.Platform
}
return nil
}
func (x *Descriptor) GetArtifactType() string {
if x != nil && x.ArtifactType != nil {
return *x.ArtifactType
}
return ""
}
func (x *Descriptor) GetAnnotations() map[string]string {
if x != nil {
return x.Annotations
}
return nil
}
type Platform struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Architecture string `protobuf:"bytes,1,opt,name=Architecture,proto3" json:"Architecture,omitempty"`
OS string `protobuf:"bytes,2,opt,name=OS,proto3" json:"OS,omitempty"`
OSVersion *string `protobuf:"bytes,3,opt,name=OSVersion,proto3,oneof" json:"OSVersion,omitempty"`
OSFeatures []string `protobuf:"bytes,4,rep,name=OSFeatures,proto3" json:"OSFeatures,omitempty"`
Variant *string `protobuf:"bytes,5,opt,name=Variant,proto3,oneof" json:"Variant,omitempty"`
}
func (x *Platform) Reset() {
*x = Platform{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_descriptor_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Platform) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Platform) ProtoMessage() {}
func (x *Platform) ProtoReflect() protoreflect.Message {
mi := &file_oci_descriptor_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Platform.ProtoReflect.Descriptor instead.
func (*Platform) Descriptor() ([]byte, []int) {
return file_oci_descriptor_proto_rawDescGZIP(), []int{1}
}
func (x *Platform) GetArchitecture() string {
if x != nil {
return x.Architecture
}
return ""
}
func (x *Platform) GetOS() string {
if x != nil {
return x.OS
}
return ""
}
func (x *Platform) GetOSVersion() string {
if x != nil && x.OSVersion != nil {
return *x.OSVersion
}
return ""
}
func (x *Platform) GetOSFeatures() []string {
if x != nil {
return x.OSFeatures
}
return nil
}
func (x *Platform) GetVariant() string {
if x != nil && x.Variant != nil {
return *x.Variant
}
return ""
}
var File_oci_descriptor_proto protoreflect.FileDescriptor
var file_oci_descriptor_proto_rawDesc = []byte{
0x0a, 0x14, 0x6f, 0x63, 0x69, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x22, 0xff,
0x02, 0x0a, 0x0a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x0a,
0x09, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x44,
0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x69, 0x67,
0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x03, 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x52, 0x4c, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x55, 0x52, 0x4c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x44,
0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12,
0x31, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x10, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66,
0x6f, 0x72, 0x6d, 0x48, 0x00, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x88,
0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79,
0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0c, 0x41, 0x72, 0x74, 0x69,
0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x45, 0x0a, 0x0b, 0x41,
0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x23, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x6f, 0x72, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x42,
0x0f, 0x0a, 0x0d, 0x5f, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65,
0x22, 0xba, 0x01, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x22, 0x0a,
0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72,
0x65, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x53, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f,
0x53, 0x12, 0x21, 0x0a, 0x09, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x88, 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x0a, 0x4f, 0x53, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72,
0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x4f, 0x53, 0x46, 0x65, 0x61, 0x74,
0x75, 0x72, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x07, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x18,
0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x07, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74,
0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x4f, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_oci_descriptor_proto_rawDescOnce sync.Once
file_oci_descriptor_proto_rawDescData = file_oci_descriptor_proto_rawDesc
)
func file_oci_descriptor_proto_rawDescGZIP() []byte {
file_oci_descriptor_proto_rawDescOnce.Do(func() {
file_oci_descriptor_proto_rawDescData = protoimpl.X.CompressGZIP(file_oci_descriptor_proto_rawDescData)
})
return file_oci_descriptor_proto_rawDescData
}
var file_oci_descriptor_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_oci_descriptor_proto_goTypes = []interface{}{
(*Descriptor)(nil), // 0: oci_v1.Descriptor
(*Platform)(nil), // 1: oci_v1.Platform
nil, // 2: oci_v1.Descriptor.AnnotationsEntry
}
var file_oci_descriptor_proto_depIdxs = []int32{
1, // 0: oci_v1.Descriptor.Platform:type_name -> oci_v1.Platform
2, // 1: oci_v1.Descriptor.Annotations:type_name -> oci_v1.Descriptor.AnnotationsEntry
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_oci_descriptor_proto_init() }
func file_oci_descriptor_proto_init() {
if File_oci_descriptor_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_oci_descriptor_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Descriptor); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_oci_descriptor_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Platform); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_oci_descriptor_proto_msgTypes[0].OneofWrappers = []interface{}{}
file_oci_descriptor_proto_msgTypes[1].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_oci_descriptor_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_oci_descriptor_proto_goTypes,
DependencyIndexes: file_oci_descriptor_proto_depIdxs,
MessageInfos: file_oci_descriptor_proto_msgTypes,
}.Build()
File_oci_descriptor_proto = out.File
file_oci_descriptor_proto_rawDesc = nil
file_oci_descriptor_proto_goTypes = nil
file_oci_descriptor_proto_depIdxs = nil
}

View File

@ -0,0 +1,217 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc v4.24.4
// source: oci/index.proto
package gen
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Index struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Versioned *Versioned `protobuf:"bytes,1,opt,name=Versioned,proto3" json:"Versioned,omitempty"`
MediaType *string `protobuf:"bytes,2,opt,name=MediaType,proto3,oneof" json:"MediaType,omitempty"`
ArtifactType *string `protobuf:"bytes,3,opt,name=ArtifactType,proto3,oneof" json:"ArtifactType,omitempty"`
Manifests []*Descriptor `protobuf:"bytes,4,rep,name=Manifests,proto3" json:"Manifests,omitempty"`
Subject *Descriptor `protobuf:"bytes,5,opt,name=Subject,proto3,oneof" json:"Subject,omitempty"`
Annotations map[string]string `protobuf:"bytes,6,rep,name=Annotations,proto3" json:"Annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *Index) Reset() {
*x = Index{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_index_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Index) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Index) ProtoMessage() {}
func (x *Index) ProtoReflect() protoreflect.Message {
mi := &file_oci_index_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Index.ProtoReflect.Descriptor instead.
func (*Index) Descriptor() ([]byte, []int) {
return file_oci_index_proto_rawDescGZIP(), []int{0}
}
func (x *Index) GetVersioned() *Versioned {
if x != nil {
return x.Versioned
}
return nil
}
func (x *Index) GetMediaType() string {
if x != nil && x.MediaType != nil {
return *x.MediaType
}
return ""
}
func (x *Index) GetArtifactType() string {
if x != nil && x.ArtifactType != nil {
return *x.ArtifactType
}
return ""
}
func (x *Index) GetManifests() []*Descriptor {
if x != nil {
return x.Manifests
}
return nil
}
func (x *Index) GetSubject() *Descriptor {
if x != nil {
return x.Subject
}
return nil
}
func (x *Index) GetAnnotations() map[string]string {
if x != nil {
return x.Annotations
}
return nil
}
var File_oci_index_proto protoreflect.FileDescriptor
var file_oci_index_proto_rawDesc = []byte{
0x0a, 0x0f, 0x6f, 0x63, 0x69, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x06, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x1a, 0x14, 0x6f, 0x63, 0x69, 0x2f, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
0x13, 0x6f, 0x63, 0x69, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96, 0x03, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2f,
0x0a, 0x09, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x65, 0x64, 0x52, 0x09, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x12,
0x21, 0x0a, 0x09, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x88,
0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79,
0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0c, 0x41, 0x72, 0x74, 0x69,
0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x09, 0x4d,
0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12,
0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x6f, 0x72, 0x52, 0x09, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x12, 0x31, 0x0a,
0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12,
0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x6f, 0x72, 0x48, 0x02, 0x52, 0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01,
0x12, 0x40, 0x0a, 0x0b, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x49,
0x6e, 0x64, 0x65, 0x78, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65,
0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70,
0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_oci_index_proto_rawDescOnce sync.Once
file_oci_index_proto_rawDescData = file_oci_index_proto_rawDesc
)
func file_oci_index_proto_rawDescGZIP() []byte {
file_oci_index_proto_rawDescOnce.Do(func() {
file_oci_index_proto_rawDescData = protoimpl.X.CompressGZIP(file_oci_index_proto_rawDescData)
})
return file_oci_index_proto_rawDescData
}
var file_oci_index_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_oci_index_proto_goTypes = []interface{}{
(*Index)(nil), // 0: oci_v1.Index
nil, // 1: oci_v1.Index.AnnotationsEntry
(*Versioned)(nil), // 2: oci_v1.Versioned
(*Descriptor)(nil), // 3: oci_v1.Descriptor
}
var file_oci_index_proto_depIdxs = []int32{
2, // 0: oci_v1.Index.Versioned:type_name -> oci_v1.Versioned
3, // 1: oci_v1.Index.Manifests:type_name -> oci_v1.Descriptor
3, // 2: oci_v1.Index.Subject:type_name -> oci_v1.Descriptor
1, // 3: oci_v1.Index.Annotations:type_name -> oci_v1.Index.AnnotationsEntry
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_oci_index_proto_init() }
func file_oci_index_proto_init() {
if File_oci_index_proto != nil {
return
}
file_oci_descriptor_proto_init()
file_oci_versioned_proto_init()
if !protoimpl.UnsafeEnabled {
file_oci_index_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Index); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_oci_index_proto_msgTypes[0].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_oci_index_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_oci_index_proto_goTypes,
DependencyIndexes: file_oci_index_proto_depIdxs,
MessageInfos: file_oci_index_proto_msgTypes,
}.Build()
File_oci_index_proto = out.File
file_oci_index_proto_rawDesc = nil
file_oci_index_proto_goTypes = nil
file_oci_index_proto_depIdxs = nil
}

View File

@ -0,0 +1,229 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc v4.24.4
// source: oci/manifest.proto
package gen
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Manifest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Versioned *Versioned `protobuf:"bytes,1,opt,name=Versioned,proto3" json:"Versioned,omitempty"`
MediaType *string `protobuf:"bytes,2,opt,name=MediaType,proto3,oneof" json:"MediaType,omitempty"`
ArtifactType *string `protobuf:"bytes,3,opt,name=ArtifactType,proto3,oneof" json:"ArtifactType,omitempty"`
Config *Descriptor `protobuf:"bytes,4,opt,name=Config,proto3" json:"Config,omitempty"`
Layers []*Descriptor `protobuf:"bytes,5,rep,name=Layers,proto3" json:"Layers,omitempty"`
Subject *Descriptor `protobuf:"bytes,6,opt,name=Subject,proto3,oneof" json:"Subject,omitempty"`
Annotations map[string]string `protobuf:"bytes,7,rep,name=Annotations,proto3" json:"Annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *Manifest) Reset() {
*x = Manifest{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_manifest_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Manifest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Manifest) ProtoMessage() {}
func (x *Manifest) ProtoReflect() protoreflect.Message {
mi := &file_oci_manifest_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Manifest.ProtoReflect.Descriptor instead.
func (*Manifest) Descriptor() ([]byte, []int) {
return file_oci_manifest_proto_rawDescGZIP(), []int{0}
}
func (x *Manifest) GetVersioned() *Versioned {
if x != nil {
return x.Versioned
}
return nil
}
func (x *Manifest) GetMediaType() string {
if x != nil && x.MediaType != nil {
return *x.MediaType
}
return ""
}
func (x *Manifest) GetArtifactType() string {
if x != nil && x.ArtifactType != nil {
return *x.ArtifactType
}
return ""
}
func (x *Manifest) GetConfig() *Descriptor {
if x != nil {
return x.Config
}
return nil
}
func (x *Manifest) GetLayers() []*Descriptor {
if x != nil {
return x.Layers
}
return nil
}
func (x *Manifest) GetSubject() *Descriptor {
if x != nil {
return x.Subject
}
return nil
}
func (x *Manifest) GetAnnotations() map[string]string {
if x != nil {
return x.Annotations
}
return nil
}
var File_oci_manifest_proto protoreflect.FileDescriptor
var file_oci_manifest_proto_rawDesc = []byte{
0x0a, 0x12, 0x6f, 0x63, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x1a, 0x14, 0x6f, 0x63,
0x69, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x13, 0x6f, 0x63, 0x69, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65,
0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc2, 0x03, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69,
0x66, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x09, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31,
0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x09, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x09, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79,
0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x4d, 0x65, 0x64, 0x69,
0x61, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x41, 0x72, 0x74, 0x69,
0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01,
0x52, 0x0c, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x88, 0x01,
0x01, 0x12, 0x2a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x12, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2a, 0x0a,
0x06, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e,
0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f,
0x72, 0x52, 0x06, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x31, 0x0a, 0x07, 0x53, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6f, 0x63, 0x69,
0x5f, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x48, 0x02,
0x52, 0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01, 0x12, 0x43, 0x0a, 0x0b,
0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x21, 0x2e, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66,
0x65, 0x73, 0x74, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x42,
0x0f, 0x0a, 0x0d, 0x5f, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65,
0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_oci_manifest_proto_rawDescOnce sync.Once
file_oci_manifest_proto_rawDescData = file_oci_manifest_proto_rawDesc
)
func file_oci_manifest_proto_rawDescGZIP() []byte {
file_oci_manifest_proto_rawDescOnce.Do(func() {
file_oci_manifest_proto_rawDescData = protoimpl.X.CompressGZIP(file_oci_manifest_proto_rawDescData)
})
return file_oci_manifest_proto_rawDescData
}
var file_oci_manifest_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_oci_manifest_proto_goTypes = []interface{}{
(*Manifest)(nil), // 0: oci_v1.Manifest
nil, // 1: oci_v1.Manifest.AnnotationsEntry
(*Versioned)(nil), // 2: oci_v1.Versioned
(*Descriptor)(nil), // 3: oci_v1.Descriptor
}
var file_oci_manifest_proto_depIdxs = []int32{
2, // 0: oci_v1.Manifest.Versioned:type_name -> oci_v1.Versioned
3, // 1: oci_v1.Manifest.Config:type_name -> oci_v1.Descriptor
3, // 2: oci_v1.Manifest.Layers:type_name -> oci_v1.Descriptor
3, // 3: oci_v1.Manifest.Subject:type_name -> oci_v1.Descriptor
1, // 4: oci_v1.Manifest.Annotations:type_name -> oci_v1.Manifest.AnnotationsEntry
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_oci_manifest_proto_init() }
func file_oci_manifest_proto_init() {
if File_oci_manifest_proto != nil {
return
}
file_oci_descriptor_proto_init()
file_oci_versioned_proto_init()
if !protoimpl.UnsafeEnabled {
file_oci_manifest_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Manifest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_oci_manifest_proto_msgTypes[0].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_oci_manifest_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_oci_manifest_proto_goTypes,
DependencyIndexes: file_oci_manifest_proto_depIdxs,
MessageInfos: file_oci_manifest_proto_msgTypes,
}.Build()
File_oci_manifest_proto = out.File
file_oci_manifest_proto_rawDesc = nil
file_oci_manifest_proto_goTypes = nil
file_oci_manifest_proto_depIdxs = nil
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,142 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.31.0
// protoc v4.24.4
// source: oci/versioned.proto
package gen
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Versioned struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
SchemaVersion int32 `protobuf:"varint,1,opt,name=SchemaVersion,proto3" json:"SchemaVersion,omitempty"`
}
func (x *Versioned) Reset() {
*x = Versioned{}
if protoimpl.UnsafeEnabled {
mi := &file_oci_versioned_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Versioned) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Versioned) ProtoMessage() {}
func (x *Versioned) ProtoReflect() protoreflect.Message {
mi := &file_oci_versioned_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Versioned.ProtoReflect.Descriptor instead.
func (*Versioned) Descriptor() ([]byte, []int) {
return file_oci_versioned_proto_rawDescGZIP(), []int{0}
}
func (x *Versioned) GetSchemaVersion() int32 {
if x != nil {
return x.SchemaVersion
}
return 0
}
var File_oci_versioned_proto protoreflect.FileDescriptor
var file_oci_versioned_proto_rawDesc = []byte{
0x0a, 0x13, 0x6f, 0x63, 0x69, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x6f, 0x63, 0x69, 0x5f, 0x76, 0x31, 0x22, 0x31, 0x0a,
0x09, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x53, 0x63,
0x68, 0x65, 0x6d, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
0x05, 0x52, 0x0d, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_oci_versioned_proto_rawDescOnce sync.Once
file_oci_versioned_proto_rawDescData = file_oci_versioned_proto_rawDesc
)
func file_oci_versioned_proto_rawDescGZIP() []byte {
file_oci_versioned_proto_rawDescOnce.Do(func() {
file_oci_versioned_proto_rawDescData = protoimpl.X.CompressGZIP(file_oci_versioned_proto_rawDescData)
})
return file_oci_versioned_proto_rawDescData
}
var file_oci_versioned_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_oci_versioned_proto_goTypes = []interface{}{
(*Versioned)(nil), // 0: oci_v1.Versioned
}
var file_oci_versioned_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_oci_versioned_proto_init() }
func file_oci_versioned_proto_init() {
if File_oci_versioned_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_oci_versioned_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Versioned); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_oci_versioned_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_oci_versioned_proto_goTypes,
DependencyIndexes: file_oci_versioned_proto_depIdxs,
MessageInfos: file_oci_versioned_proto_msgTypes,
}.Build()
File_oci_versioned_proto = out.File
file_oci_versioned_proto_rawDesc = nil
file_oci_versioned_proto_goTypes = nil
file_oci_versioned_proto_depIdxs = nil
}

View File

@ -0,0 +1,115 @@
syntax = "proto3";
package meta_v1;
import "oci/config.proto";
import "oci/manifest.proto";
import "oci/index.proto";
import "oci/timestamp.proto";
import "oci/descriptor.proto";
message TagDescriptor {
string MediaType = 1;
string Digest = 2;
}
message ImageMeta {
string MediaType = 1;
repeated ManifestMeta Manifests = 2;
optional IndexMeta Index = 3;
}
message ManifestMeta {
string Digest = 1;
int64 Size = 2;
oci_v1.Manifest Manifest = 3;
oci_v1.Image Config = 4;
}
message IndexMeta {
string Digest = 1;
int64 Size = 2;
oci_v1.Index Index = 3;
}
message RepoLastUpdatedImage {
optional google.protobuf.Timestamp LastUpdated = 1;
string MediaType = 2;
string Digest = 3;
string Tag = 4;
}
message RepoMeta {
string Name = 1;
map<string, TagDescriptor> Tags = 2;
map<string, DescriptorStatistics> Statistics = 3;
map<string, ManifestSignatures> Signatures = 4;
map<string, ReferrersInfo> Referrers = 5;
bool IsStarred = 6;
bool IsBookmarked = 7;
int32 Rank = 8;
int32 Stars = 9;
int32 Size = 10;
repeated string Vendors = 11;
repeated oci_v1.Platform Platforms = 12;
optional RepoLastUpdatedImage LastUpdatedImage = 13;
}
message RepoBlobs {
string Name = 1;
map<string, BlobInfo> Blobs = 2;
}
// for example this is a manifest and it has a config, and layers
// or index and has manifests
message BlobInfo {
int64 Size = 1;
repeated string Vendors = 2;
repeated string SubBlobs = 3;
repeated oci_v1.Platform Platforms = 4;
optional google.protobuf.Timestamp LastUpdated = 5;
}
message DescriptorStatistics {
int32 DownloadCount = 1;
}
message ReferrersInfo {
repeated ReferrerInfo list = 1;
}
message ReferrerInfo {
string Digest = 1;
int64 Count = 2;
string MediaType = 3;
string ArtifactType = 4;
int64 Size = 5;
map<string, string> Annotations = 6;
}
message ManifestSignatures {
map<string, SignaturesInfo> map = 1;
}
message SignaturesInfo {
repeated SignatureInfo list = 1;
}
message SignatureInfo {
string SignatureManifestDigest = 1;
repeated LayersInfo LayersInfo = 2;
}
message LayersInfo {
string LayerDigest = 1;
bytes LayerContent = 2;
string SignatureKey = 3;
string Signer = 4;
google.protobuf.Timestamp Date = 5;
}

View File

@ -0,0 +1,45 @@
syntax = "proto3";
package oci_v1;
import "oci/timestamp.proto";
import "oci/descriptor.proto";
// https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/config.go
message Image {
optional google.protobuf.Timestamp Created = 1;
optional string Author = 2;
Platform Platform = 3;
optional ImageConfig Config = 4;
optional RootFS RootFS = 5;
repeated History History = 6;
}
message ImageConfig {
map <string,EmptyMessage> ExposedPorts = 1;
map <string,EmptyMessage> Volumes = 2;
map <string,string> Labels = 3;
string User = 4;
repeated string Env = 5;
repeated string Entrypoint = 6;
repeated string Cmd = 7;
optional string WorkingDir = 8;
optional string StopSignal = 9;
bool ArgsEscaped = 10;
}
message RootFS {
string Type = 1;
repeated string DiffIDs = 2;
}
message History {
optional google.protobuf.Timestamp Created = 1;
optional string CreatedBy = 2;
optional string Author = 3;
optional string Comment = 4;
optional bool EmptyLayer = 5;
}
message EmptyMessage{}

View File

@ -0,0 +1,23 @@
syntax = "proto3";
package oci_v1;
// https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/descriptor.go
message Descriptor {
string MediaType = 1;
string Digest = 2;
int64 Size = 3;
repeated string URLs = 4;
bytes Data = 5;
optional Platform Platform = 6;
optional string ArtifactType = 7;
map <string,string> Annotations = 8;
}
message Platform {
string Architecture = 1;
string OS = 2;
optional string OSVersion = 3;
repeated string OSFeatures = 4;
optional string Variant = 5;
}

View File

@ -0,0 +1,16 @@
syntax = "proto3";
package oci_v1;
import "oci/descriptor.proto";
import "oci/versioned.proto";
// https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/index.go
message Index {
Versioned Versioned = 1;
optional string MediaType = 2;
optional string ArtifactType = 3;
repeated Descriptor Manifests = 4;
optional Descriptor Subject = 5;
map<string,string> Annotations = 6;
}

View File

@ -0,0 +1,17 @@
syntax = "proto3";
package oci_v1;
import "oci/descriptor.proto";
import "oci/versioned.proto";
// https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/manifest.go
message Manifest {
Versioned Versioned = 1;
optional string MediaType = 2;
optional string ArtifactType = 3;
Descriptor Config = 4;
repeated Descriptor Layers = 5;
optional Descriptor Subject = 6;
map<string,string> Annotations = 7;
}

View File

@ -0,0 +1,144 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option cc_enable_arenas = true;
option go_package = "google.golang.org/protobuf/types/known/timestamppb";
option java_package = "com.google.protobuf";
option java_outer_classname = "TimestampProto";
option java_multiple_files = true;
option objc_class_prefix = "GPB";
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
// A Timestamp represents a point in time independent of any time zone or local
// calendar, encoded as a count of seconds and fractions of seconds at
// nanosecond resolution. The count is relative to an epoch at UTC midnight on
// January 1, 1970, in the proleptic Gregorian calendar which extends the
// Gregorian calendar backwards to year one.
//
// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
// second table is needed for interpretation, using a [24-hour linear
// smear](https://developers.google.com/time/smear).
//
// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
// restricting to that range, we ensure that we can convert to and from [RFC
// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
//
// # Examples
//
// Example 1: Compute Timestamp from POSIX `time()`.
//
// Timestamp timestamp;
// timestamp.set_seconds(time(NULL));
// timestamp.set_nanos(0);
//
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
//
// struct timeval tv;
// gettimeofday(&tv, NULL);
//
// Timestamp timestamp;
// timestamp.set_seconds(tv.tv_sec);
// timestamp.set_nanos(tv.tv_usec * 1000);
//
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
//
// FILETIME ft;
// GetSystemTimeAsFileTime(&ft);
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
//
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
// Timestamp timestamp;
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
//
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
//
// long millis = System.currentTimeMillis();
//
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
// .setNanos((int) ((millis % 1000) * 1000000)).build();
//
// Example 5: Compute Timestamp from Java `Instant.now()`.
//
// Instant now = Instant.now();
//
// Timestamp timestamp =
// Timestamp.newBuilder().setSeconds(now.getEpochSecond())
// .setNanos(now.getNano()).build();
//
// Example 6: Compute Timestamp from current time in Python.
//
// timestamp = Timestamp()
// timestamp.GetCurrentTime()
//
// # JSON Mapping
//
// In JSON format, the Timestamp type is encoded as a string in the
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
// where {year} is always expressed using four digits while {month}, {day},
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
// is required. A proto3 JSON serializer should always use UTC (as indicated by
// "Z") when printing the Timestamp type and a proto3 JSON parser should be
// able to accept both UTC and other timezones (as indicated by an offset).
//
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
// 01:30 UTC on January 15, 2017.
//
// In JavaScript, one can convert a Date object to this format using the
// standard
// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
// method. In Python, a standard `datetime.datetime` object can be converted
// to this format using
// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
// the Joda Time's [`ISODateTimeFormat.dateTime()`](
// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()
// ) to obtain a formatter capable of generating timestamps in this format.
//
message Timestamp {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
int64 seconds = 1;
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
int32 nanos = 2;
}

View File

@ -0,0 +1,8 @@
syntax = "proto3";
package oci_v1;
// https://github.com/opencontainers/image-spec/blob/main/specs-go/versioned.go
message Versioned {
int32 SchemaVersion = 1;
}

View File

@ -5,18 +5,9 @@ import (
"time" "time"
godigest "github.com/opencontainers/go-digest" godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
) )
// DetailedRepoMeta is a auxiliary structure used for sorting RepoMeta arrays by information
// that's not directly available in the RepoMetadata structure (ex. that needs to be calculated
// by iterating the manifests, etc.)
type DetailedRepoMeta struct {
RepoMetadata
Rank int
Downloads int
UpdateTime time.Time
}
// Used to model changes to an object after a call to the DB. // Used to model changes to an object after a call to the DB.
type ToggleState int type ToggleState int
@ -27,23 +18,109 @@ const (
) )
type ( type (
FilterFunc func(repoMeta RepoMetadata, manifestMeta ManifestMetadata) bool // Currently imageMeta applied for indexes is applied for each manifest individually so imageMeta.manifests
FilterRepoFunc func(repoMeta RepoMetadata) bool // contains just 1 manifest.
FilterFunc func(repoMeta RepoMeta, imageMeta ImageMeta) bool
FilterRepoNameFunc func(repo string) bool
FilterFullRepoFunc func(repoMeta RepoMeta) bool
FilterRepoTagFunc func(repo, tag string) bool
)
func AcceptAllRepoNames(repo string) bool {
return true
}
func AcceptAllRepoMeta(repoMeta RepoMeta) bool {
return true
}
func AcceptAllRepoTag(repo, tag string) bool {
return true
}
func AcceptAllImageMeta(repoMeta RepoMeta, imageMeta ImageMeta) bool {
return true
}
func GetLatestImageDigests(repoMetaList []RepoMeta) []string {
digests := make([]string, 0, len(repoMetaList))
for i := range repoMetaList {
if repoMetaList[i].LastUpdatedImage != nil {
digests = append(digests, repoMetaList[i].LastUpdatedImage.Digest)
}
}
return digests
}
type (
ImageDigest = string
) )
type MetaDB interface { //nolint:interfacebloat type MetaDB interface { //nolint:interfacebloat
UserDB UserDB
SetImageMeta(digest godigest.Digest, imageMeta ImageMeta) error
// SetRepoReference sets the given image data to the repo metadata.
SetRepoReference(repo string, reference string, imageMeta ImageMeta) error
// SearchRepos searches for repos given a search string
SearchRepos(ctx context.Context, searchText string) ([]RepoMeta, error)
// SearchTags searches for images(repo:tag) given a search string
SearchTags(ctx context.Context, searchText string) ([]FullImageMeta, error)
// FilterTags filters for images given a filter function
FilterTags(ctx context.Context, filterRepoTag FilterRepoTagFunc, filterFunc FilterFunc,
) ([]FullImageMeta, error)
// FilterRepos filters for repos given a filter function
FilterRepos(ctx context.Context, rankName FilterRepoNameFunc, filterFunc FilterFullRepoFunc,
) ([]RepoMeta, error)
// GetRepoMeta returns the full information about a repo
GetRepoMeta(ctx context.Context, repo string) (RepoMeta, error)
// GetFullImageMeta returns the full information about an image
GetFullImageMeta(ctx context.Context, repo string, tag string) (FullImageMeta, error)
// GetImageMeta returns the raw information about an image
GetImageMeta(digest godigest.Digest) (ImageMeta, error)
// GetMultipleRepoMeta returns information about all repositories as map[string]RepoMetadata filtered by the filter
// function
GetMultipleRepoMeta(ctx context.Context, filter func(repoMeta RepoMeta) bool) (
[]RepoMeta, error)
// AddManifestSignature adds signature metadata to a given manifest in the database
AddManifestSignature(repo string, signedManifestDigest godigest.Digest, sm SignatureMetadata) error
// DeleteSignature deletes signature metadata to a given manifest from the database
DeleteSignature(repo string, signedManifestDigest godigest.Digest, sigMeta SignatureMetadata) error
// UpdateSignaturesValidity checks and updates signatures validity of a given manifest
UpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error
// IncrementRepoStars adds 1 to the star count of an image // IncrementRepoStars adds 1 to the star count of an image
IncrementRepoStars(repo string) error IncrementRepoStars(repo string) error
// IncrementRepoStars subtracts 1 from the star count of an image // DecrementRepoStars subtracts 1 from the star count of an image
DecrementRepoStars(repo string) error DecrementRepoStars(repo string) error
// GetRepoStars returns the total number of stars a repo has // SetRepoMeta returns RepoMetadata of a repo from the database
GetRepoStars(repo string) (int, error) SetRepoMeta(repo string, repoMeta RepoMeta) error
// SetRepoReference sets the reference of a manifest in the tag list of a repo // GetReferrersInfo returns a list of for all referrers of the given digest that match one of the
SetRepoReference(repo string, reference string, manifestDigest godigest.Digest, mediaType string) error // artifact types.
GetReferrersInfo(repo string, referredDigest godigest.Digest, artifactTypes []string) ([]ReferrerInfo, error)
// IncrementImageDownloads adds 1 to the download count of an image
IncrementImageDownloads(repo string, reference string) error
// FilterImageMeta returns the image data for the given digests
FilterImageMeta(ctx context.Context, digests []string) (map[string]ImageMeta, error)
/* /*
RemoveRepoReference removes the tag from RepoMetadata if the reference is a tag, RemoveRepoReference removes the tag from RepoMetadata if the reference is a tag,
@ -55,80 +132,12 @@ type MetaDB interface { //nolint:interfacebloat
*/ */
RemoveRepoReference(repo, reference string, manifestDigest godigest.Digest) error RemoveRepoReference(repo, reference string, manifestDigest godigest.Digest) error
// DeleteRepoTag delets the tag from the tag list of a repo // ResetRepoReferences resets all layout specific data (tags, signatures, referrers, etc.) but keep user and image
DeleteRepoTag(repo string, tag string) error // specific metadata such as star count, downloads other statistics
ResetRepoReferences(repo string) error
// GetRepoMeta returns RepoMetadata of a repo from the database // ResetDB will delete all data in the DB
GetRepoMeta(repo string) (RepoMetadata, error) ResetDB() error
// GetUserRepometa return RepoMetadata of a repo from the database along side specific information about the
// user
GetUserRepoMeta(ctx context.Context, repo string) (RepoMetadata, error)
// GetRepoMeta returns RepoMetadata of a repo from the database
SetRepoMeta(repo string, repoMeta RepoMetadata) error
// GetMultipleRepoMeta returns information about all repositories as map[string]RepoMetadata filtered by the filter
// function
GetMultipleRepoMeta(ctx context.Context, filter func(repoMeta RepoMetadata) bool) (
[]RepoMetadata, error)
// SetManifestData sets ManifestData for a given manifest in the database
SetManifestData(manifestDigest godigest.Digest, md ManifestData) error
// GetManifestData return the manifest and its related config
GetManifestData(manifestDigest godigest.Digest) (ManifestData, error)
// GetManifestMeta returns ManifestMetadata for a given manifest from the database
GetManifestMeta(repo string, manifestDigest godigest.Digest) (ManifestMetadata, error)
// GetManifestMeta sets ManifestMetadata for a given manifest in the database
SetManifestMeta(repo string, manifestDigest godigest.Digest, mm ManifestMetadata) error
// SetIndexData sets indexData for a given index in the database
SetIndexData(digest godigest.Digest, indexData IndexData) error
// GetIndexData returns indexData for a given Index from the database
GetIndexData(indexDigest godigest.Digest) (IndexData, error)
// SetReferrer adds a referrer to the referrers list of a manifest inside a repo
SetReferrer(repo string, referredDigest godigest.Digest, referrer ReferrerInfo) error
// SetReferrer delets a referrer to the referrers list of a manifest inside a repo
DeleteReferrer(repo string, referredDigest godigest.Digest, referrerDigest godigest.Digest) error
// GetReferrersInfo returnes a list of for all referrers of the given digest that match one of the
// artifact types.
GetReferrersInfo(repo string, referredDigest godigest.Digest, artifactTypes []string) (
[]ReferrerInfo, error)
// IncrementManifestDownloads adds 1 to the download count of a manifest
IncrementImageDownloads(repo string, reference string) error
// AddManifestSignature adds signature metadata to a given manifest in the database
AddManifestSignature(repo string, signedManifestDigest godigest.Digest, sm SignatureMetadata) error
// DeleteSignature delets signature metadata to a given manifest from the database
DeleteSignature(repo string, signedManifestDigest godigest.Digest, sm SignatureMetadata) error
// UpdateSignaturesValidity checks and updates signatures validity of a given manifest
UpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error
// SearchRepos searches for repos given a search string
SearchRepos(ctx context.Context, searchText string) (
[]RepoMetadata, map[string]ManifestMetadata, map[string]IndexData, error)
// SearchTags searches for images(repo:tag) given a search string
SearchTags(ctx context.Context, searchText string) (
[]RepoMetadata, map[string]ManifestMetadata, map[string]IndexData, error)
// FilterRepos filters for repos given a filter function
FilterRepos(ctx context.Context, filter FilterRepoFunc) (
[]RepoMetadata, map[string]ManifestMetadata, map[string]IndexData, error)
// FilterTags filters for images given a filter function
FilterTags(ctx context.Context, filterFunc FilterFunc) (
[]RepoMetadata, map[string]ManifestMetadata, map[string]IndexData, error)
PatchDB() error PatchDB() error
@ -176,25 +185,78 @@ type UserDB interface { //nolint:interfacebloat
type ImageTrustStore interface { type ImageTrustStore interface {
VerifySignature( VerifySignature(
signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, manifestContent []byte, signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, imageMeta ImageMeta,
repo string, repo string,
) (string, time.Time, bool, error) ) (string, time.Time, bool, error)
} }
type ManifestMetadata struct { // ImageMeta can store all data related to a image, multiarch or simple. Used for writing imaged to MetaDB.
ManifestBlob []byte type ImageMeta struct {
ConfigBlob []byte MediaType string // MediaType refers to the image descriptor, a manifest or a index (if multiarch)
Digest godigest.Digest // Digest refers to the image descriptor, a manifest or a index (if multiarch)
Size int64 // Size refers to the image descriptor, a manifest or a index (if multiarch)
Index *ispec.Index // If the image is multiarch the Index will be non-nil
Manifests []ManifestData // All manifests under the image, 1 for simple images and many for multiarch
}
// ManifestData represents all data related to an image manifests (found from the image contents itself).
type ManifestData struct {
Size int64
Digest godigest.Digest
Manifest ispec.Manifest
Config ispec.Image
}
type RepoMeta struct {
Name string
Tags map[string]Descriptor
Statistics map[string]DescriptorStatistics
Signatures map[string]ManifestSignatures
Referrers map[string][]ReferrerInfo
LastUpdatedImage *LastUpdatedImage
Platforms []ispec.Platform
Vendors []string
Size int64
IsStarred bool
IsBookmarked bool
Rank int
StarCount int
DownloadCount int DownloadCount int
}
// FullImageMeta is a condensed structure of all information needed about an image when searching MetaDB.
type FullImageMeta struct {
Repo string
Tag string
MediaType string
Digest godigest.Digest
Size int64
Index *ispec.Index
Manifests []FullManifestMeta
IsStarred bool
IsBookmarked bool
Referrers []ReferrerInfo
Statistics DescriptorStatistics
Signatures ManifestSignatures Signatures ManifestSignatures
} }
type IndexData struct { type FullManifestMeta struct {
IndexBlob []byte ManifestData
Referrers []ReferrerInfo
Statistics DescriptorStatistics
Signatures ManifestSignatures
} }
type ManifestData struct { type LastUpdatedImage struct {
ManifestBlob []byte Descriptor
ConfigBlob []byte Tag string
LastUpdated *time.Time
} }
type ReferrerInfo struct { type ReferrerInfo struct {
@ -217,21 +279,6 @@ type DescriptorStatistics struct {
type ManifestSignatures map[string][]SignatureInfo type ManifestSignatures map[string][]SignatureInfo
type RepoMetadata struct {
Name string
Tags map[string]Descriptor
Statistics map[string]DescriptorStatistics
Signatures map[string]ManifestSignatures
Referrers map[string][]ReferrerInfo
IsStarred bool
IsBookmarked bool
Rank int
Stars int
}
type LayerInfo struct { type LayerInfo struct {
LayerDigest string LayerDigest string
LayerContent []byte LayerContent []byte

View File

@ -127,8 +127,8 @@ func TestVersioningDynamoDB(t *testing.T) {
Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"), Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"),
Region: "us-east-2", Region: "us-east-2",
RepoMetaTablename: "RepoMetadataTable" + uuid.String(), RepoMetaTablename: "RepoMetadataTable" + uuid.String(),
ManifestDataTablename: "ManifestDataTable" + uuid.String(), RepoBlobsInfoTablename: "RepoBlobsInfoTablename" + uuid.String(),
IndexDataTablename: "IndexDataTable" + uuid.String(), ImageMetaTablename: "ImageMetaTablename" + uuid.String(),
UserDataTablename: "UserDataTable" + uuid.String(), UserDataTablename: "UserDataTable" + uuid.String(),
APIKeyTablename: "ApiKeyTable" + uuid.String(), APIKeyTablename: "ApiKeyTable" + uuid.String(),
VersionTablename: "Version" + uuid.String(), VersionTablename: "Version" + uuid.String(),
@ -142,8 +142,7 @@ func TestVersioningDynamoDB(t *testing.T) {
dynamoWrapper, err := mdynamodb.New(dynamoClient, params, log) dynamoWrapper, err := mdynamodb.New(dynamoClient, params, log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(dynamoWrapper.ResetManifestDataTable(), ShouldBeNil) So(dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename), ShouldBeNil)
So(dynamoWrapper.ResetRepoMetaTable(), ShouldBeNil)
Convey("dbVersion is empty", func() { Convey("dbVersion is empty", func() {
err := setDynamoDBVersion(dynamoWrapper.Client, params.VersionTablename, "") err := setDynamoDBVersion(dynamoWrapper.Client, params.VersionTablename, "")
@ -201,7 +200,7 @@ func setDynamoDBVersion(client *dynamodb.Client, versTable, vers string) error {
":Version": mdAttributeValue, ":Version": mdAttributeValue,
}, },
Key: map[string]types.AttributeValue{ Key: map[string]types.AttributeValue{
"VersionKey": &types.AttributeValueMemberS{ "Key": &types.AttributeValueMemberS{
Value: version.DBVersionKey, Value: version.DBVersionKey,
}, },
}, },

View File

@ -3,7 +3,6 @@ package storage
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"regexp"
"strings" "strings"
"github.com/docker/distribution/registry/storage/driver/factory" "github.com/docker/distribution/registry/storage/driver/factory"
@ -228,10 +227,7 @@ func CheckIsImageSignature(repoName string, manifestBlob []byte, reference strin
return true, NotationType, manifestContent.Subject.Digest, nil return true, NotationType, manifestContent.Subject.Digest, nil
} }
// check cosign if tag := reference; zcommon.IsCosignTag(reference) {
cosignTagRule := regexp.MustCompile(`sha256\-.+\.sig`)
if tag := reference; cosignTagRule.MatchString(reference) {
prefixLen := len("sha256-") prefixLen := len("sha256-")
digestLen := 64 digestLen := 64
signedImageManifestDigestEncoded := tag[prefixLen : prefixLen+digestLen] signedImageManifestDigestEncoded := tag[prefixLen : prefixLen+digestLen]

View File

@ -211,3 +211,35 @@ func GenerateRandomName() (string, int64) {
return string(randomBytes), seed return string(randomBytes), seed
} }
func AccumulateField[R any, T any](list []T, accFunc func(T) R) []R {
result := make([]R, 0, len(list))
for i := range list {
result = append(result, accFunc(list[i]))
}
return result
}
func ContainSameElements[T comparable](list1, list2 []T) bool {
if len(list1) != len(list2) {
return false
}
count1 := map[T]int{}
count2 := map[T]int{}
for i := range list1 {
count1[list1[i]]++
count2[list2[i]]++
}
for key := range count1 {
if count1[key] != count2[key] {
return false
}
}
return true
}

View File

@ -387,7 +387,7 @@ func GetRandomMultiarchImage(reference string) (image.MultiarchImage, error) {
index.SchemaVersion = 2 index.SchemaVersion = 2
return image.MultiarchImage{ return image.MultiarchImage{
Index: index, Images: images, Reference: reference, Index: index, Images: images,
}, err }, err
} }

View File

@ -11,6 +11,7 @@ import (
"github.com/opencontainers/image-spec/specs-go" "github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1" ispec "github.com/opencontainers/image-spec/specs-go/v1"
mTypes "zotregistry.io/zot/pkg/meta/types"
storageConstants "zotregistry.io/zot/pkg/storage/constants" storageConstants "zotregistry.io/zot/pkg/storage/constants"
) )
@ -48,6 +49,9 @@ type ConfigBuilder interface {
// an OCI artifact. // an OCI artifact.
// (see: https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidelines-for-artifact-usage) // (see: https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidelines-for-artifact-usage)
ArtifactConfig(artifactType string) ManifestBuilder ArtifactConfig(artifactType string) ManifestBuilder
// PlatformConfig is used when we're interesting in specifying only the platform of a manifest.
// Other fields of the config are random.
PlatformConfig(architecture, os string) ManifestBuilder
// DefaultConfig sets the default config, platform linux/amd64. // DefaultConfig sets the default config, platform linux/amd64.
DefaultConfig() ManifestBuilder DefaultConfig() ManifestBuilder
// CustomConfigBlob will set a custom blob as the image config without other checks. // CustomConfigBlob will set a custom blob as the image config without other checks.
@ -92,13 +96,17 @@ type Image struct {
} }
func (img *Image) Digest() godigest.Digest { func (img *Image) Digest() godigest.Digest {
if img.ManifestDescriptor.Digest != "" {
return img.ManifestDescriptor.Digest
}
// when we'll migrate all code to the new format of creating images we can replace this with
// the value from manifestDescriptor
blob, err := json.Marshal(img.Manifest) blob, err := json.Marshal(img.Manifest)
if err != nil { if err != nil {
panic("unreachable: ispec.Manifest should always be marshable") panic("unreachable: ispec.Manifest should always be marshable")
} }
// when we'll migrate all code to the new format of creating images we can replace this with
// the value from manifestDescriptor
return godigest.FromBytes(blob) return godigest.FromBytes(blob)
} }
@ -106,6 +114,16 @@ func (img *Image) DigestStr() string {
return img.Digest().String() return img.Digest().String()
} }
func (img *Image) Size() int {
size := img.ConfigDescriptor.Size + img.ManifestDescriptor.Size
for _, layer := range img.Manifest.Layers {
size += layer.Size
}
return int(size)
}
func (img Image) Descriptor() ispec.Descriptor { func (img Image) Descriptor() ispec.Descriptor {
return ispec.Descriptor{ return ispec.Descriptor{
MediaType: img.ManifestDescriptor.MediaType, MediaType: img.ManifestDescriptor.MediaType,
@ -122,6 +140,22 @@ func (img Image) DescriptorRef() *ispec.Descriptor {
} }
} }
func (img Image) AsImageMeta() mTypes.ImageMeta {
return mTypes.ImageMeta{
MediaType: img.Manifest.MediaType,
Digest: img.ManifestDescriptor.Digest,
Size: img.ManifestDescriptor.Size,
Manifests: []mTypes.ManifestData{
{
Size: img.ManifestDescriptor.Size,
Digest: img.ManifestDescriptor.Digest,
Manifest: img.Manifest,
Config: img.Config,
},
},
}
}
type Layer struct { type Layer struct {
Blob []byte Blob []byte
MediaType string MediaType string
@ -281,6 +315,16 @@ func (ib *BaseImageBuilder) DefaultConfig() ManifestBuilder {
return ib.ImageConfig(GetDefaultConfig()) return ib.ImageConfig(GetDefaultConfig())
} }
func (ib *BaseImageBuilder) PlatformConfig(arch, os string) ManifestBuilder {
conf := GetDefaultConfig()
conf.Created = RandomDateRef(time.UTC)
conf.Author = getRandomAuthor()
conf.Platform = ispec.Platform{Architecture: arch, OS: os}
return ib.ImageConfig(conf)
}
func (ib *BaseImageBuilder) EmptyConfig() ManifestBuilder { func (ib *BaseImageBuilder) EmptyConfig() ManifestBuilder {
ib.configDescriptor = ispec.DescriptorEmptyJSON ib.configDescriptor = ispec.DescriptorEmptyJSON

View File

@ -166,16 +166,6 @@ func TestPredefinedImages(t *testing.T) {
img = CreateRandomVulnerableImageWith().ArtifactType("art.type").Build() img = CreateRandomVulnerableImageWith().ArtifactType("art.type").Build()
So(img.Manifest.ArtifactType, ShouldEqual, "art.type") So(img.Manifest.ArtifactType, ShouldEqual, "art.type")
}) })
Convey("Predefined Multiarch-Images", t, func() {
multiArch := CreateRandomMultiarch()
So(len(multiArch.Images), ShouldEqual, 3)
So(multiArch.Reference, ShouldResemble, multiArch.Digest().String())
multiArch = CreateVulnerableMultiarch()
So(len(multiArch.Images), ShouldEqual, 3)
So(multiArch.Reference, ShouldResemble, multiArch.Digest().String())
})
} }
func TestImageMethods(t *testing.T) { func TestImageMethods(t *testing.T) {

View File

@ -13,7 +13,6 @@ import (
type MultiarchImage struct { type MultiarchImage struct {
Index ispec.Index Index ispec.Index
Images []Image Images []Image
Reference string
IndexDescriptor ispec.Descriptor IndexDescriptor ispec.Descriptor
} }
@ -31,17 +30,27 @@ func (mi *MultiarchImage) DigestStr() string {
return mi.Digest().String() return mi.Digest().String()
} }
func (mi *MultiarchImage) IndexData() mTypes.IndexData { func (mi MultiarchImage) AsImageMeta() mTypes.ImageMeta {
indexBlob, err := json.Marshal(mi.Index) index := mi.Index
if err != nil {
panic("unreachable: ispec.Index should always be marshable") manifests := make([]mTypes.ManifestData, 0, len(index.Manifests))
for _, image := range mi.Images {
manifests = append(manifests, image.AsImageMeta().Manifests...)
} }
return mTypes.IndexData{IndexBlob: indexBlob} return mTypes.ImageMeta{
MediaType: ispec.MediaTypeImageIndex,
Digest: mi.IndexDescriptor.Digest,
Size: mi.IndexDescriptor.Size,
Index: &index,
Manifests: manifests,
}
} }
type ImagesBuilder interface { type ImagesBuilder interface {
Images(images []Image) MultiarchBuilder Images(images []Image) MultiarchBuilder
RandomImages(count int) MultiarchBuilder
} }
type MultiarchBuilder interface { type MultiarchBuilder interface {
@ -88,6 +97,18 @@ func (mb *BaseMultiarchBuilder) Images(images []Image) MultiarchBuilder {
return mb return mb
} }
func (mb *BaseMultiarchBuilder) RandomImages(count int) MultiarchBuilder {
images := make([]Image, count)
for i := range images {
images[i] = CreateRandomImage()
}
mb.images = images
return mb
}
func (mb *BaseMultiarchBuilder) Subject(subject *ispec.Descriptor) MultiarchBuilder { func (mb *BaseMultiarchBuilder) Subject(subject *ispec.Descriptor) MultiarchBuilder {
mb.subject = subject mb.subject = subject
@ -135,12 +156,9 @@ func (mb *BaseMultiarchBuilder) Build() MultiarchImage {
indexDigest := godigest.FromBytes(indexBlob) indexDigest := godigest.FromBytes(indexBlob)
ref := indexDigest.String()
return MultiarchImage{ return MultiarchImage{
Index: index, Index: index,
Images: mb.images, Images: mb.images,
Reference: ref,
IndexDescriptor: ispec.Descriptor{ IndexDescriptor: ispec.Descriptor{
MediaType: ispec.MediaTypeImageIndex, MediaType: ispec.MediaTypeImageIndex,

View File

@ -223,10 +223,16 @@ func UploadMultiarchImage(multiImage MultiarchImage, baseURL string, repo, ref s
} }
// put manifest // put manifest
indexBlob, err := json.Marshal(multiImage.Index) indexBlob := multiImage.IndexDescriptor.Data
if len(indexBlob) == 0 {
var err error
indexBlob, err = json.Marshal(multiImage.Index)
if err = inject.Error(err); err != nil { if err = inject.Error(err); err != nil {
return err return err
} }
}
resp, err := resty.R(). resp, err := resty.R().
SetHeader("Content-type", ispec.MediaTypeImageIndex). SetHeader("Content-type", ispec.MediaTypeImageIndex).

View File

@ -176,21 +176,3 @@ func GetRandomImageConfig() ([]byte, godigest.Digest) {
return configBlobContent, configBlobDigestRaw return configBlobContent, configBlobDigestRaw
} }
func GetIndexBlobWithManifests(manifestDigests []godigest.Digest) ([]byte, error) {
manifests := make([]ispec.Descriptor, 0, len(manifestDigests))
for _, manifestDigest := range manifestDigests {
manifests = append(manifests, ispec.Descriptor{
Digest: manifestDigest,
MediaType: ispec.MediaTypeImageManifest,
})
}
indexContent := ispec.Index{
MediaType: ispec.MediaTypeImageIndex,
Manifests: manifests,
}
return json.Marshal(indexContent)
}

View File

@ -9,74 +9,6 @@ import (
) )
type MetaDBMock struct { type MetaDBMock struct {
SetRepoDescriptionFn func(repo, description string) error
IncrementRepoStarsFn func(repo string) error
DecrementRepoStarsFn func(repo string) error
GetRepoStarsFn func(repo string) (int, error)
SetRepoLogoFn func(repo string, logoPath string) error
SetRepoReferenceFn func(repo string, Reference string, manifestDigest godigest.Digest, mediaType string) error
RemoveRepoReferenceFn func(repo, reference string, manifestDigest godigest.Digest) error
DeleteRepoTagFn func(repo string, tag string) error
GetRepoMetaFn func(repo string) (mTypes.RepoMetadata, error)
GetUserRepoMetaFn func(ctx context.Context, repo string) (mTypes.RepoMetadata, error)
SetRepoMetaFn func(repo string, repoMeta mTypes.RepoMetadata) error
GetMultipleRepoMetaFn func(ctx context.Context, filter func(repoMeta mTypes.RepoMetadata) bool) (
[]mTypes.RepoMetadata, error)
GetManifestDataFn func(manifestDigest godigest.Digest) (mTypes.ManifestData, error)
SetManifestDataFn func(manifestDigest godigest.Digest, mm mTypes.ManifestData) error
GetManifestMetaFn func(repo string, manifestDigest godigest.Digest) (mTypes.ManifestMetadata, error)
SetManifestMetaFn func(repo string, manifestDigest godigest.Digest, mm mTypes.ManifestMetadata) error
SetIndexDataFn func(digest godigest.Digest, indexData mTypes.IndexData) error
GetIndexDataFn func(indexDigest godigest.Digest) (mTypes.IndexData, error)
SetReferrerFn func(repo string, referredDigest godigest.Digest, referrer mTypes.ReferrerInfo) error
DeleteReferrerFn func(repo string, referredDigest godigest.Digest, referrerDigest godigest.Digest) error
GetReferrersFn func(repo string, referredDigest godigest.Digest) ([]mTypes.Descriptor, error)
GetReferrersInfoFn func(repo string, referredDigest godigest.Digest, artifactTypes []string) (
[]mTypes.ReferrerInfo, error)
IncrementImageDownloadsFn func(repo string, reference string) error
UpdateSignaturesValidityFn func(repo string, manifestDigest godigest.Digest) error
AddManifestSignatureFn func(repo string, signedManifestDigest godigest.Digest, sm mTypes.SignatureMetadata) error
DeleteSignatureFn func(repo string, signedManifestDigest godigest.Digest, sm mTypes.SignatureMetadata) error
SearchReposFn func(ctx context.Context, txt string) (
[]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData,
error)
SearchTagsFn func(ctx context.Context, txt string) (
[]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData,
error)
FilterReposFn func(ctx context.Context, filter mTypes.FilterRepoFunc) (
[]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error)
FilterTagsFn func(ctx context.Context, filterFunc mTypes.FilterFunc) (
[]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error)
GetStarredReposFn func(ctx context.Context) ([]string, error) GetStarredReposFn func(ctx context.Context) ([]string, error)
GetBookmarkedReposFn func(ctx context.Context) ([]string, error) GetBookmarkedReposFn func(ctx context.Context) ([]string, error)
@ -112,6 +44,69 @@ type MetaDBMock struct {
ImageTrustStoreFn func() mTypes.ImageTrustStore ImageTrustStoreFn func() mTypes.ImageTrustStore
SetImageTrustStoreFn func(mTypes.ImageTrustStore) SetImageTrustStoreFn func(mTypes.ImageTrustStore)
SetRepoReferenceFn func(repo string, reference string, imageMeta mTypes.ImageMeta) error
SearchReposFn func(ctx context.Context, searchText string,
) ([]mTypes.RepoMeta, error)
SearchTagsFn func(ctx context.Context, searchText string) ([]mTypes.FullImageMeta, error)
FilterTagFn func(ctx context.Context, filterFunc mTypes.FilterFunc,
) ([]mTypes.RepoMeta, map[string]mTypes.ImageMeta, error)
GetImageMetaFn func(digest godigest.Digest) (mTypes.ImageMeta, error)
GetMultipleRepoMetaFn func(ctx context.Context, filter func(repoMeta mTypes.RepoMeta) bool,
) ([]mTypes.RepoMeta, error)
FilterReposFn func(ctx context.Context, rankName mTypes.FilterRepoNameFunc,
filterFunc mTypes.FilterFullRepoFunc) ([]mTypes.RepoMeta, error)
IncrementRepoStarsFn func(repo string) error
DecrementRepoStarsFn func(repo string) error
SetRepoMetaFn func(repo string, repoMeta mTypes.RepoMeta) error
DeleteReferrerFn func(repo string, referredDigest godigest.Digest, referrerDigest godigest.Digest) error
GetReferrersInfoFn func(repo string, referredDigest godigest.Digest, artifactTypes []string,
) ([]mTypes.ReferrerInfo, error)
IncrementImageDownloadsFn func(repo string, reference string) error
UpdateSignaturesValidityFn func(repo string, manifestDigest godigest.Digest) error
AddManifestSignatureFn func(repo string, signedManifestDigest godigest.Digest, sygMeta mTypes.SignatureMetadata,
) error
DeleteSignatureFn func(repo string, signedManifestDigest godigest.Digest, sigMeta mTypes.SignatureMetadata) error
SetImageMetaFn func(digest godigest.Digest, imageMeta mTypes.ImageMeta) error
FilterTagsFn func(ctx context.Context, filterRepoTag mTypes.FilterRepoTagFunc,
filterFunc mTypes.FilterFunc) ([]mTypes.FullImageMeta, error)
GetRepoMetaFn func(ctx context.Context, repo string) (mTypes.RepoMeta, error)
FilterImageMetaFn func(ctx context.Context, digests []string) (map[string]mTypes.ImageMeta, error)
RemoveRepoReferenceFn func(repo, reference string, manifestDigest godigest.Digest) error
GetFullImageMetaFn func(ctx context.Context, repo string, tag string) (mTypes.FullImageMeta, error)
ResetRepoReferencesFn func(repo string) error
ResetDBFn func() error
}
func (sdm MetaDBMock) ResetDB() error {
if sdm.ResetDBFn != nil {
return sdm.ResetDBFn()
}
return nil
} }
func (sdm MetaDBMock) ImageTrustStore() mTypes.ImageTrustStore { func (sdm MetaDBMock) ImageTrustStore() mTypes.ImageTrustStore {
@ -128,221 +123,6 @@ func (sdm MetaDBMock) SetImageTrustStore(imgTrustStore mTypes.ImageTrustStore) {
} }
} }
func (sdm MetaDBMock) SetRepoDescription(repo, description string) error {
if sdm.SetRepoDescriptionFn != nil {
return sdm.SetRepoDescriptionFn(repo, description)
}
return nil
}
func (sdm MetaDBMock) IncrementRepoStars(repo string) error {
if sdm.IncrementRepoStarsFn != nil {
return sdm.IncrementRepoStarsFn(repo)
}
return nil
}
func (sdm MetaDBMock) DecrementRepoStars(repo string) error {
if sdm.DecrementRepoStarsFn != nil {
return sdm.DecrementRepoStarsFn(repo)
}
return nil
}
func (sdm MetaDBMock) GetRepoStars(repo string) (int, error) {
if sdm.GetRepoStarsFn != nil {
return sdm.GetRepoStarsFn(repo)
}
return 0, nil
}
func (sdm MetaDBMock) SetRepoReference(repo string, reference string, manifestDigest godigest.Digest,
mediaType string,
) error {
if sdm.SetRepoReferenceFn != nil {
return sdm.SetRepoReferenceFn(repo, reference, manifestDigest, mediaType)
}
return nil
}
func (sdm MetaDBMock) RemoveRepoReference(repo, reference string, manifestDigest godigest.Digest) error {
if sdm.RemoveRepoReferenceFn != nil {
return sdm.RemoveRepoReferenceFn(repo, reference, manifestDigest)
}
return nil
}
func (sdm MetaDBMock) DeleteRepoTag(repo string, tag string) error {
if sdm.DeleteRepoTagFn != nil {
return sdm.DeleteRepoTagFn(repo, tag)
}
return nil
}
func (sdm MetaDBMock) GetRepoMeta(repo string) (mTypes.RepoMetadata, error) {
if sdm.GetRepoMetaFn != nil {
return sdm.GetRepoMetaFn(repo)
}
return mTypes.RepoMetadata{}, nil
}
func (sdm MetaDBMock) GetUserRepoMeta(ctx context.Context, repo string) (mTypes.RepoMetadata, error) {
if sdm.GetUserRepoMetaFn != nil {
return sdm.GetUserRepoMetaFn(ctx, repo)
}
return mTypes.RepoMetadata{}, nil
}
func (sdm MetaDBMock) SetRepoMeta(repo string, repoMeta mTypes.RepoMetadata) error {
if sdm.SetRepoMetaFn != nil {
return sdm.SetRepoMetaFn(repo, repoMeta)
}
return nil
}
func (sdm MetaDBMock) GetMultipleRepoMeta(ctx context.Context, filter func(repoMeta mTypes.RepoMetadata) bool,
) ([]mTypes.RepoMetadata, error) {
if sdm.GetMultipleRepoMetaFn != nil {
return sdm.GetMultipleRepoMetaFn(ctx, filter)
}
return []mTypes.RepoMetadata{}, nil
}
func (sdm MetaDBMock) GetManifestData(manifestDigest godigest.Digest) (mTypes.ManifestData, error) {
if sdm.GetManifestDataFn != nil {
return sdm.GetManifestDataFn(manifestDigest)
}
return mTypes.ManifestData{}, nil
}
func (sdm MetaDBMock) SetManifestData(manifestDigest godigest.Digest, md mTypes.ManifestData) error {
if sdm.SetManifestDataFn != nil {
return sdm.SetManifestDataFn(manifestDigest, md)
}
return nil
}
func (sdm MetaDBMock) GetManifestMeta(repo string, manifestDigest godigest.Digest) (mTypes.ManifestMetadata, error) {
if sdm.GetManifestMetaFn != nil {
return sdm.GetManifestMetaFn(repo, manifestDigest)
}
return mTypes.ManifestMetadata{}, nil
}
func (sdm MetaDBMock) SetManifestMeta(repo string, manifestDigest godigest.Digest, mm mTypes.ManifestMetadata) error {
if sdm.SetManifestMetaFn != nil {
return sdm.SetManifestMetaFn(repo, manifestDigest, mm)
}
return nil
}
func (sdm MetaDBMock) IncrementImageDownloads(repo string, reference string) error {
if sdm.IncrementImageDownloadsFn != nil {
return sdm.IncrementImageDownloadsFn(repo, reference)
}
return nil
}
func (sdm MetaDBMock) UpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error {
if sdm.UpdateSignaturesValidityFn != nil {
return sdm.UpdateSignaturesValidityFn(repo, manifestDigest)
}
return nil
}
func (sdm MetaDBMock) AddManifestSignature(repo string, signedManifestDigest godigest.Digest,
sm mTypes.SignatureMetadata,
) error {
if sdm.AddManifestSignatureFn != nil {
return sdm.AddManifestSignatureFn(repo, signedManifestDigest, sm)
}
return nil
}
func (sdm MetaDBMock) DeleteSignature(repo string, signedManifestDigest godigest.Digest,
sm mTypes.SignatureMetadata,
) error {
if sdm.DeleteSignatureFn != nil {
return sdm.DeleteSignatureFn(repo, signedManifestDigest, sm)
}
return nil
}
func (sdm MetaDBMock) SearchRepos(ctx context.Context, searchText string,
) ([]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error) {
if sdm.SearchReposFn != nil {
return sdm.SearchReposFn(ctx, searchText)
}
return []mTypes.RepoMetadata{}, map[string]mTypes.ManifestMetadata{},
map[string]mTypes.IndexData{}, nil
}
func (sdm MetaDBMock) SearchTags(ctx context.Context, searchText string,
) ([]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error) {
if sdm.SearchTagsFn != nil {
return sdm.SearchTagsFn(ctx, searchText)
}
return []mTypes.RepoMetadata{}, map[string]mTypes.ManifestMetadata{},
map[string]mTypes.IndexData{}, nil
}
func (sdm MetaDBMock) FilterRepos(ctx context.Context, filter mTypes.FilterRepoFunc,
) ([]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error) {
if sdm.FilterReposFn != nil {
return sdm.FilterReposFn(ctx, filter)
}
return []mTypes.RepoMetadata{}, map[string]mTypes.ManifestMetadata{},
map[string]mTypes.IndexData{}, nil
}
func (sdm MetaDBMock) FilterTags(ctx context.Context, filterFunc mTypes.FilterFunc,
) ([]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error) {
if sdm.FilterTagsFn != nil {
return sdm.FilterTagsFn(ctx, filterFunc)
}
return []mTypes.RepoMetadata{}, map[string]mTypes.ManifestMetadata{},
map[string]mTypes.IndexData{}, nil
}
func (sdm MetaDBMock) SetIndexData(digest godigest.Digest, indexData mTypes.IndexData) error {
if sdm.SetIndexDataFn != nil {
return sdm.SetIndexDataFn(digest, indexData)
}
return nil
}
func (sdm MetaDBMock) GetIndexData(indexDigest godigest.Digest) (mTypes.IndexData, error) {
if sdm.GetIndexDataFn != nil {
return sdm.GetIndexDataFn(indexDigest)
}
return mTypes.IndexData{}, nil
}
func (sdm MetaDBMock) PatchDB() error { func (sdm MetaDBMock) PatchDB() error {
if sdm.PatchDBFn != nil { if sdm.PatchDBFn != nil {
return sdm.PatchDBFn() return sdm.PatchDBFn()
@ -351,34 +131,6 @@ func (sdm MetaDBMock) PatchDB() error {
return nil return nil
} }
func (sdm MetaDBMock) SetReferrer(repo string, referredDigest godigest.Digest, referrer mTypes.ReferrerInfo) error {
if sdm.SetReferrerFn != nil {
return sdm.SetReferrerFn(repo, referredDigest, referrer)
}
return nil
}
func (sdm MetaDBMock) DeleteReferrer(repo string, referredDigest godigest.Digest,
referrerDigest godigest.Digest,
) error {
if sdm.DeleteReferrerFn != nil {
return sdm.DeleteReferrerFn(repo, referredDigest, referrerDigest)
}
return nil
}
func (sdm MetaDBMock) GetReferrersInfo(repo string, referredDigest godigest.Digest,
artifactTypes []string,
) ([]mTypes.ReferrerInfo, error) {
if sdm.GetReferrersInfoFn != nil {
return sdm.GetReferrersInfoFn(repo, referredDigest, artifactTypes)
}
return []mTypes.ReferrerInfo{}, nil
}
func (sdm MetaDBMock) GetStarredRepos(ctx context.Context) ([]string, error) { func (sdm MetaDBMock) GetStarredRepos(ctx context.Context) ([]string, error) {
if sdm.GetStarredReposFn != nil { if sdm.GetStarredReposFn != nil {
return sdm.GetStarredReposFn(ctx) return sdm.GetStarredReposFn(ctx)
@ -498,3 +250,184 @@ func (sdm MetaDBMock) DeleteUserAPIKey(ctx context.Context, id string) error {
return nil return nil
} }
func (sdm MetaDBMock) SetImageMeta(digest godigest.Digest, imageMeta mTypes.ImageMeta) error {
if sdm.SetImageMetaFn != nil {
return sdm.SetImageMetaFn(digest, imageMeta)
}
return nil
}
func (sdm MetaDBMock) SetRepoReference(repo string, reference string, imageMeta mTypes.ImageMeta) error {
if sdm.SetRepoReferenceFn != nil {
return sdm.SetRepoReferenceFn(repo, reference, imageMeta)
}
return nil
}
func (sdm MetaDBMock) SearchRepos(ctx context.Context, searchText string) ([]mTypes.RepoMeta, error) {
if sdm.SearchReposFn != nil {
return sdm.SearchReposFn(ctx, searchText)
}
return []mTypes.RepoMeta{}, nil
}
func (sdm MetaDBMock) SearchTags(ctx context.Context, searchText string) ([]mTypes.FullImageMeta, error) {
if sdm.SearchTagsFn != nil {
return sdm.SearchTagsFn(ctx, searchText)
}
return []mTypes.FullImageMeta{}, nil
}
func (sdm MetaDBMock) FilterTags(ctx context.Context, filterRepoTag mTypes.FilterRepoTagFunc,
filterFunc mTypes.FilterFunc,
) ([]mTypes.FullImageMeta, error) {
if sdm.FilterTagsFn != nil {
return sdm.FilterTagsFn(ctx, filterRepoTag, filterFunc)
}
return []mTypes.FullImageMeta{}, nil
}
func (sdm MetaDBMock) GetRepoMeta(ctx context.Context, repo string) (mTypes.RepoMeta, error) {
if sdm.GetRepoMetaFn != nil {
return sdm.GetRepoMetaFn(ctx, repo)
}
return mTypes.RepoMeta{}, nil
}
func (sdm MetaDBMock) GetImageMeta(digest godigest.Digest) (mTypes.ImageMeta, error) {
if sdm.GetImageMetaFn != nil {
return sdm.GetImageMetaFn(digest)
}
return mTypes.ImageMeta{}, nil
}
func (sdm MetaDBMock) GetMultipleRepoMeta(ctx context.Context, filter func(repoMeta mTypes.RepoMeta) bool,
) ([]mTypes.RepoMeta, error) {
if sdm.GetMultipleRepoMetaFn != nil {
return sdm.GetMultipleRepoMetaFn(ctx, filter)
}
return []mTypes.RepoMeta{}, nil
}
func (sdm MetaDBMock) FilterRepos(ctx context.Context, rankName mTypes.FilterRepoNameFunc,
filterFunc mTypes.FilterFullRepoFunc,
) ([]mTypes.RepoMeta, error) {
if sdm.FilterReposFn != nil {
return sdm.FilterReposFn(ctx, rankName, filterFunc)
}
return []mTypes.RepoMeta{}, nil
}
func (sdm MetaDBMock) IncrementRepoStars(repo string) error {
if sdm.IncrementRepoStarsFn != nil {
return sdm.IncrementRepoStarsFn(repo)
}
return nil
}
func (sdm MetaDBMock) DecrementRepoStars(repo string) error {
if sdm.DecrementRepoStarsFn != nil {
return sdm.DecrementRepoStarsFn(repo)
}
return nil
}
func (sdm MetaDBMock) SetRepoMeta(repo string, repoMeta mTypes.RepoMeta) error {
if sdm.SetRepoMetaFn != nil {
return sdm.SetRepoMetaFn(repo, repoMeta)
}
return nil
}
func (sdm MetaDBMock) GetReferrersInfo(repo string, referredDigest godigest.Digest,
artifactTypes []string,
) ([]mTypes.ReferrerInfo, error) {
if sdm.GetReferrersInfoFn != nil {
return sdm.GetReferrersInfoFn(repo, referredDigest, artifactTypes)
}
return []mTypes.ReferrerInfo{}, nil
}
func (sdm MetaDBMock) IncrementImageDownloads(repo string, reference string) error {
if sdm.IncrementImageDownloadsFn != nil {
return sdm.IncrementImageDownloadsFn(repo, reference)
}
return nil
}
func (sdm MetaDBMock) UpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error {
if sdm.UpdateSignaturesValidityFn != nil {
return sdm.UpdateSignaturesValidityFn(repo, manifestDigest)
}
return nil
}
func (sdm MetaDBMock) AddManifestSignature(repo string, signedManifestDigest godigest.Digest,
sygMeta mTypes.SignatureMetadata,
) error {
if sdm.AddManifestSignatureFn != nil {
return sdm.AddManifestSignatureFn(repo, signedManifestDigest, sygMeta)
}
return nil
}
func (sdm MetaDBMock) DeleteSignature(repo string, signedManifestDigest godigest.Digest,
sigMeta mTypes.SignatureMetadata,
) error {
if sdm.DeleteSignatureFn != nil {
return sdm.DeleteSignatureFn(repo, signedManifestDigest, sigMeta)
}
return nil
}
func (sdm MetaDBMock) FilterImageMeta(ctx context.Context, digests []string,
) (map[string]mTypes.ImageMeta, error) {
if sdm.FilterImageMetaFn != nil {
return sdm.FilterImageMetaFn(ctx, digests)
}
return map[string]mTypes.ImageMeta{}, nil
}
func (sdm MetaDBMock) RemoveRepoReference(repo, reference string, manifestDigest godigest.Digest) error {
if sdm.RemoveRepoReferenceFn != nil {
return sdm.RemoveRepoReferenceFn(repo, reference, manifestDigest)
}
return nil
}
func (sdm MetaDBMock) GetFullImageMeta(ctx context.Context, repo string, tag string,
) (mTypes.FullImageMeta, error) {
if sdm.GetFullImageMetaFn != nil {
return sdm.GetFullImageMetaFn(ctx, repo, tag)
}
return mTypes.FullImageMeta{}, nil
}
func (sdm MetaDBMock) ResetRepoReferences(repo string) error {
if sdm.ResetRepoReferencesFn != nil {
return sdm.ResetRepoReferencesFn(repo)
}
return nil
}

View File

@ -1,110 +1,142 @@
package ociutils package ociutils
import ( import (
ispec "github.com/opencontainers/image-spec/specs-go/v1" "context"
"fmt"
zerr "zotregistry.io/zot/errors"
mTypes "zotregistry.io/zot/pkg/meta/types" mTypes "zotregistry.io/zot/pkg/meta/types"
reqCtx "zotregistry.io/zot/pkg/requestcontext"
imageUtil "zotregistry.io/zot/pkg/test/image-utils" imageUtil "zotregistry.io/zot/pkg/test/image-utils"
) )
type RepoImage struct { type RepoImage struct {
imageUtil.Image imageUtil.Image
Tag string Reference string
Statistics mTypes.DescriptorStatistics Statistics mTypes.DescriptorStatistics
} }
type RepoMultiArchImage struct { type RepoMultiArchImage struct {
imageUtil.MultiarchImage imageUtil.MultiarchImage
ImageStatistics map[string]mTypes.DescriptorStatistics ImageStatistics map[string]mTypes.DescriptorStatistics
Tag string Reference string
} }
type Repo struct { type Repo struct {
Name string Name string
Images []RepoImage Images []RepoImage
MultiArchImages []RepoMultiArchImage MultiArchImages []RepoMultiArchImage
Signatures map[string]mTypes.ManifestSignatures
Stars int
IsBookmarked bool IsBookmarked bool
IsStarred bool IsStarred bool
} }
func GetMetadataForRepos(repos ...Repo) ([]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata, func InitializeTestMetaDB(ctx context.Context, metaDB mTypes.MetaDB, repos ...Repo) (context.Context, error) {
map[string]mTypes.IndexData, uac := reqCtx.NewUserAccessControl()
) { uac.SetUsername("test")
var ( uacContext := context.WithValue(ctx, reqCtx.GetContextKey(), *uac)
reposMetadata = []mTypes.RepoMetadata{}
manifestMetadataMap = map[string]mTypes.ManifestMetadata{}
indexDataMap = map[string]mTypes.IndexData{}
)
for _, repo := range repos { err := validateRepos(repos)
repoMeta := mTypes.RepoMetadata{ if err != nil {
Name: repo.Name, return uacContext, err
Tags: map[string]mTypes.Descriptor{},
Signatures: map[string]mTypes.ManifestSignatures{},
Statistics: map[string]mTypes.DescriptorStatistics{},
IsStarred: repo.IsStarred,
IsBookmarked: repo.IsBookmarked,
} }
for _, repo := range repos {
statistics := map[string]mTypes.DescriptorStatistics{"": {}}
for _, image := range repo.Images { for _, image := range repo.Images {
addImageMetaToMetaDB(image, repoMeta, manifestMetadataMap) err := metaDB.SetRepoReference(repo.Name, image.Reference, image.AsImageMeta())
if err != nil {
return uacContext, err
}
statistics[image.DigestStr()] = image.Statistics
} }
for _, multiArch := range repo.MultiArchImages { for _, multiArch := range repo.MultiArchImages {
if multiArch.ImageStatistics == nil {
multiArch.ImageStatistics = map[string]mTypes.DescriptorStatistics{}
}
repoMeta.Tags[multiArch.Tag] = mTypes.Descriptor{
MediaType: ispec.MediaTypeImageIndex,
Digest: multiArch.DigestStr(),
}
repoMeta.Statistics[multiArch.DigestStr()] = multiArch.ImageStatistics[multiArch.DigestStr()]
for _, image := range multiArch.Images { for _, image := range multiArch.Images {
addImageMetaToMetaDB(RepoImage{ err := metaDB.SetRepoReference(repo.Name, image.DigestStr(), image.AsImageMeta())
Image: image, if err != nil {
Statistics: multiArch.ImageStatistics[image.DigestStr()], return uacContext, err
}, repoMeta, manifestMetadataMap)
} }
indexDataMap[multiArch.IndexDescriptor.Digest.String()] = mTypes.IndexData{ statistics[image.DigestStr()] = multiArch.ImageStatistics[image.DigestStr()]
IndexBlob: multiArch.IndexDescriptor.Data, }
err := metaDB.SetRepoReference(repo.Name, multiArch.Reference, multiArch.AsImageMeta())
if err != nil {
return uacContext, err
}
statistics[multiArch.DigestStr()] = multiArch.ImageStatistics[multiArch.DigestStr()]
}
// Update repo metadata
repoMeta, err := metaDB.GetRepoMeta(ctx, repo.Name)
if err != nil {
return uacContext, err
}
repoMeta.StarCount = repo.Stars
repoMeta.IsStarred = repo.IsStarred
repoMeta.IsBookmarked = repo.IsBookmarked
// updateStatistics
for key, value := range statistics {
repoMeta.Statistics[key] = value
}
// update signatures?
for key, value := range repo.Signatures {
repoMeta.Signatures[key] = value
}
err = metaDB.SetRepoMeta(repo.Name, repoMeta)
if err != nil {
return uacContext, err
}
// User data is set after we create the repo
if repo.IsBookmarked {
_, err := metaDB.ToggleBookmarkRepo(uacContext, repo.Name)
if err != nil {
return uacContext, err
} }
} }
reposMetadata = append(reposMetadata, repoMeta) if repo.IsStarred {
_, err := metaDB.ToggleStarRepo(uacContext, repo.Name)
if err != nil {
return uacContext, err
}
}
} }
return reposMetadata, manifestMetadataMap, indexDataMap return uacContext, nil
} }
func addImageMetaToMetaDB(image RepoImage, repoMeta mTypes.RepoMetadata, func validateRepos(repos []Repo) error {
manifestMetadataMap map[string]mTypes.ManifestMetadata, repoNames := map[string]struct{}{}
) {
if image.Tag != "" {
repoMeta.Tags[image.Tag] = mTypes.Descriptor{
MediaType: ispec.MediaTypeImageManifest,
Digest: image.DigestStr(),
}
}
// here we can do many more checks about the images like check for referrers, signatures but it's not needed yet
// I need just the tags for now and the fake signature.
// This is done just to mark a manifest as signed in the resulted RepoMeta for _, repo := range repos {
if image.Manifest.ArtifactType == imageUtil.TestFakeSignatureArtType && image.Manifest.Subject != nil { if _, found := repoNames[repo.Name]; found {
signedManifestDig := image.Manifest.Subject.Digest.String() return fmt.Errorf("%w '%s'", zerr.ErrMultipleReposSameName, repo.Name)
repoMeta.Signatures[signedManifestDig] = mTypes.ManifestSignatures{
"fakeSignature": []mTypes.SignatureInfo{{SignatureManifestDigest: image.ManifestDescriptor.Digest.String()}},
}
} }
repoMeta.Statistics[image.DigestStr()] = image.Statistics repoNames[repo.Name] = struct{}{}
}
manifestMetadataMap[image.DigestStr()] = mTypes.ManifestMetadata{ return nil
ManifestBlob: image.ManifestDescriptor.Data, }
ConfigBlob: image.ConfigDescriptor.Data,
DownloadCount: image.Statistics.DownloadCount, func GetFakeSignatureInfo(signatureDigest string) map[string][]mTypes.SignatureInfo {
return map[string][]mTypes.SignatureInfo{
"fake-signature": {
{
SignatureManifestDigest: signatureDigest,
LayersInfo: []mTypes.LayerInfo{},
},
},
} }
} }

View File

@ -41,8 +41,8 @@ function setup() {
"region": "us-east-2", "region": "us-east-2",
"cacheTablename": "BlobTable", "cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable", "repoMetaTablename": "RepoMetadataTable",
"manifestDataTablename": "ManifestDataTable", "imageMetaTablename": "ImageMetaTable",
"indexDataTablename": "IndexDataTable", "repoBlobsInfoTablename": "RepoBlobsInfoTable",
"userDataTablename": "UserDataTable", "userDataTablename": "UserDataTable",
"apiKeyTablename":"ApiKeyTable", "apiKeyTablename":"ApiKeyTable",
"versionTablename": "Version" "versionTablename": "Version"