0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-16 21:56:37 -05:00

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.
# skip-pkg-cache: true
# skip-pkg-cache: false
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true

1
.gitignore vendored
View file

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

View file

@ -32,6 +32,22 @@ TESTDATA := $(TOP_LEVEL)/test/data
OS ?= $(shell go env GOOS)
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
ALL_EXTENSIONS = debug,imagetrust,lint,metrics,mgmt,profile,scrub,search,sync,ui,userprefs
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"
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
binary-minimal: EXTENSIONS=
binary-minimal: modcheck build-metadata
@ -218,6 +279,13 @@ $(CRICTL):
mv crictl $(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):
mkdir -p $(TOOLSDIR)/bin
@ -515,6 +583,12 @@ ifneq ($(shell go env GOOS),linux)
$(error makefile target can be run only on linux)
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
check-compatibility:
ifeq ($(OS),freebsd)

View file

@ -6,3 +6,4 @@ ignore:
- "./pkg/test/mocks/*.go"
- "./swagger/*.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")
ErrManifestConflict = errors.New("manifest: multiple manifests found")
ErrManifestMetaNotFound = errors.New("metadb: image metadata not found for given manifest reference")
ErrManifestDataNotFound = errors.New("metadb: image data not found for given manifest digest")
ErrIndexDataNotFount = errors.New("metadb: index data not found for given digest")
ErrImageMetaNotFound = errors.New("metadb: image meta not found")
ErrUnexpectedMediaType = errors.New("metadb: got unexpected media type")
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")
ErrTypeAssertionFailed = errors.New("storage: failed DatabaseDriver type assertion")
@ -163,4 +163,5 @@ var (
ErrInvalidOutputFormat = errors.New("cli: invalid output format")
ErrFlagValueUnsupported = errors.New("supported values ")
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",
"cacheTablename": "ZotBlobTable",
"repoMetaTablename": "ZotRepoMetadataTable",
"manifestDataTablename": "ZotManifestDataTable",
"imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"versionTablename": "ZotVersion"
}
},

View file

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

2
go.mod
View file

@ -500,7 +500,7 @@ require (
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // 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/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect

View file

@ -143,14 +143,15 @@ func TestCreateCacheDatabaseDriver(t *testing.T) {
endpoint := os.Getenv("DYNAMODBMOCK_ENDPOINT")
conf.Storage.CacheDriver = map[string]interface{}{
"name": "dynamodb",
"endpoint": endpoint,
"region": "us-east-2",
"cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable",
"manifestDataTablename": "ManifestDataTable",
"userDataTablename": "ZotUserDataTable",
"versionTablename": "Version",
"name": "dynamodb",
"endpoint": endpoint,
"region": "us-east-2",
"cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable",
"imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable",
"versionTablename": "Version",
}
driver := storage.CreateCacheDatabaseDriver(conf.Storage.StorageConfig, log)
@ -159,27 +160,29 @@ func TestCreateCacheDatabaseDriver(t *testing.T) {
// negative test cases
conf.Storage.CacheDriver = map[string]interface{}{
"endpoint": endpoint,
"region": "us-east-2",
"cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable",
"manifestDataTablename": "ManifestDataTable",
"userDataTablename": "ZotUserDataTable",
"versionTablename": "Version",
"endpoint": endpoint,
"region": "us-east-2",
"cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable",
"imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable",
"versionTablename": "Version",
}
driver = storage.CreateCacheDatabaseDriver(conf.Storage.StorageConfig, log)
So(driver, ShouldBeNil)
conf.Storage.CacheDriver = map[string]interface{}{
"name": "dummy",
"endpoint": endpoint,
"region": "us-east-2",
"cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable",
"manifestDataTablename": "ManifestDataTable",
"userDataTablename": "ZotUserDataTable",
"versionTablename": "Version",
"name": "dummy",
"endpoint": endpoint,
"region": "us-east-2",
"cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable",
"imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable",
"versionTablename": "Version",
}
driver = storage.CreateCacheDatabaseDriver(conf.Storage.StorageConfig, log)
@ -205,43 +208,45 @@ func TestCreateMetaDBDriver(t *testing.T) {
}
conf.Storage.CacheDriver = map[string]interface{}{
"name": "dummy",
"endpoint": "http://localhost:4566",
"region": "us-east-2",
"cachetablename": "BlobTable",
"repometatablename": "RepoMetadataTable",
"manifestdatatablename": "ManifestDataTable",
"userdatatablename": "UserDatatable",
"name": "dummy",
"endpoint": "http://localhost:4566",
"region": "us-east-2",
"cachetablename": "BlobTable",
"repometatablename": "RepoMetadataTable",
"imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userdatatablename": "UserDatatable",
}
testFunc := func() { _, _ = meta.New(conf.Storage.StorageConfig, log) }
So(testFunc, ShouldPanic)
conf.Storage.CacheDriver = map[string]interface{}{
"name": "dummy",
"endpoint": "http://localhost:4566",
"region": "us-east-2",
"cachetablename": "",
"repometatablename": "RepoMetadataTable",
"manifestdatatablename": "ManifestDataTable",
"userDataTablename": "ZotUserDataTable",
"versiontablename": 1,
"name": "dummy",
"endpoint": "http://localhost:4566",
"region": "us-east-2",
"cachetablename": "",
"repometatablename": "RepoMetadataTable",
"imageMetaTablename": "ZotImageMetaTable",
"repoBlobsInfoTablename": "ZotRepoBlobsInfoTable",
"userDataTablename": "ZotUserDataTable",
"versiontablename": 1,
}
testFunc = func() { _, _ = meta.New(conf.Storage.StorageConfig, log) }
So(testFunc, ShouldPanic)
conf.Storage.CacheDriver = map[string]interface{}{
"name": "dummy",
"endpoint": "http://localhost:4566",
"region": "us-east-2",
"cachetablename": "test",
"repometatablename": "RepoMetadataTable",
"manifestdatatablename": "ManifestDataTable",
"indexdatatablename": "IndexDataTable",
"userdatatablename": "ZotUserDataTable",
"apikeytablename": "APIKeyTable",
"versiontablename": "1",
"name": "dummy",
"endpoint": "http://localhost:4566",
"region": "us-east-2",
"cachetablename": "test",
"repometatablename": "RepoMetadataTable",
"imagemetatablename": "ZotImageMetaTable",
"repoblobsinfotablename": "ZotRepoBlobsInfoTable",
"userdatatablename": "ZotUserDataTable",
"apikeytablename": "APIKeyTable",
"versiontablename": "1",
}
testFunc = func() { _, _ = meta.New(conf.Storage.StorageConfig, log) }
@ -414,16 +419,16 @@ func TestObjectStorageController(t *testing.T) {
conf.Storage.StorageDriver = storageDriverParams
conf.Storage.CacheDriver = map[string]interface{}{
"name": "dynamodb",
"endpoint": os.Getenv("DYNAMODBMOCK_ENDPOINT"),
"region": "us-east-2",
"cachetablename": "test",
"repometatablename": "RepoMetadataTable",
"manifestdatatablename": "ManifestDataTable",
"indexdatatablename": "IndexDataTable",
"userdatatablename": "ZotUserDataTable",
"apikeytablename": "APIKeyTable1",
"versiontablename": "Version",
"name": "dynamodb",
"endpoint": os.Getenv("DYNAMODBMOCK_ENDPOINT"),
"region": "us-east-2",
"cachetablename": "test",
"repometatablename": "RepoMetadataTable",
"imagemetatablename": "ZotImageMetaTable",
"repoblobsinfotablename": "ZotRepoBlobsInfoTable",
"userdatatablename": "ZotUserDataTable",
"apikeytablename": "APIKeyTable1",
"versiontablename": "Version",
}
mockOIDCServer, err := authutils.MockOIDCRun()
@ -7773,6 +7778,8 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
}
func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
ctx := context.Background()
Convey("Make controller", t, func() {
Convey("Garbage collect signatures without subject and manifests without tags", func(c C) {
repoName := "testrepo" //nolint:goconst
@ -7804,7 +7811,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
ctlr.Config.Storage.Dedupe = false
cm := test.NewControllerManager(ctlr)
cm.StartServer()
cm.StartServer() //nolint: contextcheck
cm.WaitServerToBeReady(port)
defer cm.StopServer()
@ -7835,7 +7842,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
// generate a keypair
os.Setenv("COSIGN_PASSWORD", "")
err = generate.GenerateKeyPairCmd(context.TODO(), "", "cosign", nil)
err = generate.GenerateKeyPairCmd(ctx, "", "cosign", nil)
So(err, ShouldBeNil)
image := fmt.Sprintf("localhost:%s/%s@%s", port, repoName, digest.String())
@ -7864,7 +7871,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
So(err, ShouldBeNil)
// sign the image
err = signature.SignWithNotation("good", image, tdir, true)
err = signature.SignWithNotation("good", image, tdir, true) //nolint: contextcheck
So(err, ShouldBeNil)
// get cosign signature manifest
@ -7894,7 +7901,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
So(err, ShouldBeNil)
// make sure both signatures are stored in repodb
repoMeta, err := ctlr.MetaDB.GetRepoMeta(repoName)
repoMeta, err := ctlr.MetaDB.GetRepoMeta(ctx, repoName)
So(err, ShouldBeNil)
sigMeta := repoMeta.Signatures[digest.String()]
@ -7955,7 +7962,7 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
So(err, ShouldBeNil)
// make sure repoDB reference was added
repoMeta, err := ctlr.MetaDB.GetRepoMeta(repoName)
repoMeta, err := ctlr.MetaDB.GetRepoMeta(ctx, repoName)
So(err, ShouldBeNil)
_, ok := repoMeta.Referrers[untaggedManifestDigest.String()]
@ -7984,8 +7991,8 @@ func TestGCSignaturesAndUntaggedManifestsWithMetaDB(t *testing.T) {
err = gc.CleanRepo(repoName)
So(err, ShouldBeNil)
// make sure both signatures are removed from repodb and repo reference for untagged is removed
repoMeta, err = ctlr.MetaDB.GetRepoMeta(repoName)
// make sure both signatures are removed from metaDB and repo reference for untagged is removed
repoMeta, err = ctlr.MetaDB.GetRepoMeta(ctx, repoName)
So(err, ShouldBeNil)
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 {
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 {
response.WriteHeader(http.StatusInternalServerError)

View file

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

View file

@ -29,6 +29,12 @@ const (
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 {
for _, s := range elems {
if v == s {

View file

@ -131,23 +131,23 @@ func TestSignatureUploadAndVerificationAWS(t *testing.T) {
cacheTablename := "BlobTable" + uuid.String()
repoMetaTablename := "RepoMetadataTable" + uuid.String()
manifestDataTablename := "ManifestDataTable" + uuid.String()
versionTablename := "Version" + uuid.String()
indexDataTablename := "IndexDataTable" + uuid.String()
userDataTablename := "UserDataTable" + uuid.String()
apiKeyTablename := "ApiKeyTable" + uuid.String()
imageMetaTablename := "imageMetaTable" + uuid.String()
repoBlobsInfoTablename := "repoBlobsInfoTable" + uuid.String()
cacheDriverParams := map[string]interface{}{
"name": "dynamoDB",
"endpoint": os.Getenv("DYNAMODBMOCK_ENDPOINT"),
"region": "us-east-2",
"cacheTablename": cacheTablename,
"repoMetaTablename": repoMetaTablename,
"manifestDataTablename": manifestDataTablename,
"indexDataTablename": indexDataTablename,
"userDataTablename": userDataTablename,
"apiKeyTablename": apiKeyTablename,
"versionTablename": versionTablename,
"name": "dynamoDB",
"endpoint": os.Getenv("DYNAMODBMOCK_ENDPOINT"),
"region": "us-east-2",
"cacheTablename": cacheTablename,
"repoMetaTablename": repoMetaTablename,
"imageMetaTablename": imageMetaTablename,
"repoBlobsInfoTablename": repoBlobsInfoTablename,
"userDataTablename": userDataTablename,
"apiKeyTablename": apiKeyTablename,
"versionTablename": versionTablename,
}
t.Logf("using dynamo driver options: %v", cacheDriverParams)

View file

@ -5,7 +5,6 @@ package imagetrust
import (
"context"
"encoding/json"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
@ -158,18 +157,13 @@ func IsResourceExistsException(err error) bool {
}
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,
) (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{
MediaType: manifest.MediaType,
Digest: manifestDigest,
Size: int64(len(manifestContent)),
MediaType: imageMeta.MediaType,
Digest: imageMeta.Digest,
Size: imageMeta.Size,
}
if manifestDigest.String() == "" {
@ -190,7 +184,7 @@ func (imgTrustStore *ImageTrustStore) VerifySignature(
func NewTaskGenerator(metaDB mTypes.MetaDB, log log.Logger) scheduler.TaskGenerator {
return &sigValidityTaskGenerator{
repos: []mTypes.RepoMetadata{},
repos: []mTypes.RepoMeta{},
metaDB: metaDB,
repoIndex: -1,
log: log,
@ -198,7 +192,7 @@ func NewTaskGenerator(metaDB mTypes.MetaDB, log log.Logger) scheduler.TaskGenera
}
type sigValidityTaskGenerator struct {
repos []mTypes.RepoMetadata
repos []mTypes.RepoMeta
metaDB mTypes.MetaDB
repoIndex int
done bool
@ -209,7 +203,7 @@ func (gen *sigValidityTaskGenerator) Next() (scheduler.Task, error) {
if len(gen.repos) == 0 {
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
})
if err != nil {
@ -243,18 +237,18 @@ func (gen *sigValidityTaskGenerator) IsReady() bool {
func (gen *sigValidityTaskGenerator) Reset() {
gen.done = false
gen.repoIndex = -1
gen.repos = []mTypes.RepoMetadata{}
gen.repos = []mTypes.RepoMeta{}
gen.log.Info().Msg("finished resetting task generator for updating signatures validity")
}
type validityTask struct {
metaDB mTypes.MetaDB
repo mTypes.RepoMetadata
repo mTypes.RepoMeta
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}
}

View file

@ -7,6 +7,8 @@ import (
"time"
godigest "github.com/opencontainers/go-digest"
mTypes "zotregistry.io/zot/pkg/meta/types"
)
func NewLocalImageTrustStore(dir string) (*imageTrustDisabled, error) {
@ -20,7 +22,7 @@ func NewAWSImageTrustStore(region, endpoint string) (*imageTrustDisabled, error)
type imageTrustDisabled struct{}
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,
) (string, time.Time, bool, error) {
return "", time.Time{}, false, nil

View file

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

View file

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

View file

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

View file

@ -4,21 +4,19 @@ package convert_test
import (
"context"
"encoding/json"
"errors"
"testing"
"time"
"github.com/99designs/gqlgen/graphql"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"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/pagination"
"zotregistry.io/zot/pkg/log"
"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"
@ -27,187 +25,6 @@ import (
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) {
Convey("Image summary is the first image checked for the repo", t, func() {
before := time.Time{}
@ -300,14 +117,25 @@ func TestLabels(t *testing.T) {
func TestGetSignaturesInfo(t *testing.T) {
Convey("Test get signatures info - cosign", t, func() {
indexDigest := godigest.FromString("123")
repoMeta := mTypes.RepoMetadata{
Signatures: map[string]mTypes.ManifestSignatures{string(indexDigest): {"cosign": []mTypes.SignatureInfo{{
LayersInfo: []mTypes.LayerInfo{{LayerContent: []byte{}, LayerDigest: "", SignatureKey: "", Signer: "author"}},
}}}},
digest := godigest.FromString("dig")
signatures := map[string]mTypes.ManifestSignatures{
digest.String(): {
"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[0].Author, ShouldEqual, "author")
So(*signaturesSummary[0].IsTrusted, ShouldEqual, true)
@ -315,22 +143,26 @@ func TestGetSignaturesInfo(t *testing.T) {
})
Convey("Test get signatures info - notation", t, func() {
indexDigest := godigest.FromString("123")
repoMeta := mTypes.RepoMetadata{
Signatures: map[string]mTypes.ManifestSignatures{string(indexDigest): {"notation": []mTypes.SignatureInfo{{
LayersInfo: []mTypes.LayerInfo{
digest := godigest.FromString("dig")
signatures := map[string]mTypes.ManifestSignatures{
digest.String(): {
"notation": []mTypes.SignatureInfo{
{
LayerContent: []byte{},
LayerDigest: "",
SignatureKey: "",
Signer: "author",
Date: time.Now().AddDate(0, 0, -1),
LayersInfo: []mTypes.LayerInfo{
{
LayerContent: []byte{},
LayerDigest: "",
SignatureKey: "",
Signer: "author",
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[0].Author, ShouldEqual, "author")
So(*signaturesSummary[0].IsTrusted, ShouldEqual, false)
@ -422,6 +254,18 @@ func ref[T any](val T) *T {
func TestPaginatedConvert(t *testing.T) {
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 (
badBothImage = CreateImageWith().DefaultLayers().ImageConfig(
ispec.Image{Platform: ispec.Platform{OS: "bad-os", Architecture: "bad-arch"}}).Build()
@ -432,8 +276,9 @@ func TestPaginatedConvert(t *testing.T) {
goodImage = CreateImageWith().DefaultLayers().ImageConfig(
ispec.Image{Platform: ispec.Platform{OS: "good-os", Architecture: "good-arch"}}).Build()
randomImage1 = CreateRandomImage()
randomImage2 = CreateRandomImage()
randomImage1 = CreateRandomImage()
randomImage2 = CreateRandomImage()
signatureDigest = godigest.FromString("signature")
badMultiArch = CreateMultiarchWith().Images(
[]Image{badBothImage, badOsImage, badArchImage, randomImage1}).Build()
@ -441,14 +286,14 @@ func TestPaginatedConvert(t *testing.T) {
[]Image{badOsImage, badArchImage, randomImage2, goodImage}).Build()
)
reposMeta, manifestMetaMap, indexDataMap := ociutils.GetMetadataForRepos(
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB,
ociutils.Repo{
Name: "repo1-only-images",
Images: []ociutils.RepoImage{
{Image: goodImage, Tag: "goodImage"},
{Image: badOsImage, Tag: "badOsImage"},
{Image: badArchImage, Tag: "badArchImage"},
{Image: badBothImage, Tag: "badBothImage"},
{Image: goodImage, Reference: "goodImage"},
{Image: badOsImage, Reference: "badOsImage"},
{Image: badArchImage, Reference: "badArchImage"},
{Image: badBothImage, Reference: "badBothImage"},
},
IsBookmarked: true,
IsStarred: true,
@ -456,9 +301,9 @@ func TestPaginatedConvert(t *testing.T) {
ociutils.Repo{
Name: "repo2-only-bad-images",
Images: []ociutils.RepoImage{
{Image: randomImage1, Tag: "randomImage1"},
{Image: randomImage2, Tag: "randomImage2"},
{Image: badBothImage, Tag: "badBothImage"},
{Image: randomImage1, Reference: "randomImage1"},
{Image: randomImage2, Reference: "randomImage2"},
{Image: badBothImage, Reference: "badBothImage"},
},
IsBookmarked: true,
IsStarred: true,
@ -466,8 +311,8 @@ func TestPaginatedConvert(t *testing.T) {
ociutils.Repo{
Name: "repo3-only-multiarch",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: badMultiArch, Tag: "badMultiArch"},
{MultiarchImage: goodMultiArch, Tag: "goodMultiArch"},
{MultiarchImage: badMultiArch, Reference: "badMultiArch"},
{MultiarchImage: goodMultiArch, Reference: "goodMultiArch"},
},
IsBookmarked: true,
IsStarred: true,
@ -475,44 +320,56 @@ func TestPaginatedConvert(t *testing.T) {
ociutils.Repo{
Name: "repo4-not-bookmarked-or-starred",
Images: []ociutils.RepoImage{
{Image: goodImage, Tag: "goodImage"},
{Image: goodImage, Reference: "goodImage"},
},
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: goodMultiArch, Tag: "goodMultiArch"},
{MultiarchImage: goodMultiArch, Reference: "goodMultiArch"},
},
},
ociutils.Repo{
Name: "repo5-signed",
Images: []ociutils.RepoImage{
{Image: goodImage, Tag: "goodImage"}, // is fake signed by the image below
{Image: CreateFakeTestSignature(goodImage.DescriptorRef())},
{Image: goodImage, Reference: "goodImage"}, // is fake signed by the image below
},
Signatures: map[string]mTypes.ManifestSignatures{
goodImage.DigestStr(): ociutils.GetFakeSignatureInfo(signatureDigest.String()),
},
},
)
if err != nil {
t.FailNow()
}
skipCVE := convert.SkipQGLField{Vulnerabilities: true}
Convey("PaginatedRepoMeta2RepoSummaries filtering and sorting", t, func() {
// 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(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
ctx, repoMetaList, imageMeta,
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
IsBookmarked: ref(true),
IsStarred: ref(true),
},
pagination.PageInput{SortBy: pagination.AlphabeticAsc},
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 2)
So(*reposSum[0].Name, ShouldResemble, "repo1-only-images")
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)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
ctx, repoMetaList, imageMeta,
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
@ -520,18 +377,18 @@ func TestPaginatedConvert(t *testing.T) {
IsStarred: ref(true),
HasToBeSigned: ref(true),
},
pagination.PageInput{SortBy: pagination.AlphabeticAsc},
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
ctx, repoMetaList, imageMeta,
mTypes.Filter{
HasToBeSigned: ref(true),
},
pagination.PageInput{SortBy: pagination.AlphabeticAsc},
pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 1)
@ -540,8 +397,8 @@ func TestPaginatedConvert(t *testing.T) {
// no filter
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticAsc},
ctx, repoMetaList, imageMeta,
mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticAsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 5)
@ -554,8 +411,8 @@ func TestPaginatedConvert(t *testing.T) {
// no filter opposite sorting
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticDsc},
ctx, repoMetaList, imageMeta,
mTypes.Filter{}, pagination.PageInput{SortBy: pagination.AlphabeticDsc}, mocks.CveInfoMock{}, skipCVE,
)
So(err, ShouldBeNil)
So(len(reposSum), ShouldEqual, 5)
@ -568,14 +425,14 @@ func TestPaginatedConvert(t *testing.T) {
// add pagination
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
ctx, repoMetaList, imageMeta,
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
IsBookmarked: 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(len(reposSum), ShouldEqual, 1)
@ -584,14 +441,14 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.TotalCount, ShouldEqual, 2)
reposSum, pageInfo, err = convert.PaginatedRepoMeta2RepoSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
ctx, repoMetaList, imageMeta,
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
IsBookmarked: 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(len(reposSum), ShouldEqual, 1)
@ -601,8 +458,11 @@ func TestPaginatedConvert(t *testing.T) {
})
Convey("PaginatedRepoMeta2ImageSummaries filtering and sorting", t, func() {
imgSum, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, mTypes.AcceptAllImageMeta)
So(err, ShouldBeNil)
imgSum, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
@ -624,8 +484,8 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.ItemCount, ShouldEqual, 5)
// add page of size 2
imgSum, pageInfo, err = convert.PaginatedRepoMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
@ -642,8 +502,8 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.TotalCount, ShouldEqual, 5)
// next page
imgSum, pageInfo, err = convert.PaginatedRepoMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
@ -660,8 +520,8 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.TotalCount, ShouldEqual, 5)
// last page
imgSum, pageInfo, err = convert.PaginatedRepoMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
@ -676,8 +536,8 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.TotalCount, ShouldEqual, 5)
// has to be signed
imgSum, pageInfo, err = convert.PaginatedRepoMeta2ImageSummaries(
ctx, reposMeta, manifestMetaMap, indexDataMap, skipCVE, mocks.CveInfoMock{},
imgSum, pageInfo, err = convert.PaginatedFullImageMeta2ImageSummaries(
ctx, fullImageMetaList, skipCVE, mocks.CveInfoMock{},
mTypes.Filter{
Os: []*string{ref("good-os")},
Arch: []*string{ref("good-arch")},
@ -697,6 +557,16 @@ func TestIndexAnnotations(t *testing.T) {
Convey("Test ImageIndex2ImageSummary annotations logic", t, func() {
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{
ispec.AnnotationDescription: "ConfigDescription",
ispec.AnnotationLicenses: "ConfigLicenses",
@ -746,17 +616,22 @@ func TestIndexAnnotations(t *testing.T) {
[]Image{imageWithManifestAndConfigAnnotations},
).Annotations(indexAnnotations).Build()
repoMeta, manifestMetadata, indexData := ociutils.GetMetadataForRepos(ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithAnnotations, Tag: "tag"},
},
})
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB,
ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{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],
indexData[digest.String()], manifestMetadata)
imageSummary, _, err := convert.ImageIndex2ImageSummary(ctx, convert.GetFullImageMeta("tag", repoMeta,
imageMeta[indexWithAnnotations.DigestStr()]))
So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "IndexDescription")
So(*imageSummary.Licenses, ShouldResemble, "IndexLicenses")
@ -766,19 +641,30 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Vendor, ShouldResemble, "IndexVendor")
So(*imageSummary.Authors, ShouldResemble, "IndexAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
// --------------------------------------------------------
indexWithManifestAndConfigAnnotations := CreateMultiarchWith().Images(
[]Image{imageWithManifestAndConfigAnnotations, CreateRandomImage(), CreateRandomImage()},
).Build()
repoMeta, manifestMetadata, indexData = ociutils.GetMetadataForRepos(ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{{MultiarchImage: indexWithManifestAndConfigAnnotations}},
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithManifestAndConfigAnnotations, Reference: "tag"},
},
})
digest = indexWithManifestAndConfigAnnotations.Digest()
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest,
repoMeta[0], indexData[digest.String()], manifestMetadata)
digest := indexWithManifestAndConfigAnnotations.DigestStr()
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(*imageSummary.Description, ShouldResemble, "ManifestDescription")
So(*imageSummary.Licenses, ShouldResemble, "ManifestLicenses")
@ -787,19 +673,31 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Documentation, ShouldResemble, "ManifestDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "ManifestVendor")
So(*imageSummary.Authors, ShouldResemble, "ManifestAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
// --------------------------------------------------------
indexWithConfigAnnotations := CreateMultiarchWith().Images(
[]Image{imageWithConfigAnnotations, CreateRandomImage(), CreateRandomImage()},
).Build()
repoMeta, manifestMetadata, indexData = ociutils.GetMetadataForRepos(ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{{MultiarchImage: indexWithConfigAnnotations, Tag: "tag"}},
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithConfigAnnotations, Reference: "tag"},
},
})
digest = indexWithConfigAnnotations.Digest()
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest,
repoMeta[0], indexData[digest.String()], manifestMetadata)
digest = indexWithConfigAnnotations.DigestStr()
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(*imageSummary.Description, ShouldResemble, "ConfigDescription")
So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses")
@ -808,6 +706,9 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Documentation, ShouldResemble, "ConfigDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "ConfigVendor")
So(*imageSummary.Authors, ShouldResemble, "ConfigAuthors")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
//--------------------------------------------------------
indexWithMixAnnotations := CreateMultiarchWith().Images(
@ -834,14 +735,23 @@ func TestIndexAnnotations(t *testing.T) {
},
).Build()
repoMeta, manifestMetadata, indexData = ociutils.GetMetadataForRepos(ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{{MultiarchImage: indexWithMixAnnotations, Tag: "tag"}},
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithMixAnnotations, Reference: "tag"},
},
})
digest = indexWithMixAnnotations.Digest()
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest,
repoMeta[0], indexData[digest.String()], manifestMetadata)
digest = indexWithMixAnnotations.DigestStr()
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(*imageSummary.Description, ShouldResemble, "ConfigDescription")
So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses")
@ -851,17 +761,28 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Documentation, ShouldResemble, "IndexDocumentation")
So(*imageSummary.Source, ShouldResemble, "IndexSource")
err = metaDB.ResetDB()
So(err, ShouldBeNil)
//--------------------------------------------------------
indexWithNoAnnotations := CreateRandomMultiarch()
repoMeta, manifestMetadata, indexData = ociutils.GetMetadataForRepos(ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{{MultiarchImage: indexWithNoAnnotations, Tag: "tag"}},
ctx, err = ociutils.InitializeTestMetaDB(ctx, metaDB, ociutils.Repo{
Name: "repo",
MultiArchImages: []ociutils.RepoMultiArchImage{
{MultiarchImage: indexWithNoAnnotations, Reference: "tag"},
},
})
digest = indexWithNoAnnotations.Digest()
So(err, ShouldBeNil)
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest,
repoMeta[0], indexData[digest.String()], manifestMetadata)
digest = indexWithNoAnnotations.DigestStr()
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(*imageSummary.Description, ShouldBeBlank)
So(*imageSummary.Licenses, ShouldBeBlank)
@ -870,94 +791,8 @@ func TestIndexAnnotations(t *testing.T) {
So(*imageSummary.Title, ShouldBeBlank)
So(*imageSummary.Documentation, ShouldBeBlank)
So(*imageSummary.Source, ShouldBeBlank)
})
}
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)
err = metaDB.ResetDB()
So(err, ShouldBeNil)
})
}

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"
)
// 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 {
layers := make([]*gql_generated.LayerSummary, 0, len(manifestContent.Layers))

View file

@ -1,7 +1,7 @@
package cveinfo
import (
"encoding/json"
"context"
"sort"
"strings"
"time"
@ -9,6 +9,7 @@ import (
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"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) {
imgList := make([]cvemodel.TagInfo, 0)
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(repo)
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(context.Background(), repo)
if err != nil {
cveinfo.Log.Error().Err(err).Str("repository", repo).Str("cve-id", cveID).
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) {
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(repo)
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(context.Background(), repo)
if err != nil {
cveinfo.Log.Error().Err(err).Str("repository", repo).Str("cve-id", cveID).
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
}
indexData, err := metaDB.GetIndexData(indexDigest)
indexData, err := metaDB.GetImageMeta(indexDigest)
if err != nil {
return ispec.Index{}, err
}
var indexContent ispec.Index
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
return ispec.Index{}, err
if indexData.Index == nil {
return ispec.Index{}, zerr.ErrUnexpectedMediaType
}
return indexContent, nil
return *indexData.Index, nil
}
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
}
manifestData, err := metaDB.GetManifestData(manifestDigest)
manifestData, err := metaDB.GetImageMeta(manifestDigest)
if err != nil {
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.
err = json.Unmarshal(manifestData.ConfigBlob, &configContent)
return configContent, manifestDigest, err
return manifestData.Manifests[0].Config, manifestDigest, err
}
func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE string, pageFinder *CvePageFinder) {

View file

@ -5,6 +5,7 @@
package cveinfo_test
import (
"context"
"encoding/json"
"fmt"
"io"
@ -385,8 +386,8 @@ func TestImageFormat(t *testing.T) {
log := log.NewLogger("debug", "")
metaDB := &mocks.MetaDBMock{
GetRepoMetaFn: func(repo string) (mTypes.RepoMetadata, error) {
return mTypes.RepoMetadata{
GetRepoMetaFn: func(ctx context.Context, repo string) (mTypes.RepoMeta, error) {
return mTypes.RepoMeta{
Tags: map[string]mTypes.Descriptor{
"tag": {
MediaType: ispec.MediaTypeImageIndex,
@ -395,8 +396,12 @@ func TestImageFormat(t *testing.T) {
},
}, nil
},
GetIndexDataFn: func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{IndexBlob: []byte(`{}`)}, nil
GetImageMetaFn: func(digest godigest.Digest) (mTypes.ImageMeta, error) {
return mTypes.ImageMeta{
MediaType: ispec.MediaTypeImageIndex,
Digest: godigest.FromString("digest"),
Index: &ispec.Index{},
}, nil
},
}
storeController := storage.StoreController{
@ -765,73 +770,32 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
image11 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2008, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta11 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference(repo1, "0.1.0", image11.AsImageMeta())
So(err, ShouldBeNil)
image12 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta12 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference(repo1, "1.0.0", image12.AsImageMeta())
So(err, ShouldBeNil)
image13 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta13 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference(repo1, "1.1.0", image13.AsImageMeta())
So(err, ShouldBeNil)
image14 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2011, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta14 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference(repo1, "1.0.1", image14.AsImageMeta())
So(err, ShouldBeNil)
// Create metadb data for scannable image with no vulnerabilities
image61 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2016, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta61 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference(repo6, "1.0.0", image61.AsImageMeta())
So(err, ShouldBeNil)
// 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}),
}}).ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta21 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference(repo2, "1.0.0", image21.AsImageMeta())
So(err, ShouldBeNil)
// Create metadb data for invalid images/negative tests
manifestBlob31 := []byte("invalid manifest blob")
So(err, ShouldBeNil)
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)
image := CreateRandomImage()
err = metaDB.SetRepoReference(repo3, "invalid-manifest", image.AsImageMeta())
So(err, ShouldBeNil)
image41 := CreateImageWith().DefaultLayers().
CustomConfigBlob([]byte("invalid config blob"), ispec.MediaTypeImageConfig).Build()
repoMeta41 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference(repo4, "invalid-config", image41.AsImageMeta())
So(err, ShouldBeNil)
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)
// Create metadb data for scannable image which errors during scan
image71 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2000, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta71 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference(repo7, "1.0.0", image71.AsImageMeta())
So(err, ShouldBeNil)
// create multiarch image with vulnerabilities
multiarchImage := CreateRandomMultiarch()
err = metaDB.SetIndexData(
multiarchImage.IndexDescriptor.Digest,
mTypes.IndexData{IndexBlob: multiarchImage.IndexDescriptor.Data},
)
err = metaDB.SetRepoReference(repoMultiarch, multiarchImage.Images[0].DigestStr(),
multiarchImage.Images[0].AsImageMeta())
So(err, ShouldBeNil)
err = metaDB.SetManifestData(
multiarchImage.Images[0].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[0].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[0].ConfigDescriptor.Data,
err = metaDB.SetRepoReference(repoMultiarch, multiarchImage.Images[1].DigestStr(),
multiarchImage.Images[1].AsImageMeta())
So(err, ShouldBeNil)
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)
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
// This is normally done in MetaDB, but we want to verify
// the whole flow, including MetaDB
@ -966,18 +883,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
image21Media := image21.ManifestDescriptor.MediaType
image21Name := repo2 + ":1.0.0"
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()
image61Media := image61.ManifestDescriptor.MediaType
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
imageDir, inputTag := repo, reference
repoMeta, err := metaDB.GetRepoMeta(imageDir)
repoMeta, err := metaDB.GetRepoMeta(context.Background(), imageDir)
if err != nil {
return false, err
}
@ -1174,19 +1079,12 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
return false, err
}
manifestData, err := metaDB.GetManifestData(manifestDigest)
manifestData, err := metaDB.GetImageMeta(manifestDigest)
if err != nil {
return false, err
}
var manifestContent ispec.Manifest
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
return false, zerr.ErrScanNotSupported
}
for _, imageLayer := range manifestContent.Layers {
for _, imageLayer := range manifestData.Manifests[0].Manifest.Layers {
switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
@ -1203,12 +1101,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
if repo == repo2 && digest == image21Digest {
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 {
return false, zerr.ErrRepoMetaNotFound
}
@ -1295,20 +1187,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(pageInfo.ItemCount, 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
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo7, "1.0.0", "", pageInput)
So(err, ShouldEqual, ErrFailedScan)
@ -1316,6 +1194,13 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(pageInfo.ItemCount, 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
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo100, "1.0.0", "", pageInput)
So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
@ -1364,24 +1249,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.Count, ShouldEqual, 0)
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
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo5, image71Digest, image71Media)
So(err, ShouldBeNil)
@ -1430,16 +1297,6 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(err, ShouldBeNil)
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
// but we can't access their data
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) {
Convey("Errors", t, func() {
storeController := storage.StoreController{}

View file

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

View file

@ -4,8 +4,6 @@ import (
"context"
"sync"
godigest "github.com/opencontainers/go-digest"
"zotregistry.io/zot/pkg/log"
mTypes "zotregistry.io/zot/pkg/meta/types"
reqCtx "zotregistry.io/zot/pkg/requestcontext"
@ -43,13 +41,13 @@ type scanTaskGenerator struct {
}
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
// An index scan aggregates results of manifest scans
// If at least one of its manifests can be scanned,
// the index and its tag will be returned by the caller function too
repoName := repoMeta.Name
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String()
manifestDigest := imageMeta.Digest.String()
if gen.isScheduled(manifestDigest) {
// We skip this manifest as it has already scheduled
@ -121,18 +119,18 @@ func (gen *scanTaskGenerator) Next() (scheduler.Task, error) {
userAc.SetIsAdmin(true)
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
reposMeta, _, _, err := gen.metaDB.FilterTags(ctx, gen.getMatcherFunc())
imageMeta, err := gen.metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, gen.getMatcherFunc())
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
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
if len(reposMeta) == 0 {
if len(imageMeta) == 0 {
gen.log.Info().Msg("Scheduled CVE scan: finished for available images")
gen.done = true
@ -140,23 +138,14 @@ func (gen *scanTaskGenerator) Next() (scheduler.Task, error) {
return nil, nil
}
// Since reposMeta will always contain just unscanned images we can pick
// any repo and any tag out of the resulting matches
repoMeta := reposMeta[0]
var digest string
// Pick any tag
for _, descriptor := range repoMeta.Tags {
digest = descriptor.Digest
break
}
// Since imageMeta will always contain just un-scanned images we can pick
// any image out of the resulting matches
digest := imageMeta[0].Digest.String()
// Mark the digest as scheduled so it is skipped on next generator run
gen.setScheduled(digest, true)
return newScanTask(gen, repoMeta.Name, digest), nil
return newScanTask(gen, imageMeta[0].Repo, digest), nil
}
func (gen *scanTaskGenerator) IsDone() bool {

View file

@ -5,7 +5,6 @@ package cveinfo_test
import (
"context"
"encoding/json"
"errors"
"io"
"os"
@ -69,77 +68,38 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
metaDB, err := boltdb.New(boltDriver, log.NewLogger("debug", ""))
So(err, ShouldBeNil)
// Refactor Idea: We can use InitializeTestMetaDB
// Create metadb data for scannable image with vulnerabilities
image11 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2008, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta11 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference("repo1", "0.1.0", image11.AsImageMeta())
So(err, ShouldBeNil)
image12 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta12 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference("repo1", "1.0.0", image12.AsImageMeta())
So(err, ShouldBeNil)
image13 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta13 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference("repo1", "1.1.0", image13.AsImageMeta())
So(err, ShouldBeNil)
image14 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2011, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta14 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference("repo1", "1.0.1", image14.AsImageMeta())
So(err, ShouldBeNil)
// Create metadb data for scannable image with no vulnerabilities
image61 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2016, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta61 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference("repo6", "1.0.0", image61.AsImageMeta())
So(err, ShouldBeNil)
// 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}),
}}).ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta21 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference("repo2", "1.0.0", image21.AsImageMeta())
So(err, ShouldBeNil)
// Create metadb data for invalid images/negative tests
manifestBlob31 := []byte("invalid manifest blob")
So(err, ShouldBeNil)
img := CreateRandomImage()
digest31 := img.Digest()
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)
err = metaDB.SetRepoReference("repo3", "invalid-manifest", img.AsImageMeta())
So(err, ShouldBeNil)
image41 := CreateImageWith().DefaultLayers().
CustomConfigBlob([]byte("invalid config blob"), ispec.MediaTypeImageConfig).Build()
repoMeta41 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference("repo4", "invalid-config", image41.AsImageMeta())
So(err, ShouldBeNil)
digest51 := godigest.FromString("abc8")
err = metaDB.SetRepoReference("repo5", "nonexitent-manifest", digest51, ispec.MediaTypeImageManifest)
image15 := CreateRandomMultiarch()
digest51 := image15.Digest()
err = metaDB.SetRepoReference("repo5", "nonexitent-manifests-for-multiarch", image15.AsImageMeta())
So(err, ShouldBeNil)
// Create metadb data for scannable image which errors during scan
image71 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2000, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta71 := mTypes.ManifestMetadata{
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)
err = metaDB.SetRepoReference("repo7", "1.0.0", image71.AsImageMeta())
So(err, ShouldBeNil)
// Create multiarch image with vulnerabilities
multiarchImage := CreateRandomMultiarch()
err = metaDB.SetIndexData(
multiarchImage.IndexDescriptor.Digest,
mTypes.IndexData{IndexBlob: multiarchImage.IndexDescriptor.Data},
)
err = metaDB.SetRepoReference(repoIndex, multiarchImage.Images[0].DigestStr(),
multiarchImage.Images[0].AsImageMeta())
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)
err = metaDB.SetManifestData(
multiarchImage.Images[0].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[0].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[0].ConfigDescriptor.Data,
err = metaDB.SetRepoReference(repoIndex, "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()},
"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)
// 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()
image41Name := "repo4:invalid-config"
imageMap[image41Name] = image41Digest
image51Name := "repo5:nonexitent-manifest"
image51Name := "repo5:nonexitent-manifest-for-multiarch"
imageMap[image51Name] = digest51.String()
image61Digest := image61.ManifestDescriptor.Digest.String()
image61Name := "repo6:1.0.0"
@ -296,7 +210,7 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
imageMap[indexM3Name] = indexM3Digest
// Initialize a test CVE cache
cache := cvecache.NewCveCache(10, logger)
cache := cvecache.NewCveCache(20, logger)
// MetaDB loaded with initial data, now mock the 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
imageDir, inputTag := repo, reference
repoMeta, err := metaDB.GetRepoMeta(imageDir)
repoMeta, err := metaDB.GetRepoMeta(context.Background(), imageDir)
if err != nil {
return false, err
}
@ -463,19 +377,12 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
return false, err
}
manifestData, err := metaDB.GetManifestData(manifestDigest)
manifestData, err := metaDB.GetImageMeta(manifestDigest)
if err != nil {
return false, err
}
var manifestContent ispec.Manifest
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
return false, zerr.ErrScanNotSupported
}
for _, imageLayer := range manifestContent.Layers {
for _, imageLayer := range manifestData.Manifests[0].Manifest.Layers {
switch imageLayer.MediaType {
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
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(found, ShouldBeTrue)
@ -546,13 +453,12 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
t.Log("expecting " + image + " " + digestStr + " to be present in cache")
So(scanner.IsResultCached(digestStr), ShouldBeTrue)
} 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")
So(scanner.IsResultCached(digestStr), ShouldBeFalse)
}
}
// Make sure the scanner generator is catching the metadb error for repo5:nonexitent-manifest
found, err = test.ReadLogFileAndSearchString(logPath,
"Scheduled CVE scan: error while obtaining repo metadata", 20*time.Second)
So(err, ShouldBeNil)

View file

@ -2,7 +2,6 @@ package trivy
import (
"context"
"encoding/json"
"fmt"
"os"
"path"
@ -26,7 +25,6 @@ import (
cvecache "zotregistry.io/zot/pkg/extensions/search/cve/cache"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/log"
mcommon "zotregistry.io/zot/pkg/meta/common"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage"
)
@ -193,7 +191,7 @@ func (scanner Scanner) IsImageFormatScannable(repo, ref string) (bool, error) {
)
if zcommon.IsTag(ref) {
imgDescriptor, err := mcommon.GetImageDescriptor(scanner.metaDB, repo, ref)
imgDescriptor, err := getImageDescriptor(scanner.metaDB, repo, ref)
if err != nil {
return false, err
}
@ -203,7 +201,7 @@ func (scanner Scanner) IsImageFormatScannable(repo, ref string) (bool, error) {
} else {
var found bool
found, mediaType = mcommon.FindMediaTypeForDigest(scanner.metaDB, godigest.Digest(ref))
found, mediaType = findMediaTypeForDigest(scanner.metaDB, godigest.Digest(ref))
if !found {
return false, zerr.ErrManifestNotFound
}
@ -224,7 +222,7 @@ func (scanner Scanner) IsImageMediaScannable(repo, digestStr, mediaType string)
return ok, nil
case ispec.MediaTypeImageIndex:
ok, err := scanner.isIndexScanable(digestStr)
ok, err := scanner.isIndexScannable(digestStr)
if err != nil {
return ok, fmt.Errorf("image '%s' %w", image, err)
}
@ -240,21 +238,16 @@ func (scanner Scanner) isManifestScanable(digestStr string) (bool, error) {
return true, nil
}
manifestData, err := scanner.metaDB.GetManifestData(godigest.Digest(digestStr))
manifestData, err := scanner.metaDB.GetImageMeta(godigest.Digest(digestStr))
if err != nil {
return false, err
}
var manifestContent ispec.Manifest
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
scanner.log.Error().Err(err).Msg("unable to unmashal manifest blob")
return false, zerr.ErrScanNotSupported
if manifestData.MediaType != ispec.MediaTypeImageManifest {
return false, zerr.ErrUnexpectedMediaType
}
for _, imageLayer := range manifestContent.Layers {
for _, imageLayer := range manifestData.Manifests[0].Manifest.Layers {
switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
continue
@ -266,34 +259,54 @@ func (scanner Scanner) isManifestScanable(digestStr string) (bool, error) {
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 {
return true, nil
}
indexData, err := scanner.metaDB.GetIndexData(godigest.Digest(digestStr))
indexData, err := scanner.metaDB.GetImageMeta(godigest.Digest(digestStr))
if err != nil {
return false, err
}
var indexContent ispec.Index
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
return false, err
if indexData.MediaType != ispec.MediaTypeImageIndex || indexData.Index == nil {
return false, zerr.ErrUnexpectedMediaType
}
indexContent := *indexData.Index
if len(indexContent.Manifests) == 0 {
return true, nil
}
for _, manifest := range indexContent.Manifests {
isScannable, err := scanner.isManifestScanable(manifest.Digest.String())
for _, manifest := range indexData.Manifests {
isScannable, err := scanner.isManifestDataScannable(manifest)
if err != nil {
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 {
return true, nil
}
@ -323,7 +336,7 @@ func (scanner Scanner) ScanImage(image string) (map[string]cvemodel.CVE, error)
digest = ref
if isTag {
imgDescriptor, err := mcommon.GetImageDescriptor(scanner.metaDB, repo, ref)
imgDescriptor, err := getImageDescriptor(scanner.metaDB, repo, ref)
if err != nil {
return map[string]cvemodel.CVE{}, err
}
@ -333,7 +346,7 @@ func (scanner Scanner) ScanImage(image string) (map[string]cvemodel.CVE, error)
} else {
var found bool
found, mediaType = mcommon.FindMediaTypeForDigest(scanner.metaDB, godigest.Digest(ref))
found, mediaType = findMediaTypeForDigest(scanner.metaDB, godigest.Digest(ref))
if !found {
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
}
indexData, err := scanner.metaDB.GetIndexData(godigest.Digest(digest))
indexData, err := scanner.metaDB.GetImageMeta(godigest.Digest(digest))
if err != nil {
return map[string]cvemodel.CVE{}, err
}
var indexContent ispec.Index
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
if err != nil {
return map[string]cvemodel.CVE{}, err
if indexData.Index == nil {
return map[string]cvemodel.CVE{}, zerr.ErrUnexpectedMediaType
}
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 {
manifestCveIDMap, err := scanner.scanManifest(repo, manifest.Digest.String())
if err != nil {
@ -567,6 +577,31 @@ func (scanner Scanner) checkDBPresence() error {
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 {
trivySeverity, _ := dbTypes.NewSeverity(detectedSeverity)

View file

@ -22,7 +22,7 @@ import (
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta"
"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/imagestore"
"zotregistry.io/zot/pkg/storage/local"
@ -288,114 +288,31 @@ func TestImageScannable(t *testing.T) {
// Create metadb data for scannable image
timeStamp := time.Date(2008, 1, 1, 12, 0, 0, 0, time.UTC)
validConfigBlob, err := json.Marshal(ispec.Image{
validConfig := ispec.Image{
Created: &timeStamp,
})
if err != nil {
panic(err)
}
validManifestBlob, err := json.Marshal(ispec.Manifest{
Config: ispec.Descriptor{
MediaType: ispec.MediaTypeImageConfig,
Size: 0,
Digest: godigest.FromBytes(validConfigBlob),
},
Layers: []ispec.Descriptor{
{
MediaType: ispec.MediaTypeImageLayerGzip,
Size: 0,
Digest: godigest.NewDigestFromEncoded(godigest.SHA256, "digest"),
},
},
})
if err != nil {
panic(err)
}
validImage := CreateImageWith().
Layers([]Layer{{
MediaType: ispec.MediaTypeImageLayerGzip,
Digest: ispec.DescriptorEmptyJSON.Digest,
Blob: ispec.DescriptorEmptyJSON.Data,
}}).ImageConfig(validConfig).Build()
validRepoMeta := mTypes.ManifestData{
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)
err = metaDB.SetRepoReference("repo1", "valid", validImage.AsImageMeta())
if err != nil {
panic(err)
}
// Create MetaDB data for manifest with unscannable layers
manifestBlobUnscannableLayer, err := json.Marshal(ispec.Manifest{
Config: ispec.Descriptor{
MediaType: ispec.MediaTypeImageConfig,
Size: 0,
Digest: godigest.FromBytes(validConfigBlob),
},
Layers: []ispec.Descriptor{
{
MediaType: "unscannable_media_type",
Size: 0,
Digest: godigest.NewDigestFromEncoded(godigest.SHA256, "digest"),
},
},
})
if err != nil {
panic(err)
}
imageWithUnscannableLayer := CreateImageWith().
Layers([]Layer{{
MediaType: "unscannable_media_type",
Digest: ispec.DescriptorEmptyJSON.Digest,
Blob: ispec.DescriptorEmptyJSON.Data,
}}).ImageConfig(validConfig).Build()
repoMetaUnscannableLayer := mTypes.ManifestData{
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)
err = metaDB.SetRepoReference("repo1", "unscannable-layer", imageWithUnscannableLayer.AsImageMeta())
if err != nil {
panic(err)
}
@ -423,18 +340,6 @@ func TestImageScannable(t *testing.T) {
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() {
result, err := scanner.IsImageFormatScannable("repo1", "invalid-digest")
So(err, ShouldNotBeNil)
@ -523,14 +428,14 @@ func TestIsIndexScanable(t *testing.T) {
scanner.cache.Add("digest", make(map[string]model.CVE))
found, err := scanner.isIndexScanable("digest")
found, err := scanner.isIndexScannable("digest")
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
})
})
}
func TestScanIndexErrors(t *testing.T) {
func TestIsIndexScannableErrors(t *testing.T) {
Convey("Errors", t, func() {
storeController := storage.StoreController{}
storeController.DefaultStore = mocks.MockedImageStore{}
@ -538,107 +443,22 @@ func TestScanIndexErrors(t *testing.T) {
metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "")
Convey("GetIndexData fails", func() {
metaDB.GetIndexDataFn = func(indexDigest godigest.Digest) (mTypes.IndexData, error) {
return mTypes.IndexData{}, godigest.ErrDigestUnsupported
Convey("all manifests of a index are not scannable", func() {
unscannableLayer := []Layer{{MediaType: "unscannable-layer-type", Digest: godigest.FromString("123")}}
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)
_, 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")
ok, err := scanner.isIndexScannable(multiarch.DigestStr())
So(err, ShouldBeNil)
So(ok, ShouldBeFalse)
})

View file

@ -11,7 +11,6 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
extconf "zotregistry.io/zot/pkg/extensions/config"
@ -20,13 +19,11 @@ import (
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta"
"zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/local"
. "zotregistry.io/zot/pkg/test/common"
"zotregistry.io/zot/pkg/test/deprecated"
. "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks"
)
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) {
Convey("Vulnerable layer", t, func() {
vulnerableLayer, err := GetLayerWithVulnerability()

View file

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

View file

@ -6,13 +6,11 @@ package search
import (
"context"
"encoding/json"
"errors"
"fmt"
"sort"
"strings"
"github.com/99designs/gqlgen/graphql"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/vektah/gqlparser/v2/gqlerror"
@ -75,18 +73,14 @@ func NewResolver(log log.Logger, storeController storage.StoreController,
}
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
contains := false
var manifest ispec.Manifest
manifest := imageMeta.Manifests[0]
err := json.Unmarshal(manifestMeta.ManifestBlob, &manifest)
if err != nil {
return false
}
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String()
manifestDigest := manifest.Digest.String()
// Check the image manifest in index.json matches the search digest
// 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
// 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
}
// 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
for _, layer := range manifest.Layers {
for _, layer := range manifest.Manifest.Layers {
if strings.Contains(layer.Digest.String(), lookupDigest) {
contains = true
}
@ -124,21 +118,20 @@ func getImageListForDigest(ctx context.Context, digest string, metaDB mTypes.Met
}
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
),
}
// get all repos
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, FilterByDigest(digest))
fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, FilterByDigest(digest))
if err != nil {
return &gql_generated.PaginatedImagesResult{}, err
}
imageSummaries, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap,
indexDataMap, skip, cveInfo, mTypes.Filter{}, pageInput)
imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList, skip,
cveInfo, mTypes.Filter{}, pageInput)
if err != nil {
return &gql_generated.PaginatedImagesResult{}, err
}
@ -157,7 +150,7 @@ func getImageSummary(ctx context.Context, repo, tag string, digest *string, skip
) (
*gql_generated.ImageSummary, error,
) {
repoMeta, err := metaDB.GetRepoMeta(repo)
repoMeta, err := metaDB.GetRepoMeta(ctx, repo)
if err != nil {
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)
}
for t := range repoMeta.Tags {
if t != tag {
delete(repoMeta.Tags, t)
repoMeta.Tags = map[string]mTypes.Descriptor{tag: manifestDescriptor}
imageDigest := manifestDescriptor.Digest
if digest != nil {
imageDigest = *digest
repoMeta.Tags[tag] = mTypes.Descriptor{
Digest: imageDigest,
MediaType: ispec.MediaTypeImageManifest,
}
}
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
}
if digest != nil {
manifestDigest := *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{
Digest: manifestDigest,
MediaType: ispec.MediaTypeImageManifest,
}
break
}
for _, manifest := range indexContent.Manifests {
manifestData, err := metaDB.GetManifestData(manifest.Digest)
if err != nil {
return nil, fmt.Errorf("resolver: can't get ManifestData for digest %s for image '%s:%s' %w",
manifest.Digest, repo, tag, err)
}
manifestMetaMap[manifest.Digest.String()] = mTypes.ManifestMetadata{
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob,
}
}
indexDataMap[indexDigest] = indexData
default:
log.Error().Str("mediaType", manifestDescriptor.MediaType).Msg("resolver: media type not supported")
imageMetaMap, err := metaDB.FilterImageMeta(ctx, []string{imageDigest})
if err != nil {
return &gql_generated.ImageSummary{}, err
}
imageSummaries := convert.RepoMeta2ImageSummaries(ctx, repoMeta, manifestMetaMap, indexDataMap, skipCVE, cveInfo)
imageSummaries := convert.RepoMeta2ImageSummaries(ctx, repoMeta, imageMetaMap, skipCVE, cveInfo)
if len(imageSummaries) == 0 {
return &gql_generated.ImageSummary{}, nil
@ -290,10 +198,10 @@ func getCVEListForImage(
}
pageInput := cvemodel.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
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 {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String()
return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
manifestDigest := imageMeta.Manifests[0].Digest.String()
for _, tagInfo := range tagsInfo {
switch tagInfo.Descriptor.MediaType {
@ -375,12 +283,12 @@ func FilterByTagInfo(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 {
return false
}
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String()
manifestDigest := imageMeta.Manifests[0].Digest.String()
for _, tagInfo := range tagsInfo {
switch tagInfo.Descriptor.MediaType {
@ -414,7 +322,7 @@ func getImageListForCVE(
// 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,
// 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 {
return &gql_generated.PaginatedImagesResult{}, err
}
@ -457,21 +365,21 @@ func getImageListForCVE(
// Actual page requested by user
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
deref(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
),
}
// get all repos
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, FilterByTagInfo(affectedImages))
fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, FilterByTagInfo(affectedImages))
if err != nil {
return &gql_generated.PaginatedImagesResult{}, err
}
imageSummaries, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap,
indexDataMap, skip, cveInfo, localFilter, pageInput)
imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList,
skip, cveInfo, localFilter, pageInput)
if err != nil {
return &gql_generated.PaginatedImagesResult{}, err
}
@ -530,21 +438,21 @@ func getImageListWithCVEFixed(
// Actual page requested by user
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
deref(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime),
),
}
// 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 {
return &gql_generated.PaginatedImagesResult{}, err
}
imageSummaries, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap,
indexDataMap, skip, cveInfo, localFilter, pageInput)
imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList,
skip, cveInfo, localFilter, pageInput)
if err != nil {
return &gql_generated.PaginatedImagesResult{}, err
}
@ -576,20 +484,25 @@ func repoListWithNewestImage(
}
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
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 {
return &gql_generated.PaginatedReposResult{}, err
}
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap,
skip, cveInfo, mTypes.Filter{}, pageInput)
imageMetaMap, err := metaDB.FilterImageMeta(ctx, mTypes.GetLatestImageDigests(repoMetaList))
if err != nil {
return &gql_generated.PaginatedReposResult{}, err
}
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, repoMetaList, imageMetaMap,
mTypes.Filter{}, pageInput, cveInfo, skip)
if err != nil {
return &gql_generated.PaginatedReposResult{}, err
}
@ -611,16 +524,16 @@ func getBookmarkedRepos(
requestedPage *gql_generated.PageInput,
metaDB mTypes.MetaDB,
) (*gql_generated.PaginatedReposResult, error) {
repoNames, err := metaDB.GetBookmarkedRepos(ctx)
bookmarkedRepos, err := metaDB.GetBookmarkedRepos(ctx)
if err != nil {
return &gql_generated.PaginatedReposResult{}, err
}
filterFn := func(repoMeta mTypes.RepoMetadata) bool {
return zcommon.Contains(repoNames, repoMeta.Name)
filterByName := func(repo string) bool {
return zcommon.Contains(bookmarkedRepos, repo)
}
return getFilteredPaginatedRepos(ctx, cveInfo, filterFn, log, requestedPage, metaDB)
return getFilteredPaginatedRepos(ctx, cveInfo, filterByName, log, requestedPage, metaDB)
}
func getStarredRepos(
@ -630,13 +543,13 @@ func getStarredRepos(
requestedPage *gql_generated.PageInput,
metaDB mTypes.MetaDB,
) (*gql_generated.PaginatedReposResult, error) {
repoNames, err := metaDB.GetStarredRepos(ctx)
starredRepos, err := metaDB.GetStarredRepos(ctx)
if err != nil {
return &gql_generated.PaginatedReposResult{}, err
}
filterFn := func(repoMeta mTypes.RepoMetadata) bool {
return zcommon.Contains(repoNames, repoMeta.Name)
filterFn := func(repo string) bool {
return zcommon.Contains(starredRepos, repo)
}
return getFilteredPaginatedRepos(ctx, cveInfo, filterFn, log, requestedPage, metaDB)
@ -645,7 +558,7 @@ func getStarredRepos(
func getFilteredPaginatedRepos(
ctx context.Context,
cveInfo cveinfo.CveInfo,
filterFn mTypes.FilterRepoFunc,
filterFn mTypes.FilterRepoNameFunc,
log log.Logger, //nolint:unparam // may be used by devs for debugging
requestedPage *gql_generated.PageInput,
metaDB mTypes.MetaDB,
@ -659,20 +572,25 @@ func getFilteredPaginatedRepos(
}
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
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 {
return &gql_generated.PaginatedReposResult{}, err
}
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap,
skip, cveInfo, mTypes.Filter{}, pageInput)
latestImageMeta, err := metaDB.FilterImageMeta(ctx, mTypes.GetLatestImageDigests(repoMetaList))
if err != nil {
return &gql_generated.PaginatedReposResult{}, err
}
repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, repoMetaList, latestImageMeta,
mTypes.Filter{}, pageInput, cveInfo, skip)
if err != nil {
return &gql_generated.PaginatedReposResult{}, err
}
@ -716,22 +634,31 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte
}
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
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 {
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,
skip, cveInfo, localFilter, pageInput)
imageMetaMap, err := metaDB.FilterImageMeta(ctx, mTypes.GetLatestImageDigests(repoMetaList))
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{
@ -746,20 +673,20 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte
}
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
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 {
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
}
imageSummaries, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap,
indexDataMap, skip, cveInfo, localFilter, pageInput)
imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList, skip, cveInfo,
localFilter, pageInput)
if err != nil {
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{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
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
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, filterDerivedImages(searchedImage))
fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, filterDerivedImages(searchedImage))
if err != nil {
return &gql_generated.PaginatedImagesResult{}, err
}
derivedList, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap,
skip, cveInfo, mTypes.Filter{}, pageInput)
derivedList, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList, skip, cveInfo,
mTypes.Filter{}, pageInput)
if err != nil {
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 {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
var addImageToList bool
var imageManifest ispec.Manifest
err := json.Unmarshal(manifestMeta.ManifestBlob, &imageManifest)
if err != nil {
return false
}
imageManifest := imageMeta.Manifests[0]
for i := range image.Manifests {
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String()
manifestDigest := imageManifest.Digest.String()
if manifestDigest == *image.Manifests[i].Digest {
return false
}
imageLayers := image.Manifests[i].Layers
addImageToList = false
layers := imageManifest.Layers
layers := imageManifest.Manifest.Layers
sameLayer := 0
@ -895,10 +817,10 @@ func baseImageList(ctx context.Context, image string, digest *string, metaDB mTy
}
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
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
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, filterBaseImages(searchedImage))
fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, filterBaseImages(searchedImage))
if err != nil {
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)
if err != nil {
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 {
return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
var addImageToList bool
var manifestContent ispec.Manifest
err := json.Unmarshal(manifestMeta.ManifestBlob, &manifestContent)
if err != nil {
return false
}
manifest := imageMeta.Manifests[0]
for i := range image.Manifests {
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String()
manifestDigest := manifest.Digest.String()
if manifestDigest == *image.Manifests[i].Digest {
return false
}
addImageToList = true
for _, l := range manifestContent.Layers {
for _, l := range manifest.Manifest.Layers {
foundLayer := false
for _, k := range image.Manifests[i].Layers {
@ -996,7 +913,7 @@ func validateGlobalSearchInput(query string, filter *gql_generated.Filter,
requestedPage *gql_generated.PageInput,
) error {
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)
}
@ -1020,14 +937,14 @@ func checkFilter(filter *gql_generated.Filter) error {
for _, arch := range filter.Arch {
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)
}
}
for _, osSys := range filter.Os {
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)
}
}
@ -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
}
repoMeta, err := metaDB.GetUserRepoMeta(ctx, repo)
repoMeta, err := metaDB.GetRepoMeta(ctx, repo)
if err != nil {
log.Error().Err(err).Str("repository", repo).Msg("resolver: can't retrieve repoMeta for repo")
return &gql_generated.RepoInfo{}, err
}
var (
manifestMetaMap = map[string]mTypes.ManifestMetadata{}
indexDataMap = map[string]mTypes.IndexData{}
)
tagsDigests := []string{}
for tag, descriptor := range repoMeta.Tags {
switch descriptor.MediaType {
case ispec.MediaTypeImageManifest:
digest := descriptor.Digest
if _, alreadyDownloaded := manifestMetaMap[digest]; alreadyDownloaded {
continue
}
manifestData, err := metaDB.GetManifestData(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
}
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:
for i := range repoMeta.Tags {
if i == "" {
continue
}
tagsDigests = append(tagsDigests, repoMeta.Tags[i].Digest)
}
imageMetaMap, err := metaDB.FilterImageMeta(ctx, tagsDigests)
if err != nil {
log.Error().Err(err).Str("repository", repo).Msg("resolver: can't retrieve imageMeta for repo")
return &gql_generated.RepoInfo{}, err
}
skip := convert.SkipQGLField{
@ -1212,7 +1065,7 @@ func expandedRepoInfo(ctx context.Context, repo string, metaDB mTypes.MetaDB, cv
canSkipField(convert.GetPreloads(ctx), "Images.Vulnerabilities"),
}
repoSummary, imageSummaries := convert.RepoMeta2ExpandedRepoInfo(ctx, repoMeta, manifestMetaMap, indexDataMap,
repoSummary, imageSummaries := convert.RepoMeta2ExpandedRepoInfo(ctx, repoMeta, imageMetaMap,
skip, cveInfo, log)
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]
}
func safeDereferencing[T any](pointer *T, defaultVal T) T {
func deref[T any](pointer *T, defaultVal T) T {
if pointer != nil {
return *pointer
}
@ -1263,23 +1116,28 @@ func getImageList(ctx context.Context, repo string, metaDB mTypes.MetaDB, cveInf
}
pageInput := pagination.PageInput{
Limit: safeDereferencing(requestedPage.Limit, 0),
Offset: safeDereferencing(requestedPage.Offset, 0),
Limit: deref(requestedPage.Limit, 0),
Offset: deref(requestedPage.Offset, 0),
SortBy: pagination.SortCriteria(
safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
),
}
reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx,
func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool {
return repoMeta.Name == repo || repo == ""
})
var matchRepoName mTypes.FilterRepoTagFunc
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 {
return &gql_generated.PaginatedImagesResult{}, err
}
imageList, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap,
indexDataMap, skip, cveInfo, mTypes.Filter{}, pageInput)
imageList, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, imageMeta, skip,
cveInfo, mTypes.Filter{}, pageInput)
if err != nil {
return &gql_generated.PaginatedImagesResult{}, err
}

File diff suppressed because it is too large Load diff

View file

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

View file

@ -18,13 +18,11 @@ import (
"zotregistry.io/zot/pkg/api/constants"
"zotregistry.io/zot/pkg/common"
extconf "zotregistry.io/zot/pkg/extensions/config"
"zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/local"
test "zotregistry.io/zot/pkg/test/common"
"zotregistry.io/zot/pkg/test/deprecated"
. "zotregistry.io/zot/pkg/test/image-utils"
. "zotregistry.io/zot/pkg/test/oci-utils"
)
//nolint:dupl
@ -535,25 +533,15 @@ func TestChangingRepoState(t *testing.T) {
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 {
t.FailNow()
}
// ------ Create the test repos
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,
})
err = WriteImageToFileSystem(img, forbiddenRepo, "tag", storeCtlr)
if err != nil {
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).
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,
referenceDigest, manifestBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log)
}
err = meta.SetImageMetaFromInput(localRepo, cosignTag, ispec.MediaTypeImageManifest,
referenceDigest, manifestBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log)
if err != nil {
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).
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,
referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log)
}
err = meta.SetImageMetaFromInput(localRepo, referenceDigest.String(), referrer.MediaType,
referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log)
if err != nil {
return refsDigests, fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w",
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).
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,
referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log)
}
err = meta.SetImageMetaFromInput(localRepo, referenceDigest.String(), referrer.MediaType,
referenceDigest, referenceBuf, ref.storeController.GetImageStore(localRepo),
ref.metaDB, ref.log)
if err != nil {
return refsDigests, fmt.Errorf("failed to set metadata for oci reference in '%s@%s': %w",
localRepo, subjectDigestStr, err)

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -4,29 +4,25 @@ import (
"context"
"crypto/rand"
"encoding/base64"
"encoding/json"
"math"
"testing"
"time"
"github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"go.etcd.io/bbolt"
zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types"
reqCtx "zotregistry.io/zot/pkg/requestcontext"
. "zotregistry.io/zot/pkg/test/image-utils"
)
type imgTrustStore struct{}
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,
) (string, time.Time, bool, error) {
return "", time.Time{}, false, nil
@ -47,14 +43,6 @@ func TestWrapperErrors(t *testing.T) {
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.SetUsername("test")
@ -245,604 +233,6 @@ func TestWrapperErrors(t *testing.T) {
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() {
uacKey := reqCtx.GetContextKey()
ctx := context.WithValue(context.Background(), uacKey, "bad context")
@ -860,7 +250,7 @@ func TestWrapperErrors(t *testing.T) {
ctx := userAc.DeriveContext(context.Background())
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"))
So(err, ShouldBeNil)
@ -976,23 +366,6 @@ func TestWrapperErrors(t *testing.T) {
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() {
userAc := reqCtx.NewUserAccessControl()
userAc.SetUsername("username")
@ -1002,7 +375,7 @@ func TestWrapperErrors(t *testing.T) {
ctx := userAc.DeriveContext(context.Background())
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"))
So(err, ShouldBeNil)
@ -1011,78 +384,8 @@ func TestWrapperErrors(t *testing.T) {
})
So(err, ShouldBeNil)
_, err := boltdbWrapper.GetUserRepoMeta(ctx, "repo")
_, err := boltdbWrapper.GetRepoMeta(ctx, "repo")
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,10 +2,10 @@ package boltdb
// MetadataDB.
const (
ManifestDataBucket = "ManifestData"
IndexDataBucket = "IndexData"
RepoMetadataBucket = "RepoMetadata"
UserDataBucket = "UserData"
VersionBucket = "Version"
UserAPIKeysBucket = "UserAPIKeys"
ImageMetaBuck = "ImageMeta"
RepoMetaBuck = "RepoMeta"
RepoBlobsBuck = "RepoBlobsMeta"
UserDataBucket = "UserData"
VersionBucket = "Version"
UserAPIKeysBucket = "UserAPIKeys"
)

View file

@ -1,8 +1,6 @@
package common
import (
"encoding/json"
"fmt"
"strings"
"time"
@ -10,28 +8,23 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
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"
)
func UpdateManifestMeta(repoMeta mTypes.RepoMetadata, manifestDigest godigest.Digest,
manifestMeta mTypes.ManifestMetadata,
) mTypes.RepoMetadata {
updatedRepoMeta := repoMeta
updatedStatistics := repoMeta.Statistics[manifestDigest.String()]
updatedStatistics.DownloadCount = manifestMeta.DownloadCount
updatedRepoMeta.Statistics[manifestDigest.String()] = updatedStatistics
if manifestMeta.Signatures == nil {
manifestMeta.Signatures = mTypes.ManifestSignatures{}
func SignatureAlreadyExists(signatureSlice []mTypes.SignatureInfo, sm mTypes.SignatureMetadata) bool {
for _, sigInfo := range signatureSlice {
if sm.SignatureDigest == sigInfo.SignatureManifestDigest {
return true
}
}
updatedRepoMeta.Signatures[manifestDigest.String()] = manifestMeta.Signatures
return updatedRepoMeta
return false
}
func SignatureAlreadyExists(signatureSlice []mTypes.SignatureInfo, sm mTypes.SignatureMetadata) bool {
func ProtoSignatureAlreadyExists(signatureSlice []*proto_go.SignatureInfo, sm mTypes.SignatureMetadata) bool {
for _, sigInfo := range signatureSlice {
if sm.SignatureDigest == sigInfo.SignatureManifestDigest {
return true
@ -74,7 +67,7 @@ const (
)
// 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)...
func RankRepoName(searchText string, repoName string) int {
searchText = strings.Trim(searchText, "/")
@ -89,7 +82,7 @@ func RankRepoName(searchText string, repoName string) int {
return perfectMatchPriority
}
// searchText containst just 1 diretory name
// searchText contains just 1 directory name
if len(searchTextSlice) == 1 {
lastNameInRepoPath := repoNameSlice[len(repoNameSlice)-1]
@ -157,21 +150,6 @@ func GetRepoTag(searchText string) (string, string, error) {
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 {
if len(artifactTypes) == 0 {
return true
@ -208,139 +186,199 @@ func CheckImageLastUpdated(repoLastUpdated time.Time, isSigned bool, noImageChec
return repoLastUpdated, noImageChecked, isSigned
}
func FilterDataByRepo(foundRepos []mTypes.RepoMetadata, manifestMetadataMap map[string]mTypes.ManifestMetadata,
indexDataMap map[string]mTypes.IndexData,
) (map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error) {
var (
foundManifestMetadataMap = make(map[string]mTypes.ManifestMetadata)
foundindexDataMap = make(map[string]mTypes.IndexData)
)
func AddImageMetaToRepoMeta(repoMeta *proto_go.RepoMeta, repoBlobs *proto_go.RepoBlobs, reference string,
imageMeta mTypes.ImageMeta,
) (*proto_go.RepoMeta, *proto_go.RepoBlobs, error) {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
manifestData := imageMeta.Manifests[0]
// keep just the manifestMeta we need
for _, repoMeta := range foundRepos {
for _, descriptor := range repoMeta.Tags {
switch descriptor.MediaType {
case ispec.MediaTypeImageManifest:
foundManifestMetadataMap[descriptor.Digest] = manifestMetadataMap[descriptor.Digest]
case ispec.MediaTypeImageIndex:
indexData := indexDataMap[descriptor.Digest]
vendor := GetVendor(manifestData.Manifest.Annotations)
if vendor == "" {
vendor = GetVendor(manifestData.Manifest.Annotations)
}
var indexContent ispec.Index
vendors := []string{}
if vendor != "" {
vendors = append(vendors, vendor)
}
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)
}
platforms := []*proto_go.Platform{getProtoPlatform(&manifestData.Config.Platform)}
if platforms[0].OS == "" && platforms[0].Architecture == "" {
platforms = []*proto_go.Platform{}
}
for _, manifestDescriptor := range indexContent.Manifests {
manifestDigest := manifestDescriptor.Digest.String()
subBlobs := []string{manifestData.Manifest.Config.Digest.String()}
repoBlobs.Blobs[manifestData.Manifest.Config.Digest.String()] = &proto_go.BlobInfo{
Size: manifestData.Manifest.Config.Size,
}
foundManifestMetadataMap[manifestDigest] = manifestMetadataMap[manifestDigest]
}
for _, layer := range manifestData.Manifest.Layers {
subBlobs = append(subBlobs, layer.Digest.String())
repoBlobs.Blobs[layer.Digest.String()] = &proto_go.BlobInfo{Size: layer.Size}
}
foundindexDataMap[descriptor.Digest] = indexData
default:
continue
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:
subBlobs := []string{}
for _, manifest := range imageMeta.Index.Manifests {
subBlobs = append(subBlobs, manifest.Digest.String())
}
repoBlobs.Blobs[imageMeta.Digest.String()] = &proto_go.BlobInfo{
Size: imageMeta.Size,
SubBlobs: subBlobs,
}
}
// update info only when a tag is added
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
}
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,
) (map[string]mTypes.ManifestMetadata, map[string]mTypes.IndexData, error) {
foundManifestMetadataMap := map[string]mTypes.ManifestMetadata{}
foundIndexDataMap := map[string]mTypes.IndexData{}
func recalculateAggregateFields(repoMeta *proto_go.RepoMeta, repoBlobs *proto_go.RepoBlobs,
) (int64, []*proto_go.Platform, []string) {
size := int64(0)
platforms := []*proto_go.Platform{}
vendors := []string{}
blobsMap := map[string]struct{}{}
for idx := range foundRepos {
for _, descriptor := range foundRepos[idx].Tags {
switch descriptor.MediaType {
case ispec.MediaTypeImageManifest:
manifestData, err := metaDB.GetManifestData(godigest.Digest(descriptor.Digest))
if err != nil {
return map[string]mTypes.ManifestMetadata{}, map[string]mTypes.IndexData{}, err
for _, descriptor := range repoMeta.Tags {
if descriptor.Digest == "" {
continue
}
queue := []string{descriptor.Digest}
for len(queue) > 0 {
currentBlob := queue[0]
queue = queue[1:]
if _, found := blobsMap[currentBlob]; !found {
blobInfo := repoBlobs.Blobs[currentBlob]
if blobInfo == nil {
continue
}
foundManifestMetadataMap[descriptor.Digest] = mTypes.ManifestMetadata{
ManifestBlob: manifestData.ManifestBlob,
ConfigBlob: manifestData.ConfigBlob,
}
case ispec.MediaTypeImageIndex:
indexData, err := metaDB.GetIndexData(godigest.Digest(descriptor.Digest))
if err != nil {
return map[string]mTypes.ManifestMetadata{}, map[string]mTypes.IndexData{}, err
}
blobsMap[currentBlob] = struct{}{}
size += blobInfo.Size
vendors = mConvert.AddVendors(vendors, blobInfo.Vendors)
platforms = mConvert.AddProtoPlatforms(platforms, blobInfo.Platforms)
var indexContent ispec.Index
err = json.Unmarshal(indexData.IndexBlob, &indexContent)
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
queue = append(queue, blobInfo.SubBlobs...)
}
}
}
return foundManifestMetadataMap, foundIndexDataMap, nil
return size, platforms, vendors
}
// 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) {
_, err := metaDB.GetManifestData(digest)
if err == nil {
return true, ispec.MediaTypeImageManifest
func getProtoPlatform(platform *ispec.Platform) *proto_go.Platform {
if platform == nil {
return nil
}
_, err = metaDB.GetIndexData(digest)
if err == nil {
return true, ispec.MediaTypeImageIndex
return &proto_go.Platform{
Architecture: getArch(platform.Architecture, platform.Variant),
OS: platform.OS,
}
return false, ""
}
func GetImageDescriptor(metaDB mTypes.MetaDB, repo, tag string) (mTypes.Descriptor, error) {
repoMeta, err := metaDB.GetRepoMeta(repo)
if err != nil {
return mTypes.Descriptor{}, err
func getArch(arch string, variant string) string {
if variant != "" {
arch = arch + "/" + variant
}
imageDescriptor, ok := repoMeta.Tags[tag]
if !ok {
return mTypes.Descriptor{}, zerr.ErrTagMetaNotFound
}
return imageDescriptor, nil
return arch
}
func InitializeImageConfig(blob []byte) ispec.Image {
var configContent ispec.Image
func GetVendor(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationVendor, "org.label-schema.vendor")
}
err := json.Unmarshal(blob, &configContent)
if err != nil {
return ispec.Image{}
func GetAnnotationValue(annotations map[string]string, annotationKey, labelKey string) string {
value, ok := annotations[annotationKey]
if !ok || value == "" {
value, ok = annotations[labelKey]
if !ok {
value = ""
}
}
return configContent
return value
}

View file

@ -5,23 +5,15 @@ import (
"testing"
"time"
"github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/meta/common"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/test/mocks"
)
var ErrTestError = errors.New("test error")
func TestUtils(t *testing.T) {
Convey("GetReferredSubject", t, func() {
_, err := common.GetReferredSubject([]byte("bad json"))
So(err, ShouldNotBeNil)
})
Convey("MatchesArtifactTypes", t, func() {
res := common.MatchesArtifactTypes("", nil)
So(res, ShouldBeTrue)
@ -116,145 +108,4 @@ func TestUtils(t *testing.T) {
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()
manifestDataTablename := "ManifestDataTable" + uuid.String()
indexDataTablename := "IndexDataTable" + uuid.String()
userDataTablename := "UserDataTable" + uuid.String()
apiKeyTablename := "ApiKeyTable" + uuid.String()
@ -54,31 +52,23 @@ func TestWrapperErrors(t *testing.T) {
So(err, ShouldBeNil)
dynamoWrapper := DynamoDB{
Client: dynamodb.NewFromConfig(cfg),
RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename,
IndexDataTablename: indexDataTablename,
VersionTablename: versionTablename,
UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename,
Patches: version.GetDynamoDBPatches(),
Log: log.Logger{Logger: zerolog.New(os.Stdout)},
Client: dynamodb.NewFromConfig(cfg),
RepoMetaTablename: repoMetaTablename,
VersionTablename: versionTablename,
UserDataTablename: userDataTablename,
APIKeyTablename: apiKeyTablename,
Patches: version.GetDynamoDBPatches(),
Log: log.Logger{Logger: zerolog.New(os.Stdout)},
}
// The table creation should fail as the endpoint is not configured correctly
err = dynamoWrapper.createRepoMetaTable()
So(err, ShouldNotBeNil)
err = dynamoWrapper.createManifestDataTable()
So(err, ShouldNotBeNil)
err = dynamoWrapper.createIndexDataTable()
err = dynamoWrapper.createTable(dynamoWrapper.RepoMetaTablename)
So(err, ShouldNotBeNil)
err = dynamoWrapper.createVersionTable()
So(err, ShouldNotBeNil)
err = dynamoWrapper.createAPIKeyTable()
err = dynamoWrapper.createTable(dynamoWrapper.APIKeyTablename)
So(err, ShouldNotBeNil)
})
@ -98,21 +88,16 @@ func TestWrapperErrors(t *testing.T) {
So(err, ShouldBeNil)
dynamoWrapper := DynamoDB{
Client: dynamodb.NewFromConfig(cfg),
RepoMetaTablename: repoMetaTablename,
ManifestDataTablename: manifestDataTablename,
VersionTablename: versionTablename,
IndexDataTablename: indexDataTablename,
UserDataTablename: userDataTablename,
Patches: version.GetDynamoDBPatches(),
Log: log.Logger{Logger: zerolog.New(os.Stdout)},
Client: dynamodb.NewFromConfig(cfg),
RepoMetaTablename: repoMetaTablename,
VersionTablename: versionTablename,
UserDataTablename: userDataTablename,
Patches: version.GetDynamoDBPatches(),
Log: log.Logger{Logger: zerolog.New(os.Stdout)},
}
// The tables were not created so delete calls fail, but dynamoWrapper should not error
err = dynamoWrapper.deleteRepoMetaTable()
So(err, ShouldBeNil)
err = dynamoWrapper.deleteManifestDataTable()
err = dynamoWrapper.deleteTable(dynamoWrapper.RepoMetaTablename)
So(err, ShouldBeNil)
})
}

File diff suppressed because it is too large Load diff

View file

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

View file

@ -2,10 +2,10 @@ package meta
import (
godigest "github.com/opencontainers/go-digest"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/common"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage"
)
@ -22,55 +22,9 @@ func OnUpdateManifest(repo, reference, mediaType string, digest godigest.Digest,
imgStore := storeController.GetImageStore(repo)
// check if image is a signature
isSignature, signatureType, signedManifestDigest, err := storage.CheckIsImageSignature(repo, body, reference)
err := SetImageMetaFromInput(repo, reference, mediaType, digest, body,
imgStore, metaDB, log)
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)
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")
if err := imgStore.DeleteImageManifest(repo, reference, false); err != nil {
@ -130,15 +84,6 @@ func OnDeleteManifest(repo, reference, mediaType string, digest godigest.Digest,
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 {
@ -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.
func OnGetManifest(name, reference string, body []byte,
func OnGetManifest(name, reference, mediaType string, body []byte,
storeController storage.StoreController, metaDB mTypes.MetaDB, log log.Logger,
) error {
// check if image is a signature
@ -163,14 +108,20 @@ func OnGetManifest(name, reference string, body []byte,
return err
}
if !isSignature && !zcommon.IsReferrersTag(reference) {
err := metaDB.IncrementImageDownloads(name, reference)
if err != nil {
log.Error().Err(err).Str("repository", name).Str("reference", reference).
Msg("unexpected error for image")
if isSignature || zcommon.IsReferrersTag(reference) {
return nil
}
return err
}
if !(mediaType == v1.MediaTypeImageManifest || mediaType == v1.MediaTypeImageIndex) {
return nil
}
err = metaDB.IncrementImageDownloads(name, reference)
if err != nil {
log.Error().Err(err).Str("repository", name).Str("reference", reference).
Msg("unexpected error for image")
return err
}
return nil

View file

@ -1,24 +1,19 @@
package meta_test
import (
"encoding/json"
"context"
"errors"
"testing"
notreg "github.com/notaryproject/notation-go/registry"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta"
"zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/local"
"zotregistry.io/zot/pkg/test/deprecated"
. "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks"
)
@ -42,259 +37,38 @@ func TestOnUpdateManifest(t *testing.T) {
metaDB, err := boltdb.New(boltDriver, log)
So(err, ShouldBeNil)
config, layers, manifest, err := deprecated.GetRandomImageComponents(100) //nolint:staticcheck
image := CreateDefaultImage()
err = WriteImageToFileSystem(CreateDefaultImage(), "repo", "tag1", storeController)
So(err, ShouldBeNil)
err = WriteImageToFileSystem(
Image{
Config: config, Manifest: manifest, Layers: layers,
}, "repo", "tag1", storeController)
err = meta.OnUpdateManifest("repo", "tag1", ispec.MediaTypeImageManifest, image.Digest(),
image.ManifestDescriptor.Data, storeController, metaDB, log)
So(err, ShouldBeNil)
manifestBlob, err := json.Marshal(manifest)
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")
repoMeta, err := metaDB.GetRepoMeta(context.Background(), "repo")
So(err, ShouldBeNil)
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) {
Convey("Update operations", t, func() {
Convey("On UpdateManifest", func() {
imageStore := mocks.MockedImageStore{}
storeController := storage.StoreController{DefaultStore: &imageStore}
metaDB := mocks.MetaDBMock{}
log := log.NewLogger("debug", "")
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
}
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"),
storeController, metaDB, log)
So(err, ShouldBeNil)
})
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"),
storeController, metaDB, log)
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)
Convey("IsReferrersTag true update", func() {
err := meta.OnUpdateManifest("repo", "sha256-123", "digest", "media", []byte("bad"),
storeController, 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)
Convey("IsReferrersTag true delete", func() {
err := meta.OnDeleteManifest("repo", "sha256-123", "digest", "media", []byte("bad"),
storeController, metaDB, log)
So(err, ShouldBeNil)
})
})
}

View file

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

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,6 @@ package meta
import (
"encoding/json"
"errors"
"fmt"
"time"
godigest "github.com/opencontainers/go-digest"
@ -12,11 +11,17 @@ import (
zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/convert"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/storage"
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 database.
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
}
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)
if err != nil {
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
}
err = resetRepoMeta(repo, metaDB, log)
err = metaDB.ResetRepoReferences(repo)
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")
return err
}
for _, descriptor := range indexContent.Manifests {
tag := descriptor.Annotations[ispec.AnnotationRefName]
for _, manifest := range indexContent.Manifests {
tag := manifest.Annotations[ispec.AnnotationRefName]
if zcommon.IsReferrersTag(tag) {
continue
}
descriptorBlob, err := getCachedBlob(repo, descriptor, metaDB, imageStore, log)
manifestBlob, _, _, err := imageStore.GetImageManifest(repo, manifest.Digest.String())
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
}
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
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)
if err != nil {
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
}
// 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) {
allRepos, err := storeController.DefaultStore.GetRepositories()
if err != nil {
@ -197,43 +139,6 @@ func getAllRepos(storeController storage.StoreController) ([]string, error) {
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,
imageStore storageTypes.ImageStore, log log.Logger,
) ([]mTypes.LayerInfo, error) {
@ -341,92 +246,82 @@ func getNotationSignatureLayersInfo(
return layers, nil
}
// NewManifestMeta takes raw data about an image and createa a new ManifestMetadate object.
func NewManifestData(repoName string, manifestBlob []byte, imageStore storageTypes.ImageStore,
) (mTypes.ManifestData, error) {
var (
manifestContent ispec.Manifest
configContent ispec.Image
manifestData mTypes.ManifestData
)
err := json.Unmarshal(manifestBlob, &manifestContent)
if err != nil {
return mTypes.ManifestData{}, 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 {
err = json.Unmarshal(configBlob, &configContent)
if err != nil {
return mTypes.ManifestData{}, err
}
}
manifestData.ManifestBlob = manifestBlob
manifestData.ConfigBlob = configBlob
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,
func SetImageMetaFromInput(repo, reference, mediaType string, digest godigest.Digest, blob []byte,
imageStore storageTypes.ImageStore, metaDB mTypes.MetaDB, log log.Logger,
) error {
var imageMeta mTypes.ImageMeta
switch mediaType {
case ispec.MediaTypeImageManifest:
imageData, err := NewManifestData(repo, descriptorBlob, imageStore)
manifestContent := ispec.Manifest{}
configContent := ispec.Image{}
err := json.Unmarshal(blob, &manifestContent)
if err != nil {
return err
}
err = metaDB.SetManifestData(digest, imageData)
if err != nil {
log.Error().Err(err).Msg("metadb: error while putting manifest meta")
if manifestContent.Config.MediaType == ispec.MediaTypeImageConfig {
configBlob, err := imageStore.GetBlobContent(repo, manifestContent.Config.Digest)
if err != nil {
return err
}
return err
err = json.Unmarshal(configBlob, &configContent)
if err != nil {
return err
}
}
if isSig, sigType, signedManifestDigest := isSignature(reference, manifestContent); isSig {
layers, err := GetSignatureLayersInfo(repo, reference, digest.String(), sigType,
blob, imageStore, log)
if err != nil {
return err
}
err = metaDB.AddManifestSignature(repo, signedManifestDigest,
mTypes.SignatureMetadata{
SignatureType: sigType,
SignatureDigest: digest.String(),
LayersInfo: layers,
})
if err != nil {
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
}
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:
indexData := NewIndexData(repo, descriptorBlob, imageStore)
indexContent := ispec.Index{}
err := metaDB.SetIndexData(digest, indexData)
err := json.Unmarshal(blob, &indexContent)
if err != nil {
log.Error().Err(err).Msg("metadb: error while putting index data")
return err
}
imageMeta = convert.GetImageIndexMeta(indexContent, int64(len(blob)), digest)
default:
return nil
}
referredDigest, referrerInfo, hasSubject, err := GetReferredInfo(descriptorBlob, digest.String(), mediaType)
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)
err := metaDB.SetRepoReference(repo, reference, imageMeta)
if err != nil {
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
}
func GetReferredInfo(descriptorBlob []byte, referrerDigest, mediaType string,
) (godigest.Digest, mTypes.ReferrerInfo, bool, error) {
var (
referrerInfo mTypes.ReferrerInfo
referrerSubject *ispec.Descriptor
)
func isSignature(reference string, manifestContent ispec.Manifest) (bool, string, godigest.Digest) {
manifestArtifactType := zcommon.GetManifestArtifactType(manifestContent)
switch mediaType {
case ispec.MediaTypeImageManifest:
var manifestContent ispec.Manifest
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
referrerInfo = mTypes.ReferrerInfo{
Digest: referrerDigest,
MediaType: mediaType,
ArtifactType: zcommon.GetManifestArtifactType(manifestContent),
Size: len(descriptorBlob),
Annotations: manifestContent.Annotations,
}
case ispec.MediaTypeImageIndex:
var indexContent ispec.Index
err := json.Unmarshal(descriptorBlob, &indexContent)
if err != nil {
return "", referrerInfo, false,
fmt.Errorf("metadb: can't unmarshal manifest for digest %s: %w", referrerDigest, err)
}
referrerSubject = indexContent.Subject
referrerInfo = mTypes.ReferrerInfo{
Digest: referrerDigest,
MediaType: mediaType,
ArtifactType: zcommon.GetIndexArtifactType(indexContent),
Size: len(descriptorBlob),
Annotations: indexContent.Annotations,
}
// check notation signature
if manifestArtifactType == zcommon.ArtifactTypeNotation && manifestContent.Subject != nil {
return true, NotationType, manifestContent.Subject.Digest
}
if referrerSubject == nil || referrerSubject.Digest.String() == "" {
return "", mTypes.ReferrerInfo{}, false, nil
if tag := reference; zcommon.IsCosignTag(reference) {
prefixLen := len("sha256-")
digestLen := 64
signedImageManifestDigestEncoded := tag[prefixLen : prefixLen+digestLen]
signedImageManifestDigest := godigest.NewDigestFromEncoded(godigest.SHA256,
signedImageManifestDigestEncoded)
return true, CosignType, signedImageManifestDigest
}
return referrerSubject.Digest, referrerInfo, true, nil
return false, "", ""
}

View file

@ -13,7 +13,6 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/log"
@ -97,50 +96,6 @@ func TestParseStorageErrors(t *testing.T) {
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() {
indexContent := ispec.Index{
Manifests: []ispec.Descriptor{
@ -161,7 +116,7 @@ func TestParseStorageErrors(t *testing.T) {
}
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
}
@ -169,212 +124,6 @@ func TestParseStorageErrors(t *testing.T) {
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)
})
})
})
}
@ -401,14 +150,14 @@ func TestParseStorageDynamoWrapper(t *testing.T) {
rootDir := t.TempDir()
params := dynamodb.DBDriverParameters{
Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"),
Region: "us-east-2",
RepoMetaTablename: "RepoMetadataTable",
ManifestDataTablename: "ManifestDataTable",
IndexDataTablename: "IndexDataTable",
UserDataTablename: "UserDataTable",
APIKeyTablename: "ApiKeyTable",
VersionTablename: "Version",
Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"),
Region: "us-east-2",
RepoMetaTablename: "RepoMetadataTable",
RepoBlobsInfoTablename: "RepoBlobsInfoTablename",
ImageMetaTablename: "ImageMetaTablename",
UserDataTablename: "UserDataTable",
APIKeyTablename: "ApiKeyTable",
VersionTablename: "Version",
}
dynamoClient, err := dynamodb.GetDynamoClient(params)
@ -417,10 +166,13 @@ func TestParseStorageDynamoWrapper(t *testing.T) {
dynamoWrapper, err := dynamodb.New(dynamoClient, params, log.NewLogger("debug", ""))
So(err, ShouldBeNil)
err = dynamoWrapper.ResetManifestDataTable()
err = dynamoWrapper.ResetTable(dynamoWrapper.RepoMetaTablename)
So(err, ShouldBeNil)
err = dynamoWrapper.ResetRepoMetaTable()
err = dynamoWrapper.ResetTable(dynamoWrapper.RepoBlobsTablename)
So(err, ShouldBeNil)
err = dynamoWrapper.ResetTable(dynamoWrapper.ImageMetaTablename)
So(err, ShouldBeNil)
RunParseStorageTests(rootDir, dynamoWrapper)
@ -496,20 +248,20 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
So(err, ShouldBeNil)
repos, err := metaDB.GetMultipleRepoMeta(context.Background(),
func(repoMeta mTypes.RepoMetadata) bool { return true })
func(repoMeta mTypes.RepoMeta) bool { return true })
So(err, ShouldBeNil)
So(len(repos), ShouldEqual, 1)
So(len(repos[0].Tags), ShouldEqual, 2)
for _, descriptor := range repos[0].Tags {
manifestMeta, err := metaDB.GetManifestMeta(repo, godigest.Digest(descriptor.Digest))
ctx := context.Background()
for tag, descriptor := range repos[0].Tags {
imageManifestData, err := metaDB.GetFullImageMeta(ctx, repo, tag)
So(err, ShouldBeNil)
So(manifestMeta.ManifestBlob, ShouldNotBeNil)
So(manifestMeta.ConfigBlob, ShouldNotBeNil)
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", ""))
So(err, ShouldBeNil)
repos, err := metaDB.GetMultipleRepoMeta(
context.Background(),
func(repoMeta mTypes.RepoMetadata) bool { return true },
)
repos, err := metaDB.GetMultipleRepoMeta(context.Background(),
func(repoMeta mTypes.RepoMeta) bool { return true })
So(err, ShouldBeNil)
for _, desc := range repos[0].Tags {
@ -577,15 +327,12 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
storeController := storage.StoreController{DefaultStore: imageStore}
// add an image
image, err := deprecated.GetRandomImage() //nolint:staticcheck
image := CreateRandomImage() //nolint:staticcheck
err := WriteImageToFileSystem(image, repo, "tag", storeController)
So(err, ShouldBeNil)
manifestDigest := image.Digest()
err = WriteImageToFileSystem(image, repo, "tag", storeController)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(repo, "tag", manifestDigest, ispec.MediaTypeImageManifest)
err = metaDB.SetRepoReference(repo, "tag", image.AsImageMeta())
So(err, ShouldBeNil)
err = metaDB.IncrementRepoStars(repo)
@ -597,30 +344,20 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
err = metaDB.IncrementImageDownloads(repo, "tag")
So(err, ShouldBeNil)
repoMeta, err := metaDB.GetRepoMeta(repo)
repoMeta, err := metaDB.GetRepoMeta(context.Background(), repo)
So(err, ShouldBeNil)
So(repoMeta.Statistics[manifestDigest.String()].DownloadCount, ShouldEqual, 3)
So(repoMeta.Stars, ShouldEqual, 1)
So(repoMeta.Statistics[image.DigestStr()].DownloadCount, ShouldEqual, 3)
So(repoMeta.StarCount, ShouldEqual, 1)
err = meta.ParseStorage(metaDB, storeController, log.NewLogger("debug", ""))
So(err, ShouldBeNil)
repoMeta, err = metaDB.GetRepoMeta(repo)
repoMeta, err = metaDB.GetRepoMeta(context.Background(), repo)
So(err, ShouldBeNil)
So(repoMeta.Statistics[manifestDigest.String()].DownloadCount, ShouldEqual, 3)
So(repoMeta.Stars, 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)
So(repoMeta.Statistics[image.DigestStr()].DownloadCount, ShouldEqual, 3)
So(repoMeta.StarCount, ShouldEqual, 1)
})
}

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"
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.
type ToggleState int
@ -27,23 +18,109 @@ const (
)
type (
FilterFunc func(repoMeta RepoMetadata, manifestMeta ManifestMetadata) bool
FilterRepoFunc func(repoMeta RepoMetadata) bool
// Currently imageMeta applied for indexes is applied for each manifest individually so imageMeta.manifests
// 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
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(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
// GetRepoStars returns the total number of stars a repo has
GetRepoStars(repo string) (int, error)
// SetRepoMeta returns RepoMetadata of a repo from the database
SetRepoMeta(repo string, repoMeta RepoMeta) error
// SetRepoReference sets the reference of a manifest in the tag list of a repo
SetRepoReference(repo string, reference string, manifestDigest godigest.Digest, mediaType string) error
// GetReferrersInfo returns 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)
// 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,
@ -55,80 +132,12 @@ type MetaDB interface { //nolint:interfacebloat
*/
RemoveRepoReference(repo, reference string, manifestDigest godigest.Digest) error
// DeleteRepoTag delets the tag from the tag list of a repo
DeleteRepoTag(repo string, tag string) error
// ResetRepoReferences resets all layout specific data (tags, signatures, referrers, etc.) but keep user and image
// specific metadata such as star count, downloads other statistics
ResetRepoReferences(repo string) error
// GetRepoMeta returns RepoMetadata of a repo from the database
GetRepoMeta(repo string) (RepoMetadata, 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)
// ResetDB will delete all data in the DB
ResetDB() error
PatchDB() error
@ -176,25 +185,78 @@ type UserDB interface { //nolint:interfacebloat
type ImageTrustStore interface {
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,
) (string, time.Time, bool, error)
}
type ManifestMetadata struct {
ManifestBlob []byte
ConfigBlob []byte
DownloadCount int
Signatures ManifestSignatures
}
type IndexData struct {
IndexBlob []byte
// ImageMeta can store all data related to a image, multiarch or simple. Used for writing imaged to MetaDB.
type ImageMeta struct {
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 {
ManifestBlob []byte
ConfigBlob []byte
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
}
// 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
}
type FullManifestMeta struct {
ManifestData
Referrers []ReferrerInfo
Statistics DescriptorStatistics
Signatures ManifestSignatures
}
type LastUpdatedImage struct {
Descriptor
Tag string
LastUpdated *time.Time
}
type ReferrerInfo struct {
@ -217,21 +279,6 @@ type DescriptorStatistics struct {
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 {
LayerDigest string
LayerContent []byte

View file

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

View file

@ -3,7 +3,6 @@ package storage
import (
"encoding/json"
"fmt"
"regexp"
"strings"
"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
}
// check cosign
cosignTagRule := regexp.MustCompile(`sha256\-.+\.sig`)
if tag := reference; cosignTagRule.MatchString(reference) {
if tag := reference; zcommon.IsCosignTag(reference) {
prefixLen := len("sha256-")
digestLen := 64
signedImageManifestDigestEncoded := tag[prefixLen : prefixLen+digestLen]

View file

@ -211,3 +211,35 @@ func GenerateRandomName() (string, int64) {
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
return image.MultiarchImage{
Index: index, Images: images, Reference: reference,
Index: index, Images: images,
}, err
}

View file

@ -11,6 +11,7 @@ import (
"github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
mTypes "zotregistry.io/zot/pkg/meta/types"
storageConstants "zotregistry.io/zot/pkg/storage/constants"
)
@ -48,6 +49,9 @@ type ConfigBuilder interface {
// an OCI artifact.
// (see: https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidelines-for-artifact-usage)
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() ManifestBuilder
// 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 {
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)
if err != nil {
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)
}
@ -106,6 +114,16 @@ func (img *Image) DigestStr() 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 {
return ispec.Descriptor{
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 {
Blob []byte
MediaType string
@ -281,6 +315,16 @@ func (ib *BaseImageBuilder) DefaultConfig() ManifestBuilder {
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 {
ib.configDescriptor = ispec.DescriptorEmptyJSON

View file

@ -166,16 +166,6 @@ func TestPredefinedImages(t *testing.T) {
img = CreateRandomVulnerableImageWith().ArtifactType("art.type").Build()
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) {

View file

@ -11,9 +11,8 @@ import (
)
type MultiarchImage struct {
Index ispec.Index
Images []Image
Reference string
Index ispec.Index
Images []Image
IndexDescriptor ispec.Descriptor
}
@ -31,17 +30,27 @@ func (mi *MultiarchImage) DigestStr() string {
return mi.Digest().String()
}
func (mi *MultiarchImage) IndexData() mTypes.IndexData {
indexBlob, err := json.Marshal(mi.Index)
if err != nil {
panic("unreachable: ispec.Index should always be marshable")
func (mi MultiarchImage) AsImageMeta() mTypes.ImageMeta {
index := mi.Index
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 {
Images(images []Image) MultiarchBuilder
RandomImages(count int) MultiarchBuilder
}
type MultiarchBuilder interface {
@ -88,6 +97,18 @@ func (mb *BaseMultiarchBuilder) Images(images []Image) MultiarchBuilder {
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 {
mb.subject = subject
@ -135,12 +156,9 @@ func (mb *BaseMultiarchBuilder) Build() MultiarchImage {
indexDigest := godigest.FromBytes(indexBlob)
ref := indexDigest.String()
return MultiarchImage{
Index: index,
Images: mb.images,
Reference: ref,
Index: index,
Images: mb.images,
IndexDescriptor: ispec.Descriptor{
MediaType: ispec.MediaTypeImageIndex,

View file

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

View file

@ -176,21 +176,3 @@ func GetRandomImageConfig() ([]byte, godigest.Digest) {
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 {
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)
GetBookmarkedReposFn func(ctx context.Context) ([]string, error)
@ -112,6 +44,69 @@ type MetaDBMock struct {
ImageTrustStoreFn 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 {
@ -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 {
if sdm.PatchDBFn != nil {
return sdm.PatchDBFn()
@ -351,34 +131,6 @@ func (sdm MetaDBMock) PatchDB() error {
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) {
if sdm.GetStarredReposFn != nil {
return sdm.GetStarredReposFn(ctx)
@ -498,3 +250,184 @@ func (sdm MetaDBMock) DeleteUserAPIKey(ctx context.Context, id string) error {
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
import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"context"
"fmt"
zerr "zotregistry.io/zot/errors"
mTypes "zotregistry.io/zot/pkg/meta/types"
reqCtx "zotregistry.io/zot/pkg/requestcontext"
imageUtil "zotregistry.io/zot/pkg/test/image-utils"
)
type RepoImage struct {
imageUtil.Image
Tag string
Reference string
Statistics mTypes.DescriptorStatistics
}
type RepoMultiArchImage struct {
imageUtil.MultiarchImage
ImageStatistics map[string]mTypes.DescriptorStatistics
Tag string
Reference string
}
type Repo struct {
Name string
Images []RepoImage
MultiArchImages []RepoMultiArchImage
Signatures map[string]mTypes.ManifestSignatures
Stars int
IsBookmarked bool
IsStarred bool
}
func GetMetadataForRepos(repos ...Repo) ([]mTypes.RepoMetadata, map[string]mTypes.ManifestMetadata,
map[string]mTypes.IndexData,
) {
var (
reposMetadata = []mTypes.RepoMetadata{}
manifestMetadataMap = map[string]mTypes.ManifestMetadata{}
indexDataMap = map[string]mTypes.IndexData{}
)
func InitializeTestMetaDB(ctx context.Context, metaDB mTypes.MetaDB, repos ...Repo) (context.Context, error) {
uac := reqCtx.NewUserAccessControl()
uac.SetUsername("test")
uacContext := context.WithValue(ctx, reqCtx.GetContextKey(), *uac)
err := validateRepos(repos)
if err != nil {
return uacContext, err
}
for _, repo := range repos {
repoMeta := mTypes.RepoMetadata{
Name: repo.Name,
Tags: map[string]mTypes.Descriptor{},
Signatures: map[string]mTypes.ManifestSignatures{},
Statistics: map[string]mTypes.DescriptorStatistics{},
IsStarred: repo.IsStarred,
IsBookmarked: repo.IsBookmarked,
}
statistics := map[string]mTypes.DescriptorStatistics{"": {}}
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 {
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 {
addImageMetaToMetaDB(RepoImage{
Image: image,
Statistics: multiArch.ImageStatistics[image.DigestStr()],
}, repoMeta, manifestMetadataMap)
err := metaDB.SetRepoReference(repo.Name, image.DigestStr(), image.AsImageMeta())
if err != nil {
return uacContext, err
}
statistics[image.DigestStr()] = multiArch.ImageStatistics[image.DigestStr()]
}
indexDataMap[multiArch.IndexDescriptor.Digest.String()] = mTypes.IndexData{
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)
}
return reposMetadata, manifestMetadataMap, indexDataMap
}
func addImageMetaToMetaDB(image RepoImage, repoMeta mTypes.RepoMetadata,
manifestMetadataMap map[string]mTypes.ManifestMetadata,
) {
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
if image.Manifest.ArtifactType == imageUtil.TestFakeSignatureArtType && image.Manifest.Subject != nil {
signedManifestDig := image.Manifest.Subject.Digest.String()
repoMeta.Signatures[signedManifestDig] = mTypes.ManifestSignatures{
"fakeSignature": []mTypes.SignatureInfo{{SignatureManifestDigest: image.ManifestDescriptor.Digest.String()}},
if repo.IsStarred {
_, err := metaDB.ToggleStarRepo(uacContext, repo.Name)
if err != nil {
return uacContext, err
}
}
}
repoMeta.Statistics[image.DigestStr()] = image.Statistics
return uacContext, nil
}
manifestMetadataMap[image.DigestStr()] = mTypes.ManifestMetadata{
ManifestBlob: image.ManifestDescriptor.Data,
ConfigBlob: image.ConfigDescriptor.Data,
DownloadCount: image.Statistics.DownloadCount,
func validateRepos(repos []Repo) error {
repoNames := map[string]struct{}{}
for _, repo := range repos {
if _, found := repoNames[repo.Name]; found {
return fmt.Errorf("%w '%s'", zerr.ErrMultipleReposSameName, repo.Name)
}
repoNames[repo.Name] = struct{}{}
}
return nil
}
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",
"cacheTablename": "BlobTable",
"repoMetaTablename": "RepoMetadataTable",
"manifestDataTablename": "ManifestDataTable",
"indexDataTablename": "IndexDataTable",
"imageMetaTablename": "ImageMetaTable",
"repoBlobsInfoTablename": "RepoBlobsInfoTable",
"userDataTablename": "UserDataTable",
"apiKeyTablename":"ApiKeyTable",
"versionTablename": "Version"