From 8d27fbd04e3b2e3b177b40a09c13dbb094db347c Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani Date: Mon, 18 Sep 2023 21:54:02 +0000 Subject: [PATCH] feat: improve UX by speeding up metadb serialize/deserialize Use protocol buffers and update the metadb interface to better suit our search needs Signed-off-by: Ramkumar Chinchani Signed-off-by: Laurentiu Niculae --- .github/workflows/golangci-lint.yaml | 1 + Makefile | 55 +- pkg/api/controller.go | 1 + pkg/common/oci.go | 20 + pkg/extensions/imagetrust/image_trust.go | 34 +- .../imagetrust/image_trust_disabled.go | 9 + pkg/extensions/imagetrust/image_trust_test.go | 8 - pkg/extensions/search/convert/metadb.go | 1065 +++++++++++ pkg/extensions/search/resolver.go | 461 +++-- pkg/extensions/search/resolver_test.go | 2 +- pkg/extensions/search/schema.resolvers.go | 2 +- pkg/extensions/search/search_test.go | 2 + pkg/meta/boltdb/boltdb.go | 18 + pkg/meta/boltdb/boltdb_test.go | 7 + pkg/meta/boltdb/buckets.go | 6 + pkg/meta/boltdb/proto_boltdb.go | 1109 ++++++++++++ pkg/meta/common/common.go | 145 ++ pkg/meta/convert/convert.go | 317 ++++ pkg/meta/convert/convert2.go | 555 ++++++ pkg/meta/convert/convert_full.go | 18 + pkg/meta/dynamodb/dynamodb.go | 1230 ++++++++++++- pkg/meta/dynamodb/dynamodb_test.go | 87 +- pkg/meta/hooks.go | 45 + pkg/meta/parse.go | 178 +- pkg/meta/proto/config.proto | 46 + pkg/meta/proto/descriptor.proto | 20 + pkg/meta/proto/imageData.proto | 121 ++ pkg/meta/proto/index.proto | 16 + pkg/meta/proto/manifest.proto | 17 + pkg/meta/proto/timestamp.proto | 144 ++ pkg/meta/proto/versioned.proto | 8 + pkg/meta/proto_go/config.pb.go | 644 +++++++ pkg/meta/proto_go/descriptor.pb.go | 293 +++ pkg/meta/proto_go/imageData.pb.go | 1566 +++++++++++++++++ pkg/meta/proto_go/index.pb.go | 215 +++ pkg/meta/proto_go/manifest.pb.go | 226 +++ pkg/meta/proto_go/versioned.pb.go | 141 ++ pkg/meta/proto_test.go | 208 +++ pkg/meta/types/types.go | 168 +- pkg/test/mocks/repo_db_mock.go | 130 ++ 40 files changed, 9125 insertions(+), 213 deletions(-) create mode 100644 pkg/meta/boltdb/proto_boltdb.go create mode 100644 pkg/meta/convert/convert.go create mode 100644 pkg/meta/convert/convert2.go create mode 100644 pkg/meta/convert/convert_full.go create mode 100644 pkg/meta/proto/config.proto create mode 100644 pkg/meta/proto/descriptor.proto create mode 100644 pkg/meta/proto/imageData.proto create mode 100644 pkg/meta/proto/index.proto create mode 100644 pkg/meta/proto/manifest.proto create mode 100644 pkg/meta/proto/timestamp.proto create mode 100644 pkg/meta/proto/versioned.proto create mode 100644 pkg/meta/proto_go/config.pb.go create mode 100644 pkg/meta/proto_go/descriptor.pb.go create mode 100644 pkg/meta/proto_go/imageData.pb.go create mode 100644 pkg/meta/proto_go/index.pb.go create mode 100644 pkg/meta/proto_go/manifest.pb.go create mode 100644 pkg/meta/proto_go/versioned.pb.go create mode 100644 pkg/meta/proto_test.go diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 6e278a56cb..201d0fd13f 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -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 diff --git a/Makefile b/Makefile index c0e51a9ad4..4d0287c38e 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,8 @@ ZUI_VERSION := commit-fad5572 SWAGGER_VERSION := v1.8.12 STACKER := $(TOOLSDIR)/bin/stacker BATS := $(TOOLSDIR)/bin/bats +PROTOC_VERSION := 3.15.8 +PROTOC := $(TOOLSDIR)/bin/protoc TESTDATA := $(TOP_LEVEL)/test/data OS ?= $(shell go env GOOS) ARCH ?= $(shell go env GOARCH) @@ -71,7 +73,7 @@ modtidy: go mod tidy .PHONY: modcheck -modcheck: modtidy +modcheck: gen-protobuf modtidy $(eval UNCOMMITED_FILES = $(shell git status --porcelain | grep -c 'go.mod\|go.sum')) @if [ $(UNCOMMITED_FILES) != 0 ]; then \ echo "Updated go.mod and/or go.sum have uncommitted changes, commit the changes accordingly ";\ @@ -97,6 +99,47 @@ 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: $(PROTOC) + $(PROTOC) --experimental_allow_proto3_optional \ + --proto_path=$(TOP_LEVEL)/pkg/meta/proto \ + --go_out=$(TOP_LEVEL)/pkg/meta/ \ + --go_opt='Mdescriptor.proto=./proto_go' \ + $(TOP_LEVEL)/pkg/meta/proto/descriptor.proto + $(PROTOC) --experimental_allow_proto3_optional \ + --proto_path=$(TOP_LEVEL)/pkg/meta/proto \ + --go_out=$(TOP_LEVEL)/pkg/meta/ \ + --go_opt='Mconfig.proto=./proto_go' \ + --go_opt='Mdescriptor.proto=./proto_go' \ + $(TOP_LEVEL)/pkg/meta/proto/config.proto + $(PROTOC) --experimental_allow_proto3_optional \ + --proto_path=$(TOP_LEVEL)/pkg/meta/proto \ + --go_out=$(TOP_LEVEL)/pkg/meta/ \ + --go_opt='Mversioned.proto=./proto_go' \ + $(TOP_LEVEL)/pkg/meta/proto/versioned.proto + $(PROTOC) --experimental_allow_proto3_optional \ + --proto_path=$(TOP_LEVEL)/pkg/meta/proto \ + --go_out=$(TOP_LEVEL)/pkg/meta/ \ + --go_opt='Mmanifest.proto=./proto_go' \ + --go_opt='Mdescriptor.proto=./proto_go' \ + --go_opt='Mversioned.proto=./proto_go' \ + $(TOP_LEVEL)/pkg/meta/proto/manifest.proto + $(PROTOC) --experimental_allow_proto3_optional \ + --proto_path=$(TOP_LEVEL)/pkg/meta/proto \ + --go_out=$(TOP_LEVEL)/pkg/meta/ \ + --go_opt='Mindex.proto=./proto_go' \ + --go_opt='Mdescriptor.proto=./proto_go' \ + --go_opt='Mversioned.proto=./proto_go' \ + $(TOP_LEVEL)/pkg/meta/proto/index.proto + $(PROTOC) --experimental_allow_proto3_optional \ + --proto_path=$(TOP_LEVEL)/pkg/meta/proto \ + --go_out=$(TOP_LEVEL)/pkg/meta/ \ + --go_opt='MimageData.proto=./proto_go' \ + --go_opt='Mdescriptor.proto=./proto_go' \ + --go_opt='Mversioned.proto=./proto_go' \ + --go_opt='Mconfig.proto=./proto_go' \ + $(TOP_LEVEL)/pkg/meta/proto/imageData.proto + .PHONY: binary-minimal binary-minimal: EXTENSIONS= binary-minimal: modcheck build-metadata @@ -218,6 +261,12 @@ $(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)-linux-x86_64.zip + unzip -d $(TOOLSDIR) protoc.zip bin/protoc + chmod +x $(PROTOC) + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest $(ACTION_VALIDATOR): mkdir -p $(TOOLSDIR)/bin @@ -242,7 +291,7 @@ $(GOLINTER): .PHONY: check check: $(if $(findstring ui,$(BUILD_LABELS)), ui) -check: ./golangcilint.yaml $(GOLINTER) +check: ./golangcilint.yaml modcheck $(GOLINTER) mkdir -p pkg/extensions/build; touch pkg/extensions/build/.empty $(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags containers_image_openpgp ./... $(GOLINTER) --config ./golangcilint.yaml run --enable-all --out-format=colored-line-number --build-tags $(BUILD_LABELS),containers_image_openpgp ./... @@ -339,7 +388,7 @@ verify-config-commited: _verify-config fi; \ .PHONY: gqlgen -gqlgen: +gqlgen: gen-protobuf cd pkg/extensions/search;\ go run github.com/99designs/gqlgen version;\ go run github.com/99designs/gqlgen generate diff --git a/pkg/api/controller.go b/pkg/api/controller.go index e958048d77..fcf2d353cb 100644 --- a/pkg/api/controller.go +++ b/pkg/api/controller.go @@ -293,6 +293,7 @@ func (c *Controller) InitMetaDB(reloadCtx context.Context) error { return err } + // TODO: undo, commented for testing err = meta.ParseStorage(driver, c.StoreController, c.Log) if err != nil { return err diff --git a/pkg/common/oci.go b/pkg/common/oci.go index f4baf303cf..4981aac457 100644 --- a/pkg/common/oci.go +++ b/pkg/common/oci.go @@ -6,8 +6,10 @@ import ( "github.com/opencontainers/go-digest" ispec "github.com/opencontainers/image-spec/specs-go/v1" + "google.golang.org/protobuf/types/known/timestamppb" zerr "zotregistry.io/zot/errors" + "zotregistry.io/zot/pkg/meta/proto_go" ) func GetImageDirAndTag(imageName string) (string, string) { @@ -84,6 +86,24 @@ func GetImageLastUpdated(imageInfo ispec.Image) time.Time { return *timeStamp } +func GetProtoImageLastUpdated(configData *proto_go.ConfigData) time.Time { + timeStamp := configData.Created + + if timeStamp != nil && !timeStamp.AsTime().IsZero() { + return timeStamp.AsTime() + } + + if len(configData.History) > 0 { + timeStamp = configData.History[len(configData.History)-1].Created + } + + if timeStamp == nil { + timeStamp = timestamppb.New(time.Time{}) + } + + return timeStamp.AsTime() +} + // GetRepoReference returns the components of a repoName:tag or repoName@digest string. If the format is wrong // an error is returned. // The returned values have the following meaning: diff --git a/pkg/extensions/imagetrust/image_trust.go b/pkg/extensions/imagetrust/image_trust.go index 273f2d9076..b29208ae3a 100644 --- a/pkg/extensions/imagetrust/image_trust.go +++ b/pkg/extensions/imagetrust/image_trust.go @@ -157,19 +157,47 @@ func IsResourceExistsException(err error) bool { return false } +func (imgTrustStore *ImageTrustStore) ProtoVerifySignature( + signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, imageData mTypes.ImageData2, + repo string, +) (string, time.Time, bool, error) { + desc := ispec.Descriptor{ + MediaType: imageData.MediaType, + Digest: imageData.Digest, + Size: imageData.Size, + } + + if manifestDigest.String() == "" { + return "", time.Time{}, false, zerr.ErrBadManifestDigest + } + + switch signatureType { + case zcommon.CosignSignature: + author, isValid, err := VerifyCosignSignature(imgTrustStore.CosignStorage, repo, manifestDigest, sigKey, rawSignature) + + return author, time.Time{}, isValid, err + case zcommon.NotationSignature: + return VerifyNotationSignature(imgTrustStore.NotationStorage, desc, manifestDigest.String(), rawSignature, sigKey) + default: + return "", time.Time{}, false, zerr.ErrInvalidSignatureType + } +} + func (imgTrustStore *ImageTrustStore) VerifySignature( - signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, manifestContent []byte, + signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, blob []byte, repo string, ) (string, time.Time, bool, error) { var manifest ispec.Manifest - if err := json.Unmarshal(manifestContent, &manifest); err != nil { + + err := json.Unmarshal(blob, &manifest) + if err != nil { return "", time.Time{}, false, err } desc := ispec.Descriptor{ MediaType: manifest.MediaType, Digest: manifestDigest, - Size: int64(len(manifestContent)), + Size: int64(len(blob)), } if manifestDigest.String() == "" { diff --git a/pkg/extensions/imagetrust/image_trust_disabled.go b/pkg/extensions/imagetrust/image_trust_disabled.go index dda917a30f..b2390970ee 100644 --- a/pkg/extensions/imagetrust/image_trust_disabled.go +++ b/pkg/extensions/imagetrust/image_trust_disabled.go @@ -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) { @@ -25,3 +27,10 @@ func (imgTrustStore *imageTrustDisabled) VerifySignature( ) (string, time.Time, bool, error) { return "", time.Time{}, false, nil } + +func (imgTrustStore *imageTrustDisabled) ProtoVerifySignature( + signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, imageData mTypes.ImageData2, + repo string, +) (string, time.Time, bool, error) { + return "", time.Time{}, false, nil +} diff --git a/pkg/extensions/imagetrust/image_trust_test.go b/pkg/extensions/imagetrust/image_trust_test.go index 892b21e6b9..c3db0b1983 100644 --- a/pkg/extensions/imagetrust/image_trust_test.go +++ b/pkg/extensions/imagetrust/image_trust_test.go @@ -150,14 +150,6 @@ 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 diff --git a/pkg/extensions/search/convert/metadb.go b/pkg/extensions/search/convert/metadb.go index 5ff8f03292..64b7c63135 100644 --- a/pkg/extensions/search/convert/metadb.go +++ b/pkg/extensions/search/convert/metadb.go @@ -21,6 +21,7 @@ import ( "zotregistry.io/zot/pkg/extensions/search/pagination" "zotregistry.io/zot/pkg/log" mcommon "zotregistry.io/zot/pkg/meta/common" + "zotregistry.io/zot/pkg/meta/proto_go" mTypes "zotregistry.io/zot/pkg/meta/types" ) @@ -115,6 +116,95 @@ func RepoMeta2RepoSummary(ctx context.Context, repoMeta mTypes.RepoMetadata, } } +func ProtoImageData2RepoSummary(ctx context.Context, repo string, imageDataList []*proto_go.ImageData, +) *gql_generated.RepoSummary { + var ( + repoName = repo + repoLastUpdatedTimestamp = time.Time{} + repoPlatformsSet = map[string]*gql_generated.Platform{} + repoVendorsSet = map[string]bool{} + lastUpdatedImageSummary *gql_generated.ImageSummary + repoDownloadCount = 0 + // repoStarCount = repoMeta.Stars // total number of stars + // repoIsUserStarred = repoMeta.IsStarred // value specific to the current user + // repoIsUserBookMarked = repoMeta.IsBookmarked // value specific to the current user + + // map used to keep track of all blobs of a repo without duplicates as + // some images may have the same layers + repoBlob2Size = make(map[string]int64, 10) + + // made up of all manifests, configs and image layers + size = int64(0) + ) + + for _, imageData := range imageDataList { + imageSummary, imageBlobsMap, err := ProtoImageData2ImageSummary(ctx, imageData) + if err != nil { + continue + } + + for blobDigest, blobSize := range imageBlobsMap { + repoBlob2Size[blobDigest] = blobSize + } + + for _, manifestSummary := range imageSummary.Manifests { + if *manifestSummary.Platform.Os != "" || *manifestSummary.Platform.Arch != "" { + opSys, arch := *manifestSummary.Platform.Os, *manifestSummary.Platform.Arch + + platformString := strings.TrimSpace(fmt.Sprintf("%s %s", opSys, arch)) + repoPlatformsSet[platformString] = &gql_generated.Platform{Os: &opSys, Arch: &arch} + } + } + + repoDownloadCount += *imageSummary.DownloadCount + + if *imageSummary.Vendor != "" { + repoVendorsSet[*imageSummary.Vendor] = true + } + + lastUpdatedImageSummary = UpdateLastUpdatedTimestamp(&repoLastUpdatedTimestamp, lastUpdatedImageSummary, imageSummary) + } + + // calculate repo size = sum all manifest, config and layer blobs sizes + for _, blobSize := range repoBlob2Size { + size += blobSize + } + + repoSize := strconv.FormatInt(size, 10) + + repoPlatforms := make([]*gql_generated.Platform, 0, len(repoPlatformsSet)) + + for _, platform := range repoPlatformsSet { + repoPlatforms = append(repoPlatforms, platform) + } + + repoVendors := make([]*string, 0, len(repoVendorsSet)) + + for vendor := range repoVendorsSet { + vendor := vendor + repoVendors = append(repoVendors, &vendor) + } + + return &gql_generated.RepoSummary{ + Name: &repoName, + LastUpdated: &repoLastUpdatedTimestamp, + Size: &repoSize, + Platforms: repoPlatforms, + Vendors: repoVendors, + NewestImage: lastUpdatedImageSummary, + DownloadCount: &repoDownloadCount, + // StarCount: &repoStarCount, + // IsBookmarked: &repoIsUserBookMarked, + // IsStarred: &repoIsUserStarred, + // Rank: &repoMeta.Rank, + } +} + +func ProtoImageData2ImageSummary(ctx context.Context, imageData *proto_go.ImageData, +) (*gql_generated.ImageSummary, map[string]int64, error) { + panic("unimplemented") +} + func PaginatedRepoMeta2RepoSummaries(ctx context.Context, reposMeta []mTypes.RepoMetadata, manifestMetaMap map[string]mTypes.ManifestMetadata, indexDataMap map[string]mTypes.IndexData, skip SkipQGLField, cveInfo cveinfo.CveInfo, filter mTypes.Filter, pageInput pagination.PageInput, @@ -546,6 +636,40 @@ func RepoMeta2ImageSummaries(ctx context.Context, repoMeta mTypes.RepoMetadata, return imageSummaries } +func ProtoRepoMeta2ImageSummaries(ctx context.Context, repoMeta mTypes.RepoMetadata2, + imageData map[string]mTypes.ImageData2, skip SkipQGLField, cveInfo cveinfo.CveInfo, +) []*gql_generated.ImageSummary { + imageSummaries := make([]*gql_generated.ImageSummary, 0, len(repoMeta.Tags)) + + // Make sure the tags are sorted + // We need to implement a proper fix for this taking into account + // the sorting criteria used in the requested page + tags := make([]string, 0, len(repoMeta.Tags)) + for tag := range repoMeta.Tags { + tags = append(tags, tag) + } + + // Sorting ascending by tag name should do for now + sort.Strings(tags) + + for _, tag := range tags { + descriptor := repoMeta.Tags[tag] + + imageSummary, _, err := ProtoDescriptor2ImageSummary(ctx, descriptor, repoMeta.Name, tag, + repoMeta, imageData) + if err != nil { + continue + } + + // CVE scanning is expensive, only scan for final slice of results + updateImageSummaryVulnerabilities(ctx, imageSummary, skip, cveInfo) + + imageSummaries = append(imageSummaries, imageSummary) + } + + return imageSummaries +} + func PaginatedRepoMeta2ImageSummaries(ctx context.Context, reposMeta []mTypes.RepoMetadata, manifestMetaMap map[string]mTypes.ManifestMetadata, indexDataMap map[string]mTypes.IndexData, skip SkipQGLField, cveInfo cveinfo.CveInfo, filter mTypes.Filter, pageInput pagination.PageInput, @@ -677,6 +801,46 @@ func RepoMeta2ExpandedRepoInfo(ctx context.Context, repoMeta mTypes.RepoMetadata return summary, imageSummaries } +func FullRepoMeta2ExpandedRepoInfo(ctx context.Context, repoMeta mTypes.FullRepoMetadata, + imageDataMap map[string]mTypes.ImageData2, skip SkipQGLField, cveInfo cveinfo.CveInfo, log log.Logger, +) (*gql_generated.RepoSummary, []*gql_generated.ImageSummary) { + repoName := repoMeta.Name + imageSummaries := make([]*gql_generated.ImageSummary, 0, len(repoMeta.Tags)) + + for tag, descriptor := range repoMeta.Tags { + imageData := imageDataMap[descriptor.Digest] + + imageSummary, _, err := FullImageData2ImageSummary(ctx, mTypes.FullImageData{ + Repo: repoName, + Tag: tag, + MediaType: descriptor.MediaType, + Digest: godigest.Digest(descriptor.Digest), + Size: imageData.Size, + Index: imageData.Index, + Manifests: getFullManifestData(repoMeta, imageData.Manifests), + Referrers: repoMeta.Referrers[descriptor.Digest], + Statistics: repoMeta.Statistics[descriptor.Digest], + Signatures: repoMeta.Signatures[descriptor.Digest], + }) + if err != nil { + log.Error().Str("repository", repoName).Str("reference", tag). + Msg("metadb: error while converting descriptor for image") + + continue + } + + updateImageSummaryVulnerabilities(ctx, imageSummary, skip, cveInfo) + + imageSummaries = append(imageSummaries, imageSummary) + } + + repoSummary := FullRepoMeta2RepoSummary(ctx, repoMeta, imageDataMap) + + updateRepoSummaryVulnerabilities(ctx, repoSummary, skip, cveInfo) + + return repoSummary, imageSummaries +} + func StringMap2Annotations(strMap map[string]string) []*gql_generated.Annotation { annotations := make([]*gql_generated.Annotation, 0, len(strMap)) @@ -776,3 +940,904 @@ func GetSignaturesInfo(isSigned bool, repoMeta mTypes.RepoMetadata, indexDigest return signaturesInfo } + +func ProtoGetSignaturesInfo(isSigned bool, repoMeta mTypes.RepoMetadata2, indexDigest godigest.Digest, +) []*gql_generated.SignatureSummary { + signaturesInfo := []*gql_generated.SignatureSummary{} + + if !isSigned { + return signaturesInfo + } + + for sigType, signatures := range repoMeta.Signatures[indexDigest.String()] { + for _, sig := range signatures { + for _, layer := range sig.LayersInfo { + var ( + isTrusted bool + author string + tool string + ) + + if layer.Signer != "" { + author = layer.Signer + + if !layer.Date.IsZero() && time.Now().After(layer.Date) { + isTrusted = false + } else { + isTrusted = true + } + } else { + isTrusted = false + author = "" + } + + tool = sigType + + signaturesInfo = append(signaturesInfo, + &gql_generated.SignatureSummary{Tool: &tool, IsTrusted: &isTrusted, Author: &author}) + } + } + } + + return signaturesInfo +} + +func FullGetSignaturesInfo(isSigned bool, signatures mTypes.ManifestSignatures, indexDigest godigest.Digest, +) []*gql_generated.SignatureSummary { + signaturesInfo := []*gql_generated.SignatureSummary{} + + if !isSigned { + return signaturesInfo + } + + for sigType, signatures := range signatures { + for _, sig := range signatures { + for _, layer := range sig.LayersInfo { + var ( + isTrusted bool + author string + tool string + ) + + if layer.Signer != "" { + author = layer.Signer + + if !layer.Date.IsZero() && time.Now().After(layer.Date) { + isTrusted = false + } else { + isTrusted = true + } + } else { + isTrusted = false + author = "" + } + + tool = sigType + + signaturesInfo = append(signaturesInfo, + &gql_generated.SignatureSummary{Tool: &tool, IsTrusted: &isTrusted, Author: &author}) + } + } + } + + return signaturesInfo +} + +func PaginatedProtoRepoMeta2RepoSummaries(ctx context.Context, repoMetaList []mTypes.RepoMetadata2, + imageDataMap map[string]mTypes.ImageData2, filter mTypes.Filter, pageInput pagination.PageInput, cveInfo cveinfo.CveInfo, + skip SkipQGLField, +) ([]*gql_generated.RepoSummary, zcommon.PageInfo, error) { + reposPageFinder, err := pagination.NewRepoSumPageFinder(pageInput.Limit, pageInput.Offset, pageInput.SortBy) + if err != nil { + return []*gql_generated.RepoSummary{}, zcommon.PageInfo{}, err + } + + for _, repoMeta := range repoMetaList { + repoSummary := ProtoRepoMeta2RepoSummary(ctx, repoMeta, imageDataMap) + + if RepoSumAcceptedByFilter(repoSummary, filter) { + reposPageFinder.Add(repoSummary) + } + } + + page, pageInfo := reposPageFinder.Page() + + // CVE scanning is expensive, only scan for the current page + for _, repoSummary := range page { + updateRepoSummaryVulnerabilities(ctx, repoSummary, skip, cveInfo) + } + + return page, pageInfo, nil +} + +func PaginatedFullRepoMeta2RepoSummaries(ctx context.Context, repoMetaList []mTypes.FullRepoMetadata, + imageDataMap map[string]mTypes.ImageData2, filter mTypes.Filter, pageInput pagination.PageInput, cveInfo cveinfo.CveInfo, + skip SkipQGLField, +) ([]*gql_generated.RepoSummary, zcommon.PageInfo, error) { + reposPageFinder, err := pagination.NewRepoSumPageFinder(pageInput.Limit, pageInput.Offset, pageInput.SortBy) + if err != nil { + return []*gql_generated.RepoSummary{}, zcommon.PageInfo{}, err + } + + for _, repoMeta := range repoMetaList { + repoSummary := FullRepoMeta2RepoSummary(ctx, repoMeta, imageDataMap) + + if RepoSumAcceptedByFilter(repoSummary, filter) { + reposPageFinder.Add(repoSummary) + } + } + + page, pageInfo := reposPageFinder.Page() + + // CVE scanning is expensive, only scan for the current page + for _, repoSummary := range page { + updateRepoSummaryVulnerabilities(ctx, repoSummary, skip, cveInfo) + } + + return page, pageInfo, nil +} + +func ProtoRepoMeta2RepoSummary(ctx context.Context, repoMeta mTypes.RepoMetadata2, imageDataMap map[string]mTypes.ImageData2, +) *gql_generated.RepoSummary { + var ( + repoName = repoMeta.Name + repoLastUpdatedTimestamp = time.Time{} + repoPlatformsSet = map[string]*gql_generated.Platform{} + repoVendorsSet = map[string]bool{} + lastUpdatedImageSummary *gql_generated.ImageSummary + repoDownloadCount = 0 + repoStarCount = int(repoMeta.Stars) // total number of stars + repoIsUserStarred = repoMeta.IsStarred // value specific to the current user + repoIsUserBookMarked = repoMeta.IsBookmarked // value specific to the current user + + // map used to keep track of all blobs of a repo without duplicates as + // some images may have the same layers + repoBlob2Size = make(map[string]int64, 10) + + // made up of all manifests, configs and image layers + size = int64(0) + ) + + for tag, descriptor := range repoMeta.Tags { + imageSummary, imageBlobsMap, err := ProtoDescriptor2ImageSummary(ctx, descriptor, repoMeta.Name, + tag, repoMeta, imageDataMap, + ) + if err != nil { + continue + } + + for blobDigest, blobSize := range imageBlobsMap { + repoBlob2Size[blobDigest] = blobSize + } + + for _, manifestSummary := range imageSummary.Manifests { + if *manifestSummary.Platform.Os != "" || *manifestSummary.Platform.Arch != "" { + opSys, arch := *manifestSummary.Platform.Os, *manifestSummary.Platform.Arch + + platformString := strings.TrimSpace(fmt.Sprintf("%s %s", opSys, arch)) + repoPlatformsSet[platformString] = &gql_generated.Platform{Os: &opSys, Arch: &arch} + } + } + + repoDownloadCount += *imageSummary.DownloadCount + + if *imageSummary.Vendor != "" { + repoVendorsSet[*imageSummary.Vendor] = true + } + + lastUpdatedImageSummary = UpdateLastUpdatedTimestamp(&repoLastUpdatedTimestamp, lastUpdatedImageSummary, imageSummary) + } + + // calculate repo size = sum all manifest, config and layer blobs sizes + for _, blobSize := range repoBlob2Size { + size += blobSize + } + + repoSize := strconv.FormatInt(size, 10) + + repoPlatforms := make([]*gql_generated.Platform, 0, len(repoPlatformsSet)) + + for _, platform := range repoPlatformsSet { + repoPlatforms = append(repoPlatforms, platform) + } + + repoVendors := make([]*string, 0, len(repoVendorsSet)) + + for vendor := range repoVendorsSet { + vendor := vendor + repoVendors = append(repoVendors, &vendor) + } + + return &gql_generated.RepoSummary{ + Name: &repoName, + LastUpdated: &repoLastUpdatedTimestamp, + Size: &repoSize, + Platforms: repoPlatforms, + Vendors: repoVendors, + NewestImage: lastUpdatedImageSummary, + DownloadCount: &repoDownloadCount, + StarCount: &repoStarCount, + IsBookmarked: &repoIsUserBookMarked, + IsStarred: &repoIsUserStarred, + Rank: ref(int(repoMeta.Rank)), + } +} + +func FullRepoMeta2RepoSummary(ctx context.Context, repoMeta mTypes.FullRepoMetadata, imageDataMap map[string]mTypes.ImageData2, +) *gql_generated.RepoSummary { + var ( + repoName = repoMeta.Name + repoLastUpdatedTimestamp = repoMeta.LastUpdatedImage.LastUpdated + repoPlatforms = repoMeta.Platforms + repoVendors = repoMeta.Vendors + repoDownloadCount = repoMeta.DownloadCount + repoStarCount = repoMeta.StarCount + repoIsUserStarred = repoMeta.IsStarred // value specific to the current user + repoIsUserBookMarked = repoMeta.IsBookmarked // value specific to the current user + repoSize = repoMeta.Size + ) + + lastUpdatedImageData := imageDataMap[repoMeta.LastUpdatedImage.Digest] + if repoLastUpdatedTimestamp == nil { + repoLastUpdatedTimestamp = &time.Time{} + } + + imageSummary, _, err := FullImageData2ImageSummary(ctx, mTypes.FullImageData{ + Repo: repoMeta.Name, + Tag: repoMeta.LastUpdatedImage.Tag, + MediaType: repoMeta.LastUpdatedImage.MediaType, + Digest: godigest.Digest(repoMeta.LastUpdatedImage.Digest), + Size: lastUpdatedImageData.Size, + Index: lastUpdatedImageData.Index, + Manifests: getFullManifestData(repoMeta, lastUpdatedImageData.Manifests), + Referrers: repoMeta.Referrers[repoMeta.LastUpdatedImage.Digest], + Statistics: repoMeta.Statistics[repoMeta.LastUpdatedImage.Digest], + Signatures: repoMeta.Signatures[repoMeta.LastUpdatedImage.Digest], + }) + + _ = err + + return &gql_generated.RepoSummary{ + Name: &repoName, + LastUpdated: repoLastUpdatedTimestamp, + Size: ref(strconv.FormatInt(repoSize, 10)), + Platforms: getGqlPlatforms(repoPlatforms), + Vendors: getGqlVendors(repoVendors), + NewestImage: imageSummary, + DownloadCount: &repoDownloadCount, + StarCount: &repoStarCount, + IsBookmarked: &repoIsUserBookMarked, + IsStarred: &repoIsUserStarred, + Rank: ref(int(repoMeta.Rank)), + } +} + +func getFullManifestData(repoMeta mTypes.FullRepoMetadata, manifests []mTypes.ManifestData2) []mTypes.FullManifestData { + results := make([]mTypes.FullManifestData, 0, len(manifests)) + + for i := range manifests { + results = append(results, mTypes.FullManifestData{ + ManifestData2: manifests[i], + Referrers: repoMeta.Referrers[manifests[i].Digest.String()], + Statistics: repoMeta.Statistics[manifests[i].Digest.String()], + Signatures: repoMeta.Signatures[manifests[i].Digest.String()], + }) + } + + return results +} + +func getGqlVendors(repoVendors []string) []*string { + result := make([]*string, 0, len(repoVendors)) + + for i := range repoVendors { + result = append(result, &repoVendors[i]) + } + + return result +} + +func getGqlPlatforms(repoPlatforms []ispec.Platform) []*gql_generated.Platform { + result := make([]*gql_generated.Platform, 0, len(repoPlatforms)) + + for i := range repoPlatforms { + result = append(result, &gql_generated.Platform{ + Os: &repoPlatforms[i].OS, + Arch: &repoPlatforms[i].Architecture, + }) + } + + return result +} + +type ( + ManifestDigest = string + BlobDigest = string +) + +func ProtoDescriptor2ImageSummary(ctx context.Context, descriptor mTypes.Descriptor, repo, tag string, + repoMeta mTypes.RepoMetadata2, imageDataMap map[ManifestDigest]mTypes.ImageData2, +) (*gql_generated.ImageSummary, map[BlobDigest]int64, error) { + switch descriptor.MediaType { + case ispec.MediaTypeImageManifest: + return ProtoImageManifest2ImageSummary(ctx, repo, tag, repoMeta, imageDataMap[descriptor.Digest]) + case ispec.MediaTypeImageIndex: + return ProtoImageIndex2ImageSummary(ctx, repo, tag, descriptor.Digest, repoMeta, imageDataMap) + default: + // TODO: + return nil, nil, nil + } +} + +func FullImageData2ImageSummary(ctx context.Context, imageData mTypes.FullImageData, +) (*gql_generated.ImageSummary, map[BlobDigest]int64, error) { + switch imageData.MediaType { + case ispec.MediaTypeImageManifest: + return FullImageManifest2ImageSummary(ctx, imageData) + case ispec.MediaTypeImageIndex: + return FullImageIndex2ImageSummary(ctx, imageData) + default: + // TODO: + return nil, nil, nil + } +} + +func ProtoImageIndex2ImageSummary(ctx context.Context, repo, tag, digest string, repoMeta mTypes.RepoMetadata2, + imageDataMap map[ManifestDigest]mTypes.ImageData2, +) (*gql_generated.ImageSummary, map[BlobDigest]int64, error) { + imageIndex := imageDataMap[digest] + + var ( + indexLastUpdated time.Time + isSigned = isImageSigned(repoMeta.Signatures[digest]) + indexSize int64 + manifestAnnotations *ImageAnnotations + manifestSummaries = make([]*gql_generated.ManifestSummary, 0, len(imageIndex.Manifests)) + indexBlobs = make(map[string]int64, 0) + + indexDigestStr = digest + indexMediaType = ispec.MediaTypeImageIndex + ) + + for _, imageManifest := range imageIndex.Manifests { + imageManifestSummary, manifestBlobs, err := ProtoImageManifest2ImageSummary(ctx, repo, tag, repoMeta, mTypes.ImageData2{ + MediaType: ispec.MediaTypeImageManifest, + Digest: imageManifest.Digest, + Size: imageIndex.Size, + Manifests: []mTypes.ManifestData2{imageManifest}, + }) + if err != nil { + return &gql_generated.ImageSummary{}, map[string]int64{}, err + } + + manifestSize := int64(0) + + for digest, size := range manifestBlobs { + indexBlobs[digest] = size + manifestSize += size + } + + if indexLastUpdated.Before(*imageManifestSummary.LastUpdated) { + indexLastUpdated = *imageManifestSummary.LastUpdated + } + + annotations := GetAnnotations(imageManifest.Annotations, imageManifest.ConfigContent.Config.Labels) + + if manifestAnnotations == nil { + manifestAnnotations = &annotations + } + + indexSize += manifestSize + + manifestSummaries = append(manifestSummaries, imageManifestSummary.Manifests[0]) + } + + signaturesInfo := ProtoGetSignaturesInfo(isSigned, repoMeta, godigest.Digest(digest)) + + if manifestAnnotations == nil { + // The index doesn't have manifests + manifestAnnotations = &ImageAnnotations{} + } + + annotations := GetIndexAnnotations(imageIndex.Index.Annotations, manifestAnnotations) + + indexSummary := gql_generated.ImageSummary{ + RepoName: &repo, + Tag: &tag, + Digest: &indexDigestStr, + MediaType: &indexMediaType, + Manifests: manifestSummaries, + LastUpdated: &indexLastUpdated, + IsSigned: &isSigned, + SignatureInfo: signaturesInfo, + Size: ref(strconv.FormatInt(indexSize, 10)), + DownloadCount: ref(int(repoMeta.Statistics[indexDigestStr].DownloadCount)), + Description: &annotations.Description, + Title: &annotations.Title, + Documentation: &annotations.Documentation, + Licenses: &annotations.Licenses, + Labels: &annotations.Labels, + Source: &annotations.Source, + Vendor: &annotations.Vendor, + Authors: &annotations.Authors, + Referrers: getReferrers(repoMeta.Referrers[digest]), + } + + return &indexSummary, indexBlobs, nil +} + +func FullImageIndex2ImageSummary(ctx context.Context, imageData mTypes.FullImageData, +) (*gql_generated.ImageSummary, map[BlobDigest]int64, error) { + var ( + repo = imageData.Repo + tag = imageData.Tag + indexLastUpdated time.Time + isSigned = isImageSigned(imageData.Signatures) + indexSize = int64(0) + manifestAnnotations *ImageAnnotations + manifestSummaries = make([]*gql_generated.ManifestSummary, 0, len(imageData.Manifests)) + indexBlobs = map[string]int64{} + + indexDigestStr = imageData.Digest.String() + indexMediaType = ispec.MediaTypeImageIndex + ) + + for _, imageManifest := range imageData.Manifests { + imageManifestSummary, manifestBlobs, err := FullImageManifest2ImageSummary(ctx, mTypes.FullImageData{ + Repo: imageData.Repo, + Tag: imageData.Tag, + MediaType: ispec.MediaTypeImageManifest, + Digest: imageManifest.Digest, + Size: imageManifest.Size, + Manifests: []mTypes.FullManifestData{imageManifest}, + Referrers: imageManifest.Referrers, + Statistics: imageManifest.Statistics, + Signatures: imageManifest.Signatures, + }) + if err != nil { + return &gql_generated.ImageSummary{}, map[string]int64{}, err + } + + manifestSize := int64(0) + for digest, size := range manifestBlobs { + indexBlobs[digest] = size + manifestSize += size + } + + if indexLastUpdated.Before(*imageManifestSummary.LastUpdated) { + indexLastUpdated = *imageManifestSummary.LastUpdated + } + + annotations := GetAnnotations(imageManifest.Annotations, imageManifest.ConfigContent.Config.Labels) + if manifestAnnotations == nil { + manifestAnnotations = &annotations + } + + indexSize += manifestSize + + manifestSummaries = append(manifestSummaries, imageManifestSummary.Manifests[0]) + } + + signaturesInfo := FullGetSignaturesInfo(isSigned, imageData.Signatures, godigest.Digest(imageData.Digest)) + + if manifestAnnotations == nil { + manifestAnnotations = &ImageAnnotations{} + } + + annotations := GetIndexAnnotations(imageData.Index.Annotations, manifestAnnotations) + + indexSummary := gql_generated.ImageSummary{ + RepoName: &repo, + Tag: &tag, + Digest: &indexDigestStr, + MediaType: &indexMediaType, + Manifests: manifestSummaries, + LastUpdated: &indexLastUpdated, + IsSigned: &isSigned, + SignatureInfo: signaturesInfo, + Size: ref(strconv.FormatInt(indexSize, 10)), + DownloadCount: ref(int(imageData.Statistics.DownloadCount)), + Description: &annotations.Description, + Title: &annotations.Title, + Documentation: &annotations.Documentation, + Licenses: &annotations.Licenses, + Labels: &annotations.Labels, + Source: &annotations.Source, + Vendor: &annotations.Vendor, + Authors: &annotations.Authors, + Referrers: getReferrers(imageData.Referrers), + } + + return &indexSummary, indexBlobs, nil +} + +func ProtoImageManifest2ImageSummary(ctx context.Context, repo, tag string, repoMeta mTypes.RepoMetadata2, + imageData mTypes.ImageData2, +) (*gql_generated.ImageSummary, map[BlobDigest]int64, error) { + manifest := imageData.Manifests[0] + + var ( + repoName = repo + configDigest = manifest.Config.Digest.String() + configSize = manifest.Config.Size + manifestDigest = manifest.Digest.String() + manifestSize = int64(manifest.Size) + mediaType = manifest.MediaType + artifactType = zcommon.GetManifestArtifactType(imageData.Manifests[0].Manifest) + platform = getPlatform(manifest.ConfigContent.Platform) + imageLastUpdated = zcommon.GetImageLastUpdated(manifest.ConfigContent) // TODO: we can cache this + downloadCount = int(repoMeta.Statistics[manifest.Digest.String()].DownloadCount) + isSigned = isImageSigned(repoMeta.Signatures[manifest.Digest.String()]) + ) + + imageSize, imageBlobsMap := getImageBlobsInfo(manifestDigest, manifestSize, configDigest, configSize, manifest.Layers) + imageSizeStr := strconv.FormatInt(imageSize, 10) + annotations := GetAnnotations(manifest.Annotations, manifest.ConfigContent.Config.Labels) // TODO: This can be cached + + authors := annotations.Authors + if authors == "" { + authors = manifest.ConfigContent.Author + } + + historyEntries, err := getAllHistory(manifest.Manifest, manifest.ConfigContent) // TODO: this can be cached + if err != nil { + graphql.AddError(ctx, gqlerror.Errorf("error generating history on tag %s in repo %s: "+ + "manifest digest: %s, error: %s", tag, repo, manifest.Digest, err.Error())) + } + + signaturesInfo := ProtoGetSignaturesInfo(isSigned, repoMeta, manifest.Digest) + + manifestSummary := gql_generated.ManifestSummary{ + Digest: &manifestDigest, + ConfigDigest: &configDigest, + LastUpdated: &imageLastUpdated, + Size: &imageSizeStr, + IsSigned: &isSigned, + SignatureInfo: signaturesInfo, + Platform: &platform, + DownloadCount: &downloadCount, + Layers: getLayersSummaries(manifest.Manifest), + History: historyEntries, + Referrers: getReferrers(repoMeta.Referrers[manifestDigest]), + ArtifactType: &artifactType, + } + + imageSummary := gql_generated.ImageSummary{ + RepoName: &repoName, + Tag: &tag, + Digest: &manifestDigest, + MediaType: &mediaType, + Manifests: []*gql_generated.ManifestSummary{&manifestSummary}, + LastUpdated: &imageLastUpdated, + IsSigned: &isSigned, + SignatureInfo: signaturesInfo, + Size: &imageSizeStr, + DownloadCount: &downloadCount, + Description: &annotations.Description, + Title: &annotations.Title, + Documentation: &annotations.Documentation, + Licenses: &annotations.Licenses, + Labels: &annotations.Labels, + Source: &annotations.Source, + Vendor: &annotations.Vendor, + Authors: &authors, + Referrers: manifestSummary.Referrers, + } + + return &imageSummary, imageBlobsMap, nil +} + +func FullImageManifest2ImageSummary(ctx context.Context, imageData mTypes.FullImageData, +) (*gql_generated.ImageSummary, map[BlobDigest]int64, error) { + manifest := imageData.Manifests[0] + + var ( + repoName = imageData.Repo + tag = imageData.Tag + configDigest = manifest.Config.Digest.String() + configSize = manifest.Config.Size + manifestDigest = manifest.Digest.String() + manifestSize = int64(manifest.Size) + mediaType = manifest.MediaType + artifactType = zcommon.GetManifestArtifactType(imageData.Manifests[0].Manifest) + platform = getPlatform(manifest.ConfigContent.Platform) + imageLastUpdated = zcommon.GetImageLastUpdated(manifest.ConfigContent) // TODO: we can cache this + downloadCount = imageData.Statistics.DownloadCount + isSigned = isImageSigned(imageData.Signatures) + ) + + imageSize, imageBlobsMap := getImageBlobsInfo(manifestDigest, manifestSize, configDigest, configSize, manifest.Layers) + imageSizeStr := strconv.FormatInt(imageSize, 10) + annotations := GetAnnotations(manifest.Annotations, manifest.ConfigContent.Config.Labels) // TODO: This can be cached + + authors := annotations.Authors + if authors == "" { + authors = manifest.ConfigContent.Author + } + + historyEntries, err := getAllHistory(manifest.Manifest, manifest.ConfigContent) // TODO: this can be cached + if err != nil { + graphql.AddError(ctx, gqlerror.Errorf("error generating history on tag %s in repo %s: "+ + "manifest digest: %s, error: %s", tag, repoName, manifest.Digest, err.Error())) + } + + signaturesInfo := FullGetSignaturesInfo(isSigned, imageData.Signatures, manifest.Digest) + + manifestSummary := gql_generated.ManifestSummary{ + Digest: &manifestDigest, + ConfigDigest: &configDigest, + LastUpdated: &imageLastUpdated, + Size: &imageSizeStr, + IsSigned: &isSigned, + SignatureInfo: signaturesInfo, + Platform: &platform, + DownloadCount: &downloadCount, + Layers: getLayersSummaries(manifest.Manifest), + History: historyEntries, + Referrers: getReferrers(imageData.Referrers), + ArtifactType: &artifactType, + } + + imageSummary := gql_generated.ImageSummary{ + RepoName: &repoName, + Tag: &tag, + Digest: &manifestDigest, + MediaType: &mediaType, + Manifests: []*gql_generated.ManifestSummary{&manifestSummary}, + LastUpdated: &imageLastUpdated, + IsSigned: &isSigned, + SignatureInfo: signaturesInfo, + Size: &imageSizeStr, + DownloadCount: &downloadCount, + Description: &annotations.Description, + Title: &annotations.Title, + Documentation: &annotations.Documentation, + Licenses: &annotations.Licenses, + Labels: &annotations.Labels, + Source: &annotations.Source, + Vendor: &annotations.Vendor, + Authors: &authors, + Referrers: manifestSummary.Referrers, + } + + return &imageSummary, imageBlobsMap, nil +} + +func getProtoReferrers(referrersInfo *proto_go.ReferrersInfo) []*gql_generated.Referrer { + referrers := make([]*gql_generated.Referrer, 0, len(referrersInfo.List)) + + for _, referrerInfo := range referrersInfo.List { + referrerInfo := referrerInfo + + referrers = append(referrers, &gql_generated.Referrer{ + MediaType: &referrerInfo.MediaType, + ArtifactType: &referrerInfo.ArtifactType, + Size: ref(int(referrerInfo.Size)), + Digest: &referrerInfo.Digest, + Annotations: getAnnotationsFromMap(referrerInfo.Annotations), + }) + } + + return referrers +} + +func getAllProtoHistory(manifest *proto_go.ManifestData) ([]*gql_generated.LayerHistory, error) { + allHistory := []*gql_generated.LayerHistory{} + layerSummaries := getProtoLayersSummaries(manifest) + + history := manifest.Config.History + if len(history) == 0 { + // We don't have any image history metadata + // let's make due with just the layer metadata + for _, layer := range layerSummaries { + allHistory = append(allHistory, &gql_generated.LayerHistory{ + Layer: layer, + HistoryDescription: &gql_generated.HistoryDescription{}, + }) + } + + return allHistory, nil + } + + // Iterator over manifest layers + var layersIterator int + // Since we are appending pointers, it is important to iterate with an index over slice + for i := range history { + allHistory = append(allHistory, &gql_generated.LayerHistory{ + HistoryDescription: &gql_generated.HistoryDescription{ + Created: ref(history[i].GetCreated().AsTime()), + CreatedBy: history[i].Createdby, + Author: history[i].Author, + Comment: history[i].Comment, + EmptyLayer: history[i].Emptylayer, + }, + }) + + if history[i].Emptylayer != nil && *history[i].Emptylayer { + continue + } + + if layersIterator+1 > len(manifest.Layers) { + return allHistory, zerr.ErrBadLayerCount + } + + allHistory[i].Layer = layerSummaries[layersIterator] + + layersIterator++ + } + + return allHistory, nil +} + +func getProtoLayersSummaries(manifest *proto_go.ManifestData) []*gql_generated.LayerSummary { + layers := make([]*gql_generated.LayerSummary, 0, len(manifest.Layers)) + + for _, layer := range manifest.Layers { + size := strconv.FormatInt(layer.Size, 10) + digest := layer.Digest + + layers = append(layers, &gql_generated.LayerSummary{ + Size: &size, + Digest: &digest, + }) + } + + return layers +} + +func getProtoImageBlobsInfo(manifest *proto_go.ManifestData) (string, map[string]int64) { + imageBlobsMap := map[string]int64{} + imageSize := int64(0) + + // add config size + imageSize += manifest.Config.Size + imageBlobsMap[manifest.Config.Digest] = manifest.Config.Size + + // add manifest size + imageSize += manifest.Size + imageBlobsMap[manifest.Digest] = manifest.Size + + // add layers size + for _, layer := range manifest.Layers { + imageBlobsMap[layer.Digest] = layer.Size + imageSize += layer.Size + } + + return strconv.FormatInt(imageSize, 10), imageBlobsMap +} + +func isImageSigned(manifestSignatures mTypes.ManifestSignatures) bool { + for _, signatures := range manifestSignatures { + if len(signatures) > 0 { + return true + } + } + + return false +} + +func getPlatform(platform ispec.Platform) gql_generated.Platform { + return gql_generated.Platform{ + Os: ref(platform.OS), + Arch: ref(getArch(platform.Architecture, platform.Variant)), + } +} + +func getArch(arch string, variant string) string { + if variant != "" { + arch = arch + "/" + variant + } + + return arch +} + +func ref[T any](val T) *T { + ref := val + + return &ref +} + +func GetProtoSignaturesInfo(isSigned bool, repoMeta *proto_go.ProtoRepoMeta, digest string, +) []*gql_generated.SignatureSummary { + signaturesInfo := []*gql_generated.SignatureSummary{} + + if !isSigned { + return signaturesInfo + } + + for sigType, signatures := range repoMeta.Signatures[digest].Map { + for _, sig := range signatures.List { + for _, layer := range sig.LayersInfo { + var ( + isTrusted bool + author string + tool string + ) + + if layer.Signer != "" { + author = layer.Signer + + if !layer.Date.AsTime().IsZero() && time.Now().After(layer.Date.AsTime()) { + isTrusted = false + } else { + isTrusted = true + } + } else { + isTrusted = false + author = "" + } + + tool = sigType + + signaturesInfo = append(signaturesInfo, + &gql_generated.SignatureSummary{Tool: &tool, IsTrusted: &isTrusted, Author: &author}) + } + } + } + + return signaturesInfo +} + +func PaginatedProtoRepoMeta2ImageSummaries(ctx context.Context, reposMeta []mTypes.RepoMetadata2, + imageData map[string]mTypes.ImageData2, skip SkipQGLField, cveInfo cveinfo.CveInfo, filter mTypes.Filter, + pageInput pagination.PageInput, +) ([]*gql_generated.ImageSummary, zcommon.PageInfo, error) { + imagePageFinder, err := pagination.NewImgSumPageFinder(pageInput.Limit, pageInput.Offset, pageInput.SortBy) + if err != nil { + return []*gql_generated.ImageSummary{}, zcommon.PageInfo{}, err + } + + for _, repoMeta := range reposMeta { + for tag := range repoMeta.Tags { + descriptor := repoMeta.Tags[tag] + + imageSummary, _, err := ProtoDescriptor2ImageSummary(ctx, descriptor, repoMeta.Name, tag, + repoMeta, imageData) + if err != nil { + continue + } + + if ImgSumAcceptedByFilter(imageSummary, filter) { + imagePageFinder.Add(imageSummary) + } + } + } + + page, pageInfo := imagePageFinder.Page() + + for _, imageSummary := range page { + // CVE scanning is expensive, only scan for this page + updateImageSummaryVulnerabilities(ctx, imageSummary, skip, cveInfo) + } + + return page, pageInfo, nil +} + +func PaginatedFullImageData2ImageSummaries(ctx context.Context, imageDataList []mTypes.FullImageData, skip SkipQGLField, + cveInfo cveinfo.CveInfo, filter mTypes.Filter, pageInput pagination.PageInput, +) ([]*gql_generated.ImageSummary, zcommon.PageInfo, error) { + imagePageFinder, err := pagination.NewImgSumPageFinder(pageInput.Limit, pageInput.Offset, pageInput.SortBy) + if err != nil { + return []*gql_generated.ImageSummary{}, zcommon.PageInfo{}, err + } + + for _, imageData := range imageDataList { + imageSummary, _, err := FullImageData2ImageSummary(ctx, imageData) + if err != nil { + continue + } + + if ImgSumAcceptedByFilter(imageSummary, filter) { + imagePageFinder.Add(imageSummary) + } + } + + page, pageInfo := imagePageFinder.Page() + + for _, imageSummary := range page { + // CVE scanning is expensive, only scan for this page + updateImageSummaryVulnerabilities(ctx, imageSummary, skip, cveInfo) + } + + return page, pageInfo, nil +} diff --git a/pkg/extensions/search/resolver.go b/pkg/extensions/search/resolver.go index 5bbd0daab5..a322f7ff1c 100644 --- a/pkg/extensions/search/resolver.go +++ b/pkg/extensions/search/resolver.go @@ -12,7 +12,6 @@ import ( "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" @@ -112,6 +111,39 @@ func FilterByDigest(digest string) mTypes.FilterFunc { } } +func ProtoFilterByDigest(digest string) mTypes.FilterProtoFunc { + return func(repoMeta mTypes.RepoMetadata2, imageData mTypes.ImageData2) bool { + lookupDigest := digest + contains := false + + manifest := imageData.Manifests[0] + + 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 + if strings.Contains(manifestDigest, lookupDigest) { + contains = true + } + + // 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) { + 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 { + if strings.Contains(layer.Digest.String(), lookupDigest) { + contains = true + } + } + + return contains + } +} + func getImageListForDigest(ctx context.Context, digest string, metaDB mTypes.MetaDB, cveInfo cveinfo.CveInfo, requestedPage *gql_generated.PageInput, ) (*gql_generated.PaginatedImagesResult, error) { @@ -131,14 +163,13 @@ func getImageListForDigest(ctx context.Context, digest string, metaDB mTypes.Met ), } - // get all repos - reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, FilterByDigest(digest)) + imageDataList, err := metaDB.ProtoFilterTags(ctx, mTypes.AcceptAllRepoTag, ProtoFilterByDigest(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.PaginatedFullImageData2ImageSummaries(ctx, imageDataList, skip, + cveInfo, mTypes.Filter{}, pageInput) if err != nil { return &gql_generated.PaginatedImagesResult{}, err } @@ -277,6 +308,42 @@ func getImageSummary(ctx context.Context, repo, tag string, digest *string, skip return imageSummaries[0], nil } +func getProtoImageSummary(ctx context.Context, repo, tag string, digest *string, skipCVE convert.SkipQGLField, + metaDB mTypes.MetaDB, cveInfo cveinfo.CveInfo, log log.Logger, //nolint:unparam +) ( + *gql_generated.ImageSummary, error, +) { + repoMeta, err := metaDB.ProtoGetRepoMeta(repo) + if err != nil { + return nil, err + } + + manifestDescriptor, ok := repoMeta.Tags[tag] + if !ok { + return nil, gqlerror.Errorf("can't find image: %s:%s", repo, tag) + } + + repoMeta.Tags = map[string]mTypes.Descriptor{tag: manifestDescriptor} + + imageDigest := manifestDescriptor.Digest + if digest != nil { + imageDigest = *digest + } + + imageDataMap, err := metaDB.ProtoFilterImageData(ctx, []string{imageDigest}) + if err != nil { + return &gql_generated.ImageSummary{}, err + } + + imageSummaries := convert.ProtoRepoMeta2ImageSummaries(ctx, repoMeta, imageDataMap, skipCVE, cveInfo) + + if len(imageSummaries) == 0 { + return &gql_generated.ImageSummary{}, nil + } + + return imageSummaries[0], nil +} + func getCVEListForImage( ctx context.Context, //nolint:unparam // may be used in the future to filter by permissions image string, @@ -374,6 +441,29 @@ func FilterByTagInfo(tagsInfo []cvemodel.TagInfo) mTypes.FilterFunc { } } +func ProtoFilterByTagInfo(tagsInfo []cvemodel.TagInfo) mTypes.FilterProtoFunc { + return func(repoMeta mTypes.RepoMetadata2, imageData mTypes.ImageData2) bool { + manifestDigest := imageData.Manifests[0].Digest.String() + + for _, tagInfo := range tagsInfo { + switch tagInfo.Descriptor.MediaType { + case ispec.MediaTypeImageManifest: + if tagInfo.Descriptor.Digest.String() == manifestDigest { + return true + } + case ispec.MediaTypeImageIndex: + for _, manifestDesc := range tagInfo.Manifests { + if manifestDesc.Digest.String() == manifestDigest { + return true + } + } + } + } + + return false + } +} + func FilterByRepoAndTagInfo(repo string, tagsInfo []cvemodel.TagInfo) mTypes.FilterFunc { return func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { if repoMeta.Name != repo { @@ -401,6 +491,33 @@ func FilterByRepoAndTagInfo(repo string, tagsInfo []cvemodel.TagInfo) mTypes.Fil } } +func ProtoFilterByRepoAndTagInfo(repo string, tagsInfo []cvemodel.TagInfo) mTypes.FilterProtoFunc { + return func(repoMeta mTypes.RepoMetadata2, imageData mTypes.ImageData2) bool { + if repoMeta.Name != repo { + return false + } + + manifestDigest := imageData.Manifests[0].Digest.String() + + for _, tagInfo := range tagsInfo { + switch tagInfo.Descriptor.MediaType { + case ispec.MediaTypeImageManifest: + if tagInfo.Descriptor.Digest.String() == manifestDigest { + return true + } + case ispec.MediaTypeImageIndex: + for _, manifestDesc := range tagInfo.Manifests { + if manifestDesc.Digest.String() == manifestDigest { + return true + } + } + } + } + + return false + } +} + func getImageListForCVE( ctx context.Context, cveID string, @@ -414,11 +531,16 @@ 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.ProtoGetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMetadata2) bool { return true }) if err != nil { return &gql_generated.PaginatedImagesResult{}, err } + // reposMeta, err := metaDB.GetMultipleRepoMeta(ctx, func(repoMeta mTypes.RepoMetadata) bool { return true }) + // if err != nil { + // return &gql_generated.PaginatedImagesResult{}, err + // } + affectedImages := []cvemodel.TagInfo{} for _, repoMeta := range reposMeta { @@ -465,13 +587,13 @@ func getImageListForCVE( } // get all repos - reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, FilterByTagInfo(affectedImages)) + imageDataList, err := metaDB.ProtoFilterTags(ctx, mTypes.AcceptAllRepoTag, ProtoFilterByTagInfo(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.PaginatedFullImageData2ImageSummaries(ctx, imageDataList, + skip, cveInfo, localFilter, pageInput) if err != nil { return &gql_generated.PaginatedImagesResult{}, err } @@ -538,13 +660,13 @@ func getImageListWithCVEFixed( } // get all repos - reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, FilterByRepoAndTagInfo(repo, tagsInfo)) + imageDataList, err := metaDB.ProtoFilterTags(ctx, mTypes.AcceptAllRepoTag, ProtoFilterByRepoAndTagInfo(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.PaginatedFullImageData2ImageSummaries(ctx, imageDataList, + skip, cveInfo, localFilter, pageInput) if err != nil { return &gql_generated.PaginatedImagesResult{}, err } @@ -583,13 +705,18 @@ func repoListWithNewestImage( ), } - reposMeta, manifestMetaMap, indexDataMap, err := metaDB.SearchRepos(ctx, "") + reposMeta, err := metaDB.ProtoSearchRepos(ctx, "") if err != nil { return &gql_generated.PaginatedReposResult{}, err } - repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap, - skip, cveInfo, mTypes.Filter{}, pageInput) + imageDataMap, err := metaDB.ProtoFilterImageData(ctx, []string{}) + if err != nil { + return &gql_generated.PaginatedReposResult{}, err + } + + repos, pageInfo, err := convert.PaginatedFullRepoMeta2RepoSummaries(ctx, reposMeta, imageDataMap, + mTypes.Filter{}, pageInput, cveInfo, skip) if err != nil { return &gql_generated.PaginatedReposResult{}, err } @@ -611,16 +738,24 @@ 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) + // filterFn := func(repoMeta mTypes.RepoMetadata) bool { + // return zcommon.Contains(repoNames, repoMeta.Name) + // } + + filterByName := func(repo string) int { + if zcommon.Contains(bookmarkedRepos, repo) { + return 1 + } + + return -1 } - return getFilteredPaginatedRepos(ctx, cveInfo, filterFn, log, requestedPage, metaDB) + return protoGetFilteredPaginatedRepos(ctx, cveInfo, filterByName, log, requestedPage, metaDB) } func getStarredRepos( @@ -630,16 +765,20 @@ 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) + protoFilterFn := func(repo string) int { + if zcommon.Contains(starredRepos, repo) { + return 1 + } + + return -1 } - return getFilteredPaginatedRepos(ctx, cveInfo, filterFn, log, requestedPage, metaDB) + return protoGetFilteredPaginatedRepos(ctx, cveInfo, protoFilterFn, log, requestedPage, metaDB) } func getFilteredPaginatedRepos( @@ -686,6 +825,55 @@ func getFilteredPaginatedRepos( }, nil } +func protoGetFilteredPaginatedRepos( + ctx context.Context, + cveInfo cveinfo.CveInfo, + filterFn mTypes.FilterRepoNameFunc, + log log.Logger, //nolint:unparam // may be used by devs for debugging + requestedPage *gql_generated.PageInput, + metaDB mTypes.MetaDB, +) (*gql_generated.PaginatedReposResult, error) { + if requestedPage == nil { + requestedPage = &gql_generated.PageInput{} + } + + skip := convert.SkipQGLField{ + Vulnerabilities: canSkipField(convert.GetPreloads(ctx), "Results.NewestImage.Vulnerabilities"), + } + + pageInput := pagination.PageInput{ + Limit: safeDereferencing(requestedPage.Limit, 0), + Offset: safeDereferencing(requestedPage.Offset, 0), + SortBy: pagination.SortCriteria( + safeDereferencing(requestedPage.SortBy, gql_generated.SortCriteriaUpdateTime), + ), + } + + repoMetaList, err := metaDB.ProtoFilterRepos(ctx, filterFn, mTypes.AcceptAllRepoMeta) + if err != nil { + return &gql_generated.PaginatedReposResult{}, err + } + + latestImageData, err := metaDB.ProtoFilterImageData(ctx, []string{}) + if err != nil { + return &gql_generated.PaginatedReposResult{}, err + } + + repos, pageInfo, err := convert.PaginatedFullRepoMeta2RepoSummaries(ctx, repoMetaList, latestImageData, + mTypes.Filter{}, pageInput, cveInfo, skip) + if err != nil { + return &gql_generated.PaginatedReposResult{}, err + } + + return &gql_generated.PaginatedReposResult{ + Results: repos, + Page: &gql_generated.PageInfo{ + TotalCount: pageInfo.TotalCount, + ItemCount: pageInfo.ItemCount, + }, + }, nil +} + func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filter *gql_generated.Filter, requestedPage *gql_generated.PageInput, cveInfo cveinfo.CveInfo, log log.Logger, //nolint:unparam ) (*gql_generated.PaginatedReposResult, []*gql_generated.ImageSummary, []*gql_generated.LayerSummary, error, @@ -723,13 +911,18 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte ), } - reposMeta, manifestMetaMap, indexDataMap, err := metaDB.SearchRepos(ctx, query) + repoMetaList, err := metaDB.ProtoSearchRepos(ctx, query) if err != nil { return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err } - repos, pageInfo, err := convert.PaginatedRepoMeta2RepoSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap, - skip, cveInfo, localFilter, pageInput) + imageDataMap, err := metaDB.ProtoFilterImageData(ctx, getLatestImageDigest(repoMetaList)) + if err != nil { + return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err + } + + repos, pageInfo, err := convert.PaginatedFullRepoMeta2RepoSummaries(ctx, repoMetaList, imageDataMap, localFilter, pageInput, cveInfo, + skip) if err != nil { return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err } @@ -753,13 +946,13 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte ), } - reposMeta, manifestMetaMap, indexDataMap, err := metaDB.SearchTags(ctx, query) + imageDataList, err := metaDB.ProtoSearchTags(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.PaginatedFullImageData2ImageSummaries(ctx, imageDataList, skip, cveInfo, + localFilter, pageInput) if err != nil { return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err } @@ -775,6 +968,16 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte return &paginatedRepos, images, layers, nil } +func getLatestImageDigest(repoMetaList []mTypes.FullRepoMetadata) []string { + digests := make([]string, 0, len(repoMetaList)) + + for i := range repoMetaList { + digests = append(digests, repoMetaList[i].LastUpdatedImage.Digest) + } + + return digests +} + func canSkipField(preloads map[string]bool, s string) bool { fieldIsPresent := preloads[s] @@ -810,7 +1013,7 @@ func derivedImageList(ctx context.Context, image string, digest *string, metaDB Vulnerabilities: true, } - searchedImage, err := getImageSummary(ctx, imageRepo, imageTag, digest, skipReferenceImage, metaDB, cveInfo, log) + searchedImage, err := getProtoImageSummary(ctx, imageRepo, imageTag, digest, skipReferenceImage, metaDB, cveInfo, log) if err != nil { if errors.Is(err, zerr.ErrRepoMetaNotFound) { return &gql_generated.PaginatedImagesResult{}, gqlerror.Errorf("repository: not found") @@ -820,13 +1023,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)) + imageDataList, err := metaDB.ProtoFilterTags(ctx, mTypes.AcceptAllRepoTag, protoFilterDerivedImages(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.PaginatedFullImageData2ImageSummaries(ctx, imageDataList, skip, cveInfo, + mTypes.Filter{}, pageInput) if err != nil { return &gql_generated.PaginatedImagesResult{}, err } @@ -886,6 +1089,47 @@ func filterDerivedImages(image *gql_generated.ImageSummary) mTypes.FilterFunc { } } +func protoFilterDerivedImages(image *gql_generated.ImageSummary) mTypes.FilterProtoFunc { + return func(repoMeta mTypes.RepoMetadata2, imageData mTypes.ImageData2) bool { + var addImageToList bool + + imageManifest := imageData.Manifests[0] + + for i := range image.Manifests { + manifestDigest := imageManifest.Digest.String() + if manifestDigest == *image.Manifests[i].Digest { + return false + } + imageLayers := image.Manifests[i].Layers + + addImageToList = false + layers := imageManifest.Layers + + sameLayer := 0 + + for _, l := range imageLayers { + for _, k := range layers { + if k.Digest.String() == *l.Digest { + sameLayer++ + } + } + } + + // if all layers are the same + if sameLayer == len(imageLayers) { + // it's a derived image + addImageToList = true + } + + if addImageToList { + return true + } + } + + return false + } +} + func baseImageList(ctx context.Context, image string, digest *string, metaDB mTypes.MetaDB, requestedPage *gql_generated.PageInput, cveInfo cveinfo.CveInfo, log log.Logger, @@ -916,7 +1160,7 @@ func baseImageList(ctx context.Context, image string, digest *string, metaDB mTy Vulnerabilities: true, } - searchedImage, err := getImageSummary(ctx, imageRepo, imageTag, digest, skipReferenceImage, metaDB, cveInfo, log) + searchedImage, err := getProtoImageSummary(ctx, imageRepo, imageTag, digest, skipReferenceImage, metaDB, cveInfo, log) if err != nil { if errors.Is(err, zerr.ErrRepoMetaNotFound) { return &gql_generated.PaginatedImagesResult{}, gqlerror.Errorf("repository: not found") @@ -926,12 +1170,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)) + imageDataList, err := metaDB.ProtoFilterTags(ctx, mTypes.AcceptAllRepoTag, protoFilterBaseImages(searchedImage)) if err != nil { return &gql_generated.PaginatedImagesResult{}, err } - baseList, pageInfo, err := convert.PaginatedRepoMeta2ImageSummaries(ctx, reposMeta, manifestMetaMap, indexDataMap, + baseList, pageInfo, err := convert.PaginatedFullImageData2ImageSummaries(ctx, imageDataList, skip, cveInfo, mTypes.Filter{}, pageInput) if err != nil { return &gql_generated.PaginatedImagesResult{}, err @@ -992,6 +1236,47 @@ func filterBaseImages(image *gql_generated.ImageSummary) mTypes.FilterFunc { } } +func protoFilterBaseImages(image *gql_generated.ImageSummary) mTypes.FilterProtoFunc { + return func(repoMeta mTypes.RepoMetadata2, imageData mTypes.ImageData2) bool { + var addImageToList bool + + manifest := imageData.Manifests[0] + + for i := range image.Manifests { + manifestDigest := manifest.Digest.String() + if manifestDigest == *image.Manifests[i].Digest { + return false + } + + addImageToList = true + + for _, l := range manifest.Layers { + foundLayer := false + + for _, k := range image.Manifests[i].Layers { + if l.Digest.String() == *k.Digest { + foundLayer = true + + break + } + } + + if !foundLayer { + addImageToList = false + + break + } + } + + if addImageToList { + return true + } + } + + return false + } +} + func validateGlobalSearchInput(query string, filter *gql_generated.Filter, requestedPage *gql_generated.PageInput, ) error { @@ -1119,92 +1404,27 @@ 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.ProtoGetFullRepoMeta(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{} - ) - - 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 - } + tagsDigests := []string{} + for i := range repoMeta.Tags { + if i == "" { + continue + } - manifestMetaMap[descriptor.Digest.String()] = mTypes.ManifestMetadata{ - ManifestBlob: manifestData.ManifestBlob, - ConfigBlob: manifestData.ConfigBlob, - } - } + tagsDigests = append(tagsDigests, repoMeta.Tags[i].Digest) + } - if errorOccured { - continue - } + imageDataMap, err := metaDB.ProtoFilterImageData(ctx, tagsDigests) + if err != nil { + log.Error().Err(err).Str("repository", repo).Msg("resolver: can't retrieve imageData for repo") - indexDataMap[digest] = indexData - default: - } + return &gql_generated.RepoInfo{}, err } skip := convert.SkipQGLField{ @@ -1212,7 +1432,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.FullRepoMeta2ExpandedRepoInfo(ctx, repoMeta, imageDataMap, skip, cveInfo, log) dateSortedImages := make(timeSlice, 0, len(imageSummaries)) @@ -1270,16 +1490,15 @@ func getImageList(ctx context.Context, repo string, metaDB mTypes.MetaDB, cveInf ), } - reposMeta, manifestMetaMap, indexDataMap, err := metaDB.FilterTags(ctx, - func(repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata) bool { - return repoMeta.Name == repo || repo == "" - }) + matchRepoName := func(repoName, tag string) bool { return repoName == repo } + + imageData, err := metaDB.ProtoFilterTags(ctx, matchRepoName, mTypes.AcceptAllImageData) 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.PaginatedFullImageData2ImageSummaries(ctx, imageData, skip, + cveInfo, mTypes.Filter{}, pageInput) if err != nil { return &gql_generated.PaginatedImagesResult{}, err } @@ -1304,7 +1523,7 @@ func getReferrers(metaDB mTypes.MetaDB, repo string, referredDigest string, arti referredDigest, err) } - referrers, err := metaDB.GetReferrersInfo(repo, refDigest, artifactTypes) + referrers, err := metaDB.ProtoGetReferrersInfo(repo, refDigest, artifactTypes) if err != nil { return nil, err } diff --git a/pkg/extensions/search/resolver_test.go b/pkg/extensions/search/resolver_test.go index eedcce38b3..d5efa57509 100644 --- a/pkg/extensions/search/resolver_test.go +++ b/pkg/extensions/search/resolver_test.go @@ -32,7 +32,7 @@ import ( var ErrTestError = errors.New("TestError") -func TestGlobalSearch(t *testing.T) { +func TestResolverGlobalSearch(t *testing.T) { Convey("globalSearch", t, func() { const query = "repo1" Convey("MetaDB SearchRepos error", func() { diff --git a/pkg/extensions/search/schema.resolvers.go b/pkg/extensions/search/schema.resolvers.go index 6d614b6890..4caa350f5d 100644 --- a/pkg/extensions/search/schema.resolvers.go +++ b/pkg/extensions/search/schema.resolvers.go @@ -138,7 +138,7 @@ func (r *queryResolver) Image(ctx context.Context, image string) (*gql_generated Vulnerabilities: canSkipField(convert.GetPreloads(ctx), "Vulnerabilities"), } - return getImageSummary(ctx, repo, tag, nil, skip, r.metaDB, r.cveInfo, r.log) + return getProtoImageSummary(ctx, repo, tag, nil, skip, r.metaDB, r.cveInfo, r.log) } // Referrers is the resolver for the Referrers field. diff --git a/pkg/extensions/search/search_test.go b/pkg/extensions/search/search_test.go index f704e48cca..8d09b93b32 100644 --- a/pkg/extensions/search/search_test.go +++ b/pkg/extensions/search/search_test.go @@ -3203,7 +3203,9 @@ func TestGlobalSearch(t *testing.T) { Vendors NewestImage { RepoName Tag LastUpdated Size + Digest Manifests{ + Digest ConfigDigest LastUpdated Size Platform { Os Arch } History { diff --git a/pkg/meta/boltdb/boltdb.go b/pkg/meta/boltdb/boltdb.go index ca14e456da..c633e05990 100644 --- a/pkg/meta/boltdb/boltdb.go +++ b/pkg/meta/boltdb/boltdb.go @@ -66,6 +66,22 @@ func New(boltDB *bbolt.DB, log log.Logger) (*BoltDB, error) { return err } + // TODO: PROTO STUFF + _, err = transaction.CreateBucketIfNotExists([]byte(ProtoImageDataBuck)) + if err != nil { + return err + } + + _, err = transaction.CreateBucketIfNotExists([]byte(ProtoRepoMetaBuck)) + if err != nil { + return err + } + + _, err = transaction.CreateBucketIfNotExists([]byte(ProtoRepoBlobsBuck)) + if err != nil { + return err + } + return nil }) if err != nil { @@ -798,6 +814,7 @@ func (bdw *BoltDB) IncrementImageDownloads(repo string, reference string) error func (bdw *BoltDB) UpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error { err := bdw.DB.Update(func(transaction *bbolt.Tx) error { + // TODO: Update RepoMetaProto as well imgTrustStore := bdw.ImageTrustStore() if imgTrustStore == nil { @@ -901,6 +918,7 @@ func (bdw *BoltDB) UpdateSignaturesValidity(repo string, manifestDigest godigest func (bdw *BoltDB) AddManifestSignature(repo string, signedManifestDigest godigest.Digest, sygMeta mTypes.SignatureMetadata, ) error { + // TODO: add support for RepoMetaProto err := bdw.DB.Update(func(tx *bbolt.Tx) error { buck := tx.Bucket([]byte(RepoMetadataBucket)) diff --git a/pkg/meta/boltdb/boltdb_test.go b/pkg/meta/boltdb/boltdb_test.go index 4729e5a892..a7021388be 100644 --- a/pkg/meta/boltdb/boltdb_test.go +++ b/pkg/meta/boltdb/boltdb_test.go @@ -32,6 +32,13 @@ func (its imgTrustStore) VerifySignature( return "", time.Time{}, false, nil } +func (its imgTrustStore) ProtoVerifySignature( + signatureType string, rawSignature []byte, sigKey string, manifestDigest digest.Digest, imageData mTypes.ImageData2, + repo string, +) (string, time.Time, bool, error) { + return "", time.Time{}, false, nil +} + func TestWrapperErrors(t *testing.T) { Convey("Errors", t, func() { tmpDir := t.TempDir() diff --git a/pkg/meta/boltdb/buckets.go b/pkg/meta/boltdb/buckets.go index 8464990233..aa9475072c 100644 --- a/pkg/meta/boltdb/buckets.go +++ b/pkg/meta/boltdb/buckets.go @@ -9,3 +9,9 @@ const ( VersionBucket = "Version" UserAPIKeysBucket = "UserAPIKeys" ) + +const ( + ProtoImageDataBuck = "ProtoImageData" + ProtoRepoMetaBuck = "ProtoRepoMeta" + ProtoRepoBlobsBuck = "ProtoRepoBlobsMeta" +) diff --git a/pkg/meta/boltdb/proto_boltdb.go b/pkg/meta/boltdb/proto_boltdb.go new file mode 100644 index 0000000000..fcfc3bc7fc --- /dev/null +++ b/pkg/meta/boltdb/proto_boltdb.go @@ -0,0 +1,1109 @@ +package boltdb + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + godigest "github.com/opencontainers/go-digest" + ispec "github.com/opencontainers/image-spec/specs-go/v1" + "go.etcd.io/bbolt" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" + + zerr "zotregistry.io/zot/errors" + zcommon "zotregistry.io/zot/pkg/common" + "zotregistry.io/zot/pkg/meta/common" + mConvert "zotregistry.io/zot/pkg/meta/convert" + "zotregistry.io/zot/pkg/meta/proto_go" + mTypes "zotregistry.io/zot/pkg/meta/types" + reqCtx "zotregistry.io/zot/pkg/requestcontext" +) + +func (bdw *BoltDB) ProtoSetImageData(digest godigest.Digest, imageData mTypes.ImageData2) error { + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoImageDataBuck)) + + protoImageData := &proto_go.ImageData{} + + switch imageData.MediaType { + case ispec.MediaTypeImageManifest: + manifest := imageData.Manifests[0] + + protoImageData = mConvert.GetProtoImageManifestData(manifest.Manifest, manifest.ConfigContent, + manifest.Size, manifest.Digest.String()) + case ispec.MediaTypeImageIndex: + protoImageData = mConvert.GetProtoImageIndexData(*imageData.Index, imageData.Size, imageData.Digest.String()) + } + + pImageDataBlob, err := proto.Marshal(protoImageData) + if err != nil { + return fmt.Errorf("metadb: error while calculating blob for manifest with digest %s %w", digest, err) + } + + err = buck.Put([]byte(digest), pImageDataBlob) + if err != nil { + return fmt.Errorf("metadb: error while setting manifest data with for digest %s %w", digest, err) + } + + return nil + }) + + return err +} + +func (bdw *BoltDB) ProtoSetRepoReference(repo string, reference string, imageData mTypes.ImageData2, +) error { + if err := common.ValidateRepoReferenceInput(repo, reference, imageData.Digest); err != nil { + return err + } + + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + repoBuck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + repoBlobsBuck := tx.Bucket([]byte(ProtoRepoBlobsBuck)) + imageBuck := tx.Bucket([]byte(ProtoImageDataBuck)) + + // 1. Add image data to db if needed + + protoImageData := mConvert.GetProtoImageData(imageData) + + imageDataBlob, err := proto.Marshal(protoImageData) + if err != nil { + return err + } + + imageBuck.Put([]byte(imageData.Digest), imageDataBlob) + + repoMetaBlob := repoBuck.Get([]byte(repo)) + + repoMeta := &proto_go.ProtoRepoMeta{ + Name: repo, + Tags: map[string]*proto_go.TagDescriptor{"": {}}, // This is done so Protobuff can insitialize a non-nill map + Statistics: map[string]*proto_go.DescriptorStatistics{"": {}}, + Signatures: map[string]*proto_go.ManifestSignatures{"": {Map: map[string]*proto_go.SignaturesInfo{"": {}}}}, + Referrers: map[string]*proto_go.ReferrersInfo{"": {}}, + } + + if len(repoMetaBlob) > 0 { + err := proto.Unmarshal(repoMetaBlob, repoMeta) + if err != nil { + return err + } + } + + // 2. Referrers + if protoImageData.Subject != nil { + refList := repoMeta.Referrers[protoImageData.Subject.Digest].List + newRefList := append(refList, &proto_go.ReferrerInfo{ + Digest: protoImageData.Digest, + MediaType: protoImageData.MediaType, + ArtifactType: protoImageData.ArtifacType, + Size: protoImageData.Size, + Annotations: protoImageData.Annotations, + }) + repoMeta.Referrers[protoImageData.Subject.Digest].List = newRefList + } + + // 3. Update tag + if !common.ReferenceIsDigest(reference) { + repoMeta.Tags[reference] = &proto_go.TagDescriptor{ + Digest: imageData.Digest.String(), + MediaType: imageData.MediaType, + } + } + + if _, ok := repoMeta.Statistics[imageData.Digest.String()]; !ok { + repoMeta.Statistics[imageData.Digest.String()] = &proto_go.DescriptorStatistics{DownloadCount: 0} + } + + if _, ok := repoMeta.Signatures[imageData.Digest.String()]; !ok { + repoMeta.Signatures[imageData.Digest.String()] = &proto_go.ManifestSignatures{ + Map: map[string]*proto_go.SignaturesInfo{"": {}}, + } + } + + if _, ok := repoMeta.Referrers[imageData.Digest.String()]; !ok { + repoMeta.Referrers[imageData.Digest.String()] = &proto_go.ReferrersInfo{ + List: []*proto_go.ReferrerInfo{}, + } + } + + // 4. Blobs + repoBlobsBytes := repoBlobsBuck.Get([]byte(repoMeta.Name)) + + repoBlobs := &proto_go.RepoBlobs{} + + if repoBlobsBytes == nil { + repoBlobs.Blobs = map[string]*proto_go.BlobInfo{} + } else { + err := proto.Unmarshal(repoBlobsBytes, repoBlobs) + if err != nil { + return nil + } + } + + repoMeta, repoBlobs, err = common.GetUpdatedRepoMeta(repoMeta, repoBlobs, reference, imageData) + if err != nil { + return err + } + + repoBlobsBytes, err = proto.Marshal(repoBlobs) + if err != nil { + return err + } + + repoBlobsBuck.Put([]byte(repoMeta.Name), repoBlobsBytes) + + repoMetaBlob, err = proto.Marshal(repoMeta) + if err != nil { + return err + } + + return repoBuck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func (bdw *BoltDB) ProtoFilterImageData(ctx context.Context, digests []string, +) (map[string]mTypes.ImageData2, error) { + imageDataMap := map[string]mTypes.ImageData2{} + + err := bdw.DB.View(func(transaction *bbolt.Tx) error { + imageBuck := transaction.Bucket([]byte(ProtoImageDataBuck)) + + for _, digest := range digests { + protoImageData, err := fetchProtoImageData(imageBuck, digest) + if err != nil { + return err + } + + if protoImageData.MediaType == ispec.MediaTypeImageIndex { + for i, manifest := range protoImageData.Manifests { + manifestDigest := manifest.Digest + + imageManifestData, err := fetchProtoImageData(imageBuck, manifestDigest) + if err != nil { + return err + } + + protoImageData.Manifests[i] = imageManifestData.Manifests[0] + } + } + + imageDataMap[digest] = mConvert.GetImageData(protoImageData) + } + + return nil + }) + + return imageDataMap, err +} + +// TODO +func (bdw *BoltDB) ProtoSearchRepos(ctx context.Context, searchText string, +) ([]mTypes.FullRepoMetadata, error) { + repos := []mTypes.FullRepoMetadata{} + + err := bdw.DB.View(func(transaction *bbolt.Tx) error { + var ( + repoBuck = transaction.Bucket([]byte(ProtoRepoMetaBuck)) + userBookmarks = getUserBookmarks(ctx, transaction) + userStars = getUserStars(ctx, transaction) + ) + + cursor := repoBuck.Cursor() + + for repoName, repoMetaBlob := cursor.First(); repoName != nil; repoName, repoMetaBlob = cursor.Next() { + if ok, err := reqCtx.RepoIsUserAvailable(ctx, string(repoName)); !ok || err != nil { + continue + } + + rank := common.RankRepoName(searchText, string(repoName)) + if rank == -1 { + continue + } + + var protoRepoMeta proto_go.ProtoRepoMeta + + err := proto.Unmarshal(repoMetaBlob, &protoRepoMeta) + if err != nil { + return err + } + + delete(protoRepoMeta.Tags, "") + + protoRepoMeta.Rank = int32(rank) + protoRepoMeta.IsStarred = zcommon.Contains(userStars, protoRepoMeta.Name) + protoRepoMeta.IsBookmarked = zcommon.Contains(userBookmarks, protoRepoMeta.Name) + + repos = append(repos, mConvert.GetFullRepoMeta(&protoRepoMeta)) + } + + return nil + }) + + return repos, err +} + +func fetchProtoImageData(imageBuck *bbolt.Bucket, digest string) (*proto_go.ImageData, error) { + imageDataBlob := imageBuck.Get([]byte(digest)) + // TODO: check empty imageDataBlob + + imageData := proto_go.ImageData{} + + err := proto.Unmarshal(imageDataBlob, &imageData) + if err != nil { + return nil, err + } + + return &imageData, nil +} + +func (bdw *BoltDB) ProtoSearchTags(ctx context.Context, searchText string, +) ([]mTypes.FullImageData, error) { + images := []mTypes.FullImageData{} + + searchedRepo, searchedTag, err := common.GetRepoTag(searchText) + if err != nil { + return []mTypes.FullImageData{}, + fmt.Errorf("metadb: error while parsing search text, invalid format %w", err) + } + + err = bdw.DB.View(func(transaction *bbolt.Tx) error { + var ( + repoBuck = transaction.Bucket([]byte(ProtoRepoMetaBuck)) + imageBuck = transaction.Bucket([]byte(ProtoImageDataBuck)) + userBookmarks = getUserBookmarks(ctx, transaction) + userStars = getUserStars(ctx, transaction) + ) + + repoName, repoMetaBlob := repoBuck.Cursor().Seek([]byte(searchedRepo)) + + if string(repoName) != searchedRepo { + return nil + } + + if ok, err := reqCtx.RepoIsUserAvailable(ctx, string(repoName)); !ok || err != nil { + return err + } + + protoRepoMeta := &proto_go.ProtoRepoMeta{} + + err := proto.Unmarshal(repoMetaBlob, protoRepoMeta) + if err != nil { + return err + } + + delete(protoRepoMeta.Tags, "") + + protoRepoMeta.IsBookmarked = zcommon.Contains(userBookmarks, protoRepoMeta.Name) + protoRepoMeta.IsStarred = zcommon.Contains(userStars, protoRepoMeta.Name) + + for tag, descriptor := range protoRepoMeta.Tags { + if !strings.HasPrefix(tag, searchedTag) || tag == "" { + continue + } + + protoImageData := &proto_go.ImageData{} + + switch descriptor.MediaType { + case ispec.MediaTypeImageManifest: + manifestDigest := descriptor.Digest + + imageManifestData, err := fetchProtoImageData(imageBuck, manifestDigest) + if err != nil { + return fmt.Errorf("metadb: error fetching manifest meta for manifest with digest %s %w", + manifestDigest, err) + } + + imageManifestData.Repo = ref(string(repoName)) + imageManifestData.Tag = &tag + + protoImageData = imageManifestData + case ispec.MediaTypeImageIndex: + indexDigest := descriptor.Digest + + imageIndexData, err := fetchProtoImageData(imageBuck, indexDigest) + if err != nil { + return fmt.Errorf("metadb: error fetching manifest meta for manifest with digest %s %w", + indexDigest, err) + } + + for i, manifest := range imageIndexData.Manifests { + manifestDigest := manifest.Digest + + imageManifestData, err := fetchProtoImageData(imageBuck, manifestDigest) + if err != nil { + return err + } + + imageIndexData.Manifests[i] = imageManifestData.Manifests[0] + } + + imageIndexData.Repo = ref(string(repoName)) + imageIndexData.Tag = &tag + + protoImageData = imageIndexData + default: + bdw.Log.Error().Str("mediaType", descriptor.MediaType).Msg("Unsupported media type") + + continue + } + + // fullImageData := getFullImageData(tag, protoRepoMeta, protoImageData) + images = append(images, mConvert.GetFullImageData(tag, protoRepoMeta, protoImageData)) + } + + return nil + }) + + return images, err +} + +func (bdw *BoltDB) ProtoFilterTags(ctx context.Context, filterRepoTag mTypes.FilterRepoTagFunc, filterFunc mTypes.FilterProtoFunc, +) ([]mTypes.FullImageData, error) { + images := []mTypes.FullImageData{} + + err := bdw.DB.View(func(transaction *bbolt.Tx) error { + var ( + repoBuck = transaction.Bucket([]byte(ProtoRepoMetaBuck)) + imageDataBuck = transaction.Bucket([]byte(ProtoImageDataBuck)) + userBookmarks = getUserBookmarks(ctx, transaction) + userStars = getUserStars(ctx, transaction) + ) + + cursor := repoBuck.Cursor() + repoName, repoMetaBlob := cursor.First() + + for ; repoName != nil; repoName, repoMetaBlob = cursor.Next() { + if ok, err := reqCtx.RepoIsUserAvailable(ctx, string(repoName)); !ok || err != nil { + continue + } + + protoRepoMeta := &proto_go.ProtoRepoMeta{} + + err := proto.Unmarshal(repoMetaBlob, protoRepoMeta) + if err != nil { + return err + } + + delete(protoRepoMeta.Tags, "") + protoRepoMeta.IsBookmarked = zcommon.Contains(userBookmarks, protoRepoMeta.Name) + protoRepoMeta.IsStarred = zcommon.Contains(userStars, protoRepoMeta.Name) + repoMeta := mConvert.GetRepoMeta(protoRepoMeta) + + for tag, descriptor := range protoRepoMeta.Tags { + if !filterRepoTag(string(repoName), tag) { + continue + } + + switch descriptor.MediaType { + case ispec.MediaTypeImageManifest: + manifestDigest := descriptor.Digest + + imageManifestData, err := fetchProtoImageData(imageDataBuck, manifestDigest) + if err != nil { + return fmt.Errorf("metadb: error while unmashaling manifest metadata for digest %s %w", manifestDigest, err) + } + + imageManifestData.Repo = ref(repoMeta.Name) + imageManifestData.Tag = ref(tag) + + imageData := mConvert.GetImageData(imageManifestData) + + if filterFunc(repoMeta, imageData) { + images = append(images, mConvert.GetFullImageData(tag, protoRepoMeta, imageManifestData)) + } + case ispec.MediaTypeImageIndex: + indexDigest := descriptor.Digest + + imageIndexData, err := fetchProtoImageData(imageDataBuck, indexDigest) + if err != nil { + return fmt.Errorf("metadb: error while getting index data for digest %s %w", indexDigest, err) + } + + matchedManifests := []*proto_go.ManifestData{} + + for _, manifest := range imageIndexData.Manifests { + manifestDigest := manifest.Digest + + imageManifestData, err := fetchProtoImageData(imageDataBuck, manifestDigest) + if err != nil { + return fmt.Errorf("metadb: error while getting manifest data for digest %s %w", manifestDigest, err) + } + + imageData := mConvert.GetImageData(imageManifestData) + + if filterFunc(repoMeta, imageData) { + matchedManifests = append(matchedManifests, imageManifestData.Manifests[0]) + } + } + + if len(matchedManifests) > 0 { + imageIndexData.Manifests = matchedManifests + + images = append(images, mConvert.GetFullImageData(tag, protoRepoMeta, imageIndexData)) + } + default: + bdw.Log.Error().Str("mediaType", descriptor.MediaType).Msg("Unsupported media type") + + continue + } + } + } + + return nil + }) + + return images, err +} + +func (bdw *BoltDB) ProtoFilterRepos(ctx context.Context, rankName mTypes.FilterRepoNameFunc, filter mTypes.FilterFullRepoFunc, +) ([]mTypes.FullRepoMetadata, error) { + repos := []mTypes.FullRepoMetadata{} + + err := bdw.DB.View(func(tx *bbolt.Tx) error { + var ( + buck = tx.Bucket([]byte(ProtoRepoMetaBuck)) + cursor = buck.Cursor() + userBookmarks = getUserBookmarks(ctx, tx) + userStars = getUserStars(ctx, tx) + ) + + for repoName, repoMetaBlob := cursor.First(); repoName != nil; repoName, repoMetaBlob = cursor.Next() { + if ok, err := reqCtx.RepoIsUserAvailable(ctx, string(repoName)); !ok || err != nil { + continue + } + + rank := rankName(string(repoName)) + if rank < 0 { + continue + } + + repoMeta := proto_go.ProtoRepoMeta{} + + err := json.Unmarshal(repoMetaBlob, &repoMeta) + if err != nil { + return err + } + + repoMeta.Rank = int32(rank) + repoMeta.IsBookmarked = zcommon.Contains(userBookmarks, repoMeta.Name) + repoMeta.IsStarred = zcommon.Contains(userStars, repoMeta.Name) + + fullRepoMeta := mConvert.GetFullRepoMeta(&repoMeta) + + if filter(fullRepoMeta) { + repos = append(repos, fullRepoMeta) + } + } + + return nil + }) + if err != nil { + return []mTypes.FullRepoMetadata{}, err + } + + return repos, err +} + +func (bdw *BoltDB) ProtoGetRepoMeta(repo string) (mTypes.RepoMetadata2, error) { + var protoRepoMeta proto_go.ProtoRepoMeta + + err := bdw.DB.View(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := buck.Get([]byte(repo)) + + // object not found + if repoMetaBlob == nil { + return zerr.ErrRepoMetaNotFound + } + + // object found + err := proto.Unmarshal(repoMetaBlob, &protoRepoMeta) + if err != nil { + return err + } + + return nil + }) + + return mConvert.GetRepoMeta(&protoRepoMeta), err +} + +func (bdw *BoltDB) ProtoGetFullRepoMeta(ctx context.Context, repo string) (mTypes.FullRepoMetadata, error) { + var protoRepoMeta proto_go.ProtoRepoMeta + + err := bdw.DB.View(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + userBookmarks := getUserBookmarks(ctx, tx) + userStars := getUserStars(ctx, tx) + + repoMetaBlob := buck.Get([]byte(repo)) + + // object not found + if repoMetaBlob == nil { + return zerr.ErrRepoMetaNotFound + } + + // object found + err := proto.Unmarshal(repoMetaBlob, &protoRepoMeta) + if err != nil { + return err + } + + delete(protoRepoMeta.Tags, "") + protoRepoMeta.IsBookmarked = zcommon.Contains(userBookmarks, repo) + protoRepoMeta.IsStarred = zcommon.Contains(userStars, repo) + + return nil + }) + + return mConvert.GetFullRepoMeta(&protoRepoMeta), err +} + +func (bdw *BoltDB) ProtoGetImageData(digest godigest.Digest) (mTypes.ImageData2, error) { + imageData := mTypes.ImageData2{} + + err := bdw.DB.View(func(tx *bbolt.Tx) error { + imageBuck := tx.Bucket([]byte(ProtoImageDataBuck)) + + protoImageData, err := fetchProtoImageData(imageBuck, digest.String()) + if err != nil { + return err + } + + if protoImageData.MediaType == ispec.MediaTypeImageIndex { + for i, manifest := range protoImageData.Manifests { + manifestDigest := manifest.Digest + + imageManifestData, err := fetchProtoImageData(imageBuck, manifestDigest) + if err != nil { + return err + } + + protoImageData.Manifests[i] = imageManifestData.Manifests[0] + } + } + + imageData = mConvert.GetImageData(protoImageData) + + return nil + }) + + return imageData, err +} + +func (bdw *BoltDB) ProtoGetMultipleRepoMeta(ctx context.Context, filter func(repoMeta mTypes.RepoMetadata2) bool, +) ([]mTypes.RepoMetadata2, error) { + foundRepos := []mTypes.RepoMetadata2{} + + err := bdw.DB.View(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + cursor := buck.Cursor() + + for repoName, repoMetaBlob := cursor.First(); repoName != nil; repoName, repoMetaBlob = cursor.Next() { + if ok, err := reqCtx.RepoIsUserAvailable(ctx, string(repoName)); !ok || err != nil { + continue + } + + protoRepoMeta := proto_go.ProtoRepoMeta{} + + err := proto.Unmarshal(repoMetaBlob, &protoRepoMeta) + if err != nil { + return err + } + + repoMeta := mConvert.GetRepoMeta(&protoRepoMeta) + + if filter(repoMeta) { + foundRepos = append(foundRepos, repoMeta) + } + } + + return nil + }) + + return foundRepos, err +} + +func (bdw *BoltDB) ProtoAddManifestSignature(repo string, signedManifestDigest godigest.Digest, + sygMeta mTypes.SignatureMetadata, +) error { + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := buck.Get([]byte(repo)) + + if len(repoMetaBlob) == 0 { + var err error + // create a new object + repoMeta := proto_go.ProtoRepoMeta{ + Name: repo, + Tags: map[string]*proto_go.TagDescriptor{}, + Signatures: map[string]*proto_go.ManifestSignatures{ + signedManifestDigest.String(): { + Map: map[string]*proto_go.SignaturesInfo{ + sygMeta.SignatureType: { + List: []*proto_go.SignatureInfo{ + { + SignatureManifestDigest: sygMeta.SignatureDigest, + LayersInfo: mConvert.GetProtoLayersInfo(sygMeta.LayersInfo), + }, + }, + }, + }, + }, + }, + Statistics: map[string]*proto_go.DescriptorStatistics{"": {}}, + } + + repoMetaBlob, err = proto.Marshal(&repoMeta) + if err != nil { + return err + } + + return buck.Put([]byte(repo), repoMetaBlob) + } + + protoRepoMeta := &proto_go.ProtoRepoMeta{} + + err := proto.Unmarshal(repoMetaBlob, protoRepoMeta) + if err != nil { + return err + } + + var ( + manifestSignatures *proto_go.ManifestSignatures + found bool + ) + + if manifestSignatures, found = protoRepoMeta.Signatures[signedManifestDigest.String()]; !found { + manifestSignatures = &proto_go.ManifestSignatures{Map: map[string]*proto_go.SignaturesInfo{"": {}}} + } + + signatureSlice := &proto_go.SignaturesInfo{List: []*proto_go.SignatureInfo{}} + if sigSlice, found := manifestSignatures.Map[sygMeta.SignatureType]; found { + signatureSlice = sigSlice + } + + if !common.ProtoSignatureAlreadyExists(signatureSlice.List, sygMeta) { + switch sygMeta.SignatureType { + case zcommon.NotationSignature: + signatureSlice.List = append(signatureSlice.List, &proto_go.SignatureInfo{ + SignatureManifestDigest: sygMeta.SignatureDigest, + LayersInfo: mConvert.GetProtoLayersInfo(sygMeta.LayersInfo), + }) + case zcommon.CosignSignature: + signatureSlice.List = []*proto_go.SignatureInfo{{ + SignatureManifestDigest: sygMeta.SignatureDigest, + LayersInfo: mConvert.GetProtoLayersInfo(sygMeta.LayersInfo), + }} + } + } + + manifestSignatures.Map[sygMeta.SignatureType] = signatureSlice + protoRepoMeta.Signatures[signedManifestDigest.String()] = manifestSignatures + + repoMetaBlob, err = proto.Marshal(protoRepoMeta) + if err != nil { + return err + } + + return buck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func (bdw *BoltDB) ProtoDeleteSignature(repo string, signedManifestDigest godigest.Digest, sigMeta mTypes.SignatureMetadata) error { + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := buck.Get([]byte(repo)) + if repoMetaBlob == nil { + return zerr.ErrManifestMetaNotFound + } + + protoRepoMeta := proto_go.ProtoRepoMeta{} + + err := json.Unmarshal(repoMetaBlob, &protoRepoMeta) + if err != nil { + return err + } + + manifestSignatures, found := protoRepoMeta.Signatures[signedManifestDigest.String()] + if !found { + return zerr.ErrManifestMetaNotFound + } + + signatureSlice := manifestSignatures.Map[sigMeta.SignatureType] + + newSignatureSlice := make([]*proto_go.SignatureInfo, 0, len(signatureSlice.List)) + + for _, sigInfo := range signatureSlice.List { + if sigInfo.SignatureManifestDigest != sigMeta.SignatureDigest { + newSignatureSlice = append(newSignatureSlice, sigInfo) + } + } + + manifestSignatures.Map[sigMeta.SignatureType] = &proto_go.SignaturesInfo{List: newSignatureSlice} + + protoRepoMeta.Signatures[signedManifestDigest.String()] = manifestSignatures + + repoMetaBlob, err = proto.Marshal(&protoRepoMeta) + if err != nil { + return err + } + + return buck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func (bdw *BoltDB) ProtoIncrementRepoStars(repo string) error { + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := buck.Get([]byte(repo)) + if repoMetaBlob == nil { + return zerr.ErrRepoMetaNotFound + } + + var repoMeta proto_go.ProtoRepoMeta + + err := proto.Unmarshal(repoMetaBlob, &repoMeta) + if err != nil { + return err + } + + repoMeta.Stars++ + + repoMetaBlob, err = proto.Marshal(&repoMeta) + if err != nil { + return err + } + + return buck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func (bdw *BoltDB) ProtoDecrementRepoStars(repo string) error { + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := buck.Get([]byte(repo)) + if repoMetaBlob == nil { + return zerr.ErrRepoMetaNotFound + } + + var repoMeta proto_go.ProtoRepoMeta + + err := proto.Unmarshal(repoMetaBlob, &repoMeta) + if err != nil { + return err + } + + if repoMeta.Stars == 0 { + return nil + } + + repoMeta.Stars-- + + repoMetaBlob, err = proto.Marshal(&repoMeta) + if err != nil { + return err + } + + return buck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func (bdw *BoltDB) ProtoGetRepoStars(repo string) (int, error) { + stars := 0 + + err := bdw.DB.View(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + buck.Get([]byte(repo)) + repoMetaBlob := buck.Get([]byte(repo)) + if repoMetaBlob == nil { + return zerr.ErrRepoMetaNotFound + } + + var repoMeta proto_go.ProtoRepoMeta + + err := proto.Unmarshal(repoMetaBlob, &repoMeta) + if err != nil { + return err + } + + stars = int(repoMeta.Stars) + + return nil + }) + + return stars, err +} + +func (bdw *BoltDB) ProtoDeleteRepoTag(repo string, tag string) error { + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := buck.Get([]byte(repo)) + + // object not found + if repoMetaBlob == nil { + return nil + } + + // object found + var repoMeta proto_go.ProtoRepoMeta + + err := proto.Unmarshal(repoMetaBlob, &repoMeta) + if err != nil { + return err + } + + delete(repoMeta.Tags, tag) + + repoMetaBlob, err = proto.Marshal(&repoMeta) + if err != nil { + return err + } + + return buck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func (bdw *BoltDB) ProtoGetUserRepoMeta(ctx context.Context, repo string) (mTypes.RepoMetadata2, error) { + var repoMeta proto_go.ProtoRepoMeta + + err := bdw.DB.View(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + userBookmarks := getUserBookmarks(ctx, tx) + userStars := getUserStars(ctx, tx) + + repoMetaBlob := buck.Get([]byte(repo)) + + // object not found + if repoMetaBlob == nil { + return zerr.ErrRepoMetaNotFound + } + + // object found + err := proto.Unmarshal(repoMetaBlob, &repoMeta) + if err != nil { + return err + } + + repoMeta.IsBookmarked = zcommon.Contains(userBookmarks, repo) + repoMeta.IsStarred = zcommon.Contains(userStars, repo) + + return nil + }) + + return mConvert.GetRepoMeta(&repoMeta), err +} + +func (bdw *BoltDB) ProtoSetRepoMeta(repo string, repoMeta mTypes.RepoMetadata2) error { + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMeta.Name = repo + + repoMetaBlob, err := proto.Marshal(mConvert.GetProtoRepoMeta(repoMeta)) + if err != nil { + return err + } + + return buck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func (bdw *BoltDB) ProtoGetReferrersInfo(repo string, referredDigest godigest.Digest, artifactTypes []string) ([]mTypes.ReferrerInfo, error) { + referrersInfoResult := []mTypes.ReferrerInfo{} + + err := bdw.DB.View(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := buck.Get([]byte(repo)) + if len(repoMetaBlob) == 0 { + return zerr.ErrRepoMetaNotFound + } + + var repoMeta proto_go.ProtoRepoMeta + + err := proto.Unmarshal(repoMetaBlob, &repoMeta) + if err != nil { + return err + } + + referrersInfo := repoMeta.Referrers[referredDigest.String()].List + + for i := range referrersInfo { + if !common.MatchesArtifactTypes(referrersInfo[i].ArtifactType, artifactTypes) { + continue + } + + referrersInfoResult = append(referrersInfoResult, mTypes.ReferrerInfo{ + Digest: referrersInfo[i].Digest, + MediaType: referrersInfo[i].MediaType, + ArtifactType: referrersInfo[i].ArtifactType, + Size: int(referrersInfo[i].Size), + Annotations: referrersInfo[i].Annotations, + }) + } + + return nil + }) + + return referrersInfoResult, err +} + +func (bdw *BoltDB) ProtoIncrementImageDownloads(repo string, reference string) error { + err := bdw.DB.Update(func(tx *bbolt.Tx) error { + buck := tx.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := buck.Get([]byte(repo)) + if repoMetaBlob == nil { + return zerr.ErrManifestMetaNotFound + } + + var repoMeta proto_go.ProtoRepoMeta + + err := proto.Unmarshal(repoMetaBlob, &repoMeta) + if err != nil { + return err + } + + manifestDigest := reference + + if !common.ReferenceIsDigest(reference) { + // search digest for tag + descriptor, found := repoMeta.Tags[reference] + + if !found { + return zerr.ErrManifestMetaNotFound + } + + manifestDigest = descriptor.Digest + } + + manifestStatistics := repoMeta.Statistics[manifestDigest] + manifestStatistics.DownloadCount++ + repoMeta.Statistics[manifestDigest] = manifestStatistics + + repoMetaBlob, err = proto.Marshal(&repoMeta) + if err != nil { + return err + } + + return buck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func (bdw *BoltDB) ProtoUpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error { + err := bdw.DB.Update(func(transaction *bbolt.Tx) error { + imgTrustStore := bdw.ImageTrustStore() + + if imgTrustStore == nil { + return nil + } + + // get ManifestData of signed manifest + imageDataBuck := transaction.Bucket([]byte(ProtoImageDataBuck)) + idBlob := imageDataBuck.Get([]byte(manifestDigest)) + + if len(idBlob) != 0 { + // manifest meta not found, updating signatures with details about validity and author will not be performed + return nil + } + + protoImageData := proto_go.ImageData{} + + err := proto.Unmarshal(idBlob, &protoImageData) + if err != nil { + return err + } + + // update signatures with details about validity and author + repoBuck := transaction.Bucket([]byte(ProtoRepoMetaBuck)) + + repoMetaBlob := repoBuck.Get([]byte(repo)) + if repoMetaBlob == nil { + return zerr.ErrRepoMetaNotFound + } + + protoRepoMeta := proto_go.ProtoRepoMeta{} + + err = proto.Unmarshal(repoMetaBlob, &protoRepoMeta) + if err != nil { + return err + } + + manifestSignatures := proto_go.ManifestSignatures{Map: map[string]*proto_go.SignaturesInfo{"": {}}} + for sigType, sigs := range protoRepoMeta.Signatures[manifestDigest.String()].Map { + signaturesInfo := []*proto_go.SignatureInfo{} + + for _, sigInfo := range sigs.List { + layersInfo := []*proto_go.LayersInfo{} + + for _, layerInfo := range sigInfo.LayersInfo { + author, date, isTrusted, _ := imgTrustStore.ProtoVerifySignature(sigType, layerInfo.LayerContent, + layerInfo.SignatureKey, manifestDigest, mConvert.GetImageData(&protoImageData), repo) + + if isTrusted { + layerInfo.Signer = author + } + + if !date.IsZero() { + layerInfo.Signer = author + layerInfo.Date = timestamppb.New(date) + } + + layersInfo = append(layersInfo, layerInfo) + } + + signaturesInfo = append(signaturesInfo, &proto_go.SignatureInfo{ + SignatureManifestDigest: sigInfo.SignatureManifestDigest, + LayersInfo: layersInfo, + }) + } + + manifestSignatures.Map[sigType] = &proto_go.SignaturesInfo{List: signaturesInfo} + } + + protoRepoMeta.Signatures[manifestDigest.String()] = &manifestSignatures + + repoMetaBlob, err = proto.Marshal(&protoRepoMeta) + if err != nil { + return err + } + + return repoBuck.Put([]byte(repo), repoMetaBlob) + }) + + return err +} + +func ref[T any](input T) *T { + ref := input + + return &ref +} diff --git a/pkg/meta/common/common.go b/pkg/meta/common/common.go index f97dfa010f..2c989b7bad 100644 --- a/pkg/meta/common/common.go +++ b/pkg/meta/common/common.go @@ -10,6 +10,9 @@ 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" + "zotregistry.io/zot/pkg/meta/proto_go" mTypes "zotregistry.io/zot/pkg/meta/types" ) @@ -41,6 +44,16 @@ func SignatureAlreadyExists(signatureSlice []mTypes.SignatureInfo, sm mTypes.Sig return false } +func ProtoSignatureAlreadyExists(signatureSlice []*proto_go.SignatureInfo, sm mTypes.SignatureMetadata) bool { + for _, sigInfo := range signatureSlice { + if sm.SignatureDigest == sigInfo.SignatureManifestDigest { + return true + } + } + + return false +} + func ReferenceIsDigest(reference string) bool { _, err := godigest.Parse(reference) @@ -344,3 +357,135 @@ func InitializeImageConfig(blob []byte) ispec.Image { return configContent } + +func GetUpdatedRepoMeta(repoMeta *proto_go.ProtoRepoMeta, repoBlobs *proto_go.RepoBlobs, ref string, + imageData mTypes.ImageData2, +) (*proto_go.ProtoRepoMeta, *proto_go.RepoBlobs, error) { + switch imageData.MediaType { + case ispec.MediaTypeImageManifest: + manifestData := imageData.Manifests[0] + vendor := GetVendor(manifestData.Manifest.Annotations) + if vendor == "" { + vendor = GetVendor(manifestData.Manifest.Annotations) + } + + vendors := []string{} + if vendor != "" { + vendors = append(vendors, vendor) + } + + platforms := []*proto_go.Platform{getProtoPlatform(&imageData.Manifests[0].ConfigContent.Platform)} + if platforms[0].Os == "" && platforms[0].Arch == "" { + platforms = []*proto_go.Platform{} + } + + subBlobs := []string{manifestData.Config.Digest.String()} + repoBlobs.Blobs[manifestData.Config.Digest.String()] = &proto_go.BlobInfo{ + Size: manifestData.Config.Size, + } + + for _, layer := range manifestData.Layers { + subBlobs = append(subBlobs, layer.Digest.String()) + repoBlobs.Blobs[layer.Digest.String()] = &proto_go.BlobInfo{Size: layer.Size} + } + + repoBlobs.Blobs[imageData.Digest.String()] = &proto_go.BlobInfo{ + Size: imageData.Size, + Vendors: vendors, + Platforms: platforms, + SubBlobs: subBlobs, + LastUpdated: mConvert.GetProtoTime(manifestData.ConfigContent.Created), + } + case ispec.MediaTypeImageIndex: + subBlobs := []string{} + for _, manifest := range imageData.Manifests { + subBlobs = append(subBlobs, manifest.Digest.String()) + } + + repoBlobs.Blobs[imageData.Digest.String()] = &proto_go.BlobInfo{ + Size: imageData.Size, + SubBlobs: subBlobs, + } + } + + imageBlobInfo := repoBlobs.Blobs[imageData.Digest.String()] + + repoMeta.Vendors = mConvert.AddVendors(repoMeta.Vendors, imageBlobInfo.Vendors) + repoMeta.Platforms = mConvert.AddProtoPlatforms(repoMeta.Platforms, imageBlobInfo.Platforms) + repoMeta.Size = int32(getRepoSize(repoMeta, repoBlobs)) + + if zcommon.IsTag(ref) { + repoMeta.LastUpdatedImage = mConvert.GetProtoEarlierUpdatedImage(repoMeta.LastUpdatedImage, + &proto_go.RepoLastUpdatedImage{ + LastUpdated: imageBlobInfo.LastUpdated, + MediaType: imageData.MediaType, + Digest: imageData.Digest.String(), + Tag: ref, + }) + } + + return repoMeta, repoBlobs, nil +} + +func getRepoSize(repoMeta *proto_go.ProtoRepoMeta, repoBlobs *proto_go.RepoBlobs) int64 { + size := int64(0) + blobsMap := map[string]struct{}{} + + 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] + blobsMap[currentBlob] = struct{}{} + size += blobInfo.Size + + queue = append(queue, blobInfo.SubBlobs...) + } + } + } + + return size +} + +func getProtoPlatform(platform *ispec.Platform) *proto_go.Platform { + if platform == nil { + return nil + } + + return &proto_go.Platform{ + Arch: getArch(platform.Architecture, platform.Variant), + Os: platform.OS, + } +} + +func getArch(arch string, variant string) string { + if variant != "" { + arch = arch + "/" + variant + } + + return arch +} + +func GetVendor(annotations map[string]string) string { + return GetAnnotationValue(annotations, ispec.AnnotationVendor, "org.label-schema.vendor") +} + +func GetAnnotationValue(annotations map[string]string, annotationKey, labelKey string) string { + value, ok := annotations[annotationKey] + if !ok || value == "" { + value, ok = annotations[labelKey] + if !ok { + value = "" + } + } + + return value +} diff --git a/pkg/meta/convert/convert.go b/pkg/meta/convert/convert.go new file mode 100644 index 0000000000..5637657384 --- /dev/null +++ b/pkg/meta/convert/convert.go @@ -0,0 +1,317 @@ +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" + "zotregistry.io/zot/pkg/meta/proto_go" + + mTypes "zotregistry.io/zot/pkg/meta/types" +) + +func GetImageManifestData(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest godigest.Digest) mTypes.ImageData2 { + return mTypes.ImageData2{ + MediaType: ispec.MediaTypeImageManifest, + Digest: digest, + Size: size, + Manifests: []mTypes.ManifestData2{ + { + Digest: digest, + Size: size, + ConfigContent: configContent, + Manifest: manifestContent, + }, + }, + } +} + +func GetImageIndexData(indexContent ispec.Index, size int64, digest godigest.Digest) mTypes.ImageData2 { + return mTypes.ImageData2{ + MediaType: ispec.MediaTypeImageIndex, + Index: &indexContent, + Manifests: getManifests(indexContent.Manifests), + Size: size, + Digest: digest, + } +} + +func GetProtoImageData(imageData mTypes.ImageData2) *proto_go.ImageData { + switch imageData.MediaType { + case ispec.MediaTypeImageManifest: + if len(imageData.Manifests) == 0 { + return nil + } + + return GetProtoImageManifestData(imageData.Manifests[0].Manifest, imageData.Manifests[0].ConfigContent, + imageData.Manifests[0].Size, imageData.Manifests[0].Digest.String()) + case ispec.MediaTypeImageIndex: + if imageData.Index == nil { + return nil + } + + return GetProtoImageIndexData(*imageData.Index, imageData.Size, imageData.Digest.String()) + default: + return nil + } +} + +func GetProtoImageIndexData(indexContent ispec.Index, size int64, digest string) *proto_go.ImageData { + return &proto_go.ImageData{ + Versioned: &proto_go.Versioned{Schemaversion: int32(indexContent.SchemaVersion)}, + MediaType: ispec.MediaTypeImageIndex, + ArtifacType: common.GetIndexArtifactType(indexContent), + Manifests: getProtoManifests(indexContent.Manifests), + Subject: getProtoDesc(indexContent.Subject), + Annotations: indexContent.Annotations, + Size: size, + Digest: digest, + } +} + +func getProtoManifests(descriptors []ispec.Descriptor) []*proto_go.ManifestData { + manifestList := []*proto_go.ManifestData{} + + for _, manifest := range descriptors { + manifestList = append(manifestList, &proto_go.ManifestData{ + MediaType: ref(ispec.MediaTypeImageManifest), + Digest: manifest.Digest.String(), + }) + } + + return manifestList +} + +func getManifests(descriptors []ispec.Descriptor) []mTypes.ManifestData2 { + manifestList := []mTypes.ManifestData2{} + + for _, manifest := range descriptors { + manifestList = append(manifestList, mTypes.ManifestData2{ + Digest: manifest.Digest, + Size: manifest.Size, + }) + } + + return manifestList +} + +func GetProtoImageManifestData(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest string, +) *proto_go.ImageData { + return &proto_go.ImageData{ + Versioned: &proto_go.Versioned{Schemaversion: int32(manifestContent.SchemaVersion)}, + MediaType: ispec.MediaTypeImageManifest, + Manifests: []*proto_go.ManifestData{GetProtoManifestData(manifestContent, configContent, size, digest)}, + ArtifacType: common.GetManifestArtifactType(manifestContent), + Subject: getProtoDesc(manifestContent.Subject), + Annotations: manifestContent.Annotations, + Size: size, + Digest: digest, + } +} + +func GetProtoManifestData(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest string, +) *proto_go.ManifestData { + return &proto_go.ManifestData{ + Versioned: &proto_go.Versioned{Schemaversion: int32(manifestContent.SchemaVersion)}, + Digest: digest, + MediaType: ref(ispec.MediaTypeImageManifest), + Config: &proto_go.ConfigData{ + Digest: manifestContent.Config.Digest.String(), + Size: manifestContent.Config.Size, + Created: GetProtoTime(configContent.Created), + Author: &configContent.Author, + Platform: &proto_go.Platform{ + Arch: getArch(configContent.Architecture, configContent.Variant), + Os: configContent.OS, + // Osversion: &configContent.OSVersion, + // Osfeatures: configContent.OSFeatures, + // Variant: &configContent.Variant, + }, + 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, + Argsescaped: configContent.Config.ArgsEscaped, + }, + Rootfs: &proto_go.RootFS{ + Type: configContent.RootFS.Type, + Diffids: getProtoDiffIDs(configContent.RootFS.DiffIDs), + }, + History: getProtoHistory(configContent.History), + }, + Size: size, + ArtifactType: ref(common.GetManifestArtifactType(manifestContent)), + Layers: getProtoManifestLayers(manifestContent.Layers), + Subject: getProtoDesc(manifestContent.Subject), + Annotations: manifestContent.Annotations, + } +} + +func getArch(arch string, variant string) string { + if variant != "" { + arch = arch + "/" + variant + } + + return arch +} + +func GetProtoTime(time *time.Time) *timestamppb.Timestamp { + if time == nil { + return nil + } + + return timestamppb.New(*time) +} + +func GetTime(time *timestamppb.Timestamp) *time.Time { + if time == nil { + return nil + } + + return ref(time.AsTime()) +} + +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 getProtoPlatform(platform *ispec.Platform) *proto_go.Platform { + if platform == nil { + return nil + } + + return &proto_go.Platform{ + Arch: getArch(platform.Architecture, platform.Variant), + Os: platform.OS, + // Osversion: &platform.OSVersion, + // Osfeatures: platform.OSFeatures, + // Variant: &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 GetProtoRefferrerInfo(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 GetFullImageData(tag string, protoRepoMeta *proto_go.ProtoRepoMeta, protoImageData *proto_go.ImageData, +) mTypes.FullImageData { + imageData := GetImageData(protoImageData) + imageDigest := imageData.Digest.String() + + return mTypes.FullImageData{ + Repo: protoRepoMeta.Name, + Tag: tag, + MediaType: imageData.MediaType, + Digest: imageData.Digest, + Size: imageData.Size, + Index: imageData.Index, + Manifests: GetFullManifestData(protoRepoMeta, imageData.Manifests), + + Referrers: GetImageReferrers(protoRepoMeta.Referrers[imageDigest]), + Statistics: GetImageStatistics(protoRepoMeta.Statistics[imageDigest]), + Signatures: GetImageSignatures(protoRepoMeta.Signatures[imageDigest]), + } +} + +func GetFullManifestData(protoRepoMeta *proto_go.ProtoRepoMeta, manifestData []mTypes.ManifestData2, +) []mTypes.FullManifestData { + results := []mTypes.FullManifestData{} + + for i := range manifestData { + results = append(results, mTypes.FullManifestData{ + ManifestData2: 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 +} diff --git a/pkg/meta/convert/convert2.go b/pkg/meta/convert/convert2.go new file mode 100644 index 0000000000..1f3ed27a96 --- /dev/null +++ b/pkg/meta/convert/convert2.go @@ -0,0 +1,555 @@ +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" + zcommon "zotregistry.io/zot/pkg/common" + "zotregistry.io/zot/pkg/meta/proto_go" + + mTypes "zotregistry.io/zot/pkg/meta/types" +) + +func GetRepoMeta(repo *proto_go.ProtoRepoMeta) mTypes.RepoMetadata2 { + return mTypes.RepoMetadata2{ + Name: repo.Name, + Tags: getTags(repo.Tags), + Statistics: GetStatisticsMap(repo.Statistics), + Signatures: GetSignatures(repo.Signatures), + Referrers: GetReferrers(repo.Referrers), + } +} + +func GetProtoRepoMeta(repo mTypes.RepoMetadata2) *proto_go.ProtoRepoMeta { + return &proto_go.ProtoRepoMeta{ + Name: repo.Name, + Tags: getProtoTags(repo.Tags), + Statistics: getProtoStatistics(repo.Statistics), + Signatures: getProtoSignatures(repo.Signatures), + Referrers: getProtoReferrers(repo.Referrers), + } +} + +func GetImageData(dbImageData *proto_go.ImageData) mTypes.ImageData2 { + imageData := mTypes.ImageData2{ + MediaType: dbImageData.MediaType, + Size: dbImageData.Size, + Digest: godigest.Digest(dbImageData.Digest), + } + + if dbImageData.MediaType == ispec.MediaTypeImageIndex { + manifests := make([]ispec.Descriptor, 0, len(dbImageData.Manifests)) + var subject *ispec.Descriptor + + for _, manifest := range dbImageData.Manifests { + manifests = append(manifests, ispec.Descriptor{ + MediaType: deref(manifest.MediaType, ""), + Digest: godigest.Digest(manifest.Digest), + Size: manifest.Size, + }) + } + + if dbImageData.Subject != nil { + subject = &ispec.Descriptor{ + MediaType: dbImageData.Subject.MediaType, + Digest: godigest.Digest(dbImageData.Subject.Digest), + Size: dbImageData.Subject.Size, + } + } + + imageData.Index = &ispec.Index{ + Versioned: specs.Versioned{SchemaVersion: int(dbImageData.Versioned.GetSchemaversion())}, + MediaType: ispec.MediaTypeImageIndex, + ArtifactType: dbImageData.ArtifacType, + Manifests: manifests, + Subject: subject, + Annotations: dbImageData.Annotations, + } + } + + manifestDataList := make([]mTypes.ManifestData2, 0, len(dbImageData.Manifests)) + + for _, manifest := range dbImageData.Manifests { + manifestDataList = append(manifestDataList, mTypes.ManifestData2{ + Size: manifest.Size, + Digest: godigest.Digest(manifest.Digest), + Manifest: ispec.Manifest{ + Versioned: specs.Versioned{SchemaVersion: int(manifest.Versioned.GetSchemaversion())}, + MediaType: deref(manifest.MediaType, ""), + ArtifactType: deref(manifest.ArtifactType, ""), + Config: ispec.Descriptor{ + MediaType: ispec.MediaTypeImageConfig, // TODO add config media type to manifest data in DB + Size: manifest.Config.Size, + Digest: godigest.Digest(manifest.Config.Digest), + }, + Layers: getLayers(manifest.Layers), + Subject: getSubject(manifest.Subject), + Annotations: manifest.Annotations, + }, + ConfigContent: ispec.Image{ + Created: getTime(manifest.Config.Created), + Author: deref(manifest.Config.Author, ""), + Platform: getPlatform(manifest.Config.Platform), + Config: ispec.ImageConfig{}, + RootFS: ispec.RootFS{}, + History: getHistory(manifest.Config.History), + }, + }) + } + + imageData.Manifests = manifestDataList + + return imageData +} + +func getTime(time *timestamppb.Timestamp) *time.Time { + if time == nil { + return nil + } + + return ref(time.AsTime()) +} + +func getHistory(history []*proto_go.History) []ispec.History { + 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 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 +} + +func getPlatform(platform *proto_go.Platform) ispec.Platform { + if platform == nil { + return ispec.Platform{} + } + + return ispec.Platform{ + Architecture: platform.Arch, + 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 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 { + return mTypes.DescriptorStatistics{ + DownloadCount: int(stats.DownloadCount), + } +} + +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 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 { + 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 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, &proto_go.ReferrerInfo{ + Digest: dbRef.Digest, + MediaType: dbRef.MediaType, + ArtifactType: dbRef.ArtifactType, + Size: int64(dbRef.Size), + Annotations: dbRef.Annotations, + }) + } + + results[digest] = &proto_go.ReferrersInfo{List: referrersInfoList} + } + + 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 { + results := mTypes.ManifestSignatures{} + + for signatureName, signatureInfo := range sigs.Map { + results[signatureName] = getSignaturesInfo(signatureInfo.List) + } + + 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 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 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, 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 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 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 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 GetFullRepoMeta(protoRepoMeta *proto_go.ProtoRepoMeta) mTypes.FullRepoMetadata { + repoDownloads := int32(0) + + for _, descriptor := range protoRepoMeta.Tags { + repoDownloads += protoRepoMeta.Statistics[descriptor.Digest].DownloadCount + } + + return mTypes.FullRepoMetadata{ + 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, ispec.Platform{ + OS: platforms[i].Os, + Architecture: platforms[i].Arch, + }) + } + + return result +} + +func GetLastUpdated(timestamp *timestamppb.Timestamp) *time.Time { + if timestamp == nil { + return nil + } + + return ref(timestamp.AsTime()) +} + +func AddPlatforms(platforms []ispec.Platform, newPlatforms []ispec.Platform) []ispec.Platform { + for _, newPlatform := range newPlatforms { + if !ContainsPlatform(platforms, newPlatform) { + platforms = append(platforms, newPlatform) + } + } + + return platforms +} + +func ContainsPlatform(platforms []ispec.Platform, platform ispec.Platform) bool { + for i := range platforms { + if platforms[i].OS == platform.OS || platforms[i].Architecture == platform.Architecture { + return true + } + } + + return false +} + +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].Arch == platform.Arch { + return true + } + } + + return false +} + +func AddVendors(vendors []string, newVendors []string) []string { + for _, newVendor := range newVendors { + if !zcommon.Contains(vendors, newVendor) { + vendors = append(vendors, newVendor) + } + } + + return vendors +} + +func GetEarlierLastUpdated(lastUpdated *time.Time, newLastUpdated *time.Time) *time.Time { + if newLastUpdated == nil { + return lastUpdated + } + + if lastUpdated == nil { + return newLastUpdated + } + + if lastUpdated.Before(*newLastUpdated) { + return newLastUpdated + } + + return lastUpdated +} + +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 GetProtoEarlierUpdatedImage(repoLastImage *proto_go.RepoLastUpdatedImage, newLastImage *proto_go.RepoLastUpdatedImage, +) *proto_go.RepoLastUpdatedImage { + if repoLastImage == nil { + return newLastImage + } + + if newLastImage == nil || newLastImage.LastUpdated == nil { + return repoLastImage + } + + if repoLastImage.LastUpdated == nil { + return newLastImage + } + + if repoLastImage.LastUpdated.AsTime().Before(newLastImage.LastUpdated.AsTime()) { + return newLastImage + } + + return repoLastImage +} diff --git a/pkg/meta/convert/convert_full.go b/pkg/meta/convert/convert_full.go new file mode 100644 index 0000000000..3a85f2ff86 --- /dev/null +++ b/pkg/meta/convert/convert_full.go @@ -0,0 +1,18 @@ +package convert + +// import ( +// "zotregistry.io/zot/pkg/meta/proto_go" + +// mTypes "zotregistry.io/zot/pkg/meta/types" +// ) + +// // func GetFullRepoMeta(repo *proto_go.ProtoRepoMeta) mTypes.FullRepoMetadata { + +// // return mTypes.FullRepoMetadata{ +// // Name: repo.Name, +// // Tags: getTags(repo.Tags), +// // Statistics: getStatistics(repo.Statistics), +// // Signatures: getSignatures(repo.Signatures), +// // Referrers: getReferrers(repo.Referrers), +// // } +// // } diff --git a/pkg/meta/dynamodb/dynamodb.go b/pkg/meta/dynamodb/dynamodb.go index 84c20e2d63..e486fe1fb9 100644 --- a/pkg/meta/dynamodb/dynamodb.go +++ b/pkg/meta/dynamodb/dynamodb.go @@ -14,12 +14,16 @@ import ( "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" godigest "github.com/opencontainers/go-digest" ispec "github.com/opencontainers/image-spec/specs-go/v1" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" zerr "zotregistry.io/zot/errors" "zotregistry.io/zot/pkg/api/constants" zcommon "zotregistry.io/zot/pkg/common" "zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/meta/common" + mConvert "zotregistry.io/zot/pkg/meta/convert" + "zotregistry.io/zot/pkg/meta/proto_go" mTypes "zotregistry.io/zot/pkg/meta/types" "zotregistry.io/zot/pkg/meta/version" reqCtx "zotregistry.io/zot/pkg/requestcontext" @@ -28,32 +32,38 @@ import ( var errMetaDB = errors.New("metadb: error while constructing manifest meta") type DynamoDB struct { - Client *dynamodb.Client - APIKeyTablename string - RepoMetaTablename string - IndexDataTablename string - ManifestDataTablename string - UserDataTablename string - VersionTablename string - Patches []func(client *dynamodb.Client, tableNames map[string]string) error - imgTrustStore mTypes.ImageTrustStore - Log log.Logger + Client *dynamodb.Client + APIKeyTablename string + RepoMetaTablename string + ProtoRepoMetaTablename string + ProtoRepoBlobsTablename string + ProtoImageDataTablename string + IndexDataTablename string + ManifestDataTablename string + UserDataTablename string + VersionTablename string + Patches []func(client *dynamodb.Client, tableNames map[string]string) error + imgTrustStore mTypes.ImageTrustStore + Log log.Logger } func New( client *dynamodb.Client, params DBDriverParameters, log log.Logger, ) (*DynamoDB, error) { dynamoWrapper := DynamoDB{ - Client: client, - RepoMetaTablename: params.RepoMetaTablename, - ManifestDataTablename: params.ManifestDataTablename, - IndexDataTablename: params.IndexDataTablename, - VersionTablename: params.VersionTablename, - UserDataTablename: params.UserDataTablename, - APIKeyTablename: params.APIKeyTablename, - Patches: version.GetDynamoDBPatches(), - imgTrustStore: nil, - Log: log, + Client: client, + RepoMetaTablename: params.RepoMetaTablename, + ManifestDataTablename: params.ManifestDataTablename, + IndexDataTablename: params.IndexDataTablename, + VersionTablename: params.VersionTablename, + UserDataTablename: params.UserDataTablename, + APIKeyTablename: params.APIKeyTablename, + ProtoRepoMetaTablename: "Proto" + params.RepoMetaTablename, // TODO CHANGE + ProtoImageDataTablename: "Proto" + params.ManifestDataTablename, // TODO CHANGE + ProtoRepoBlobsTablename: "ProtoBlobs" + params.RepoMetaTablename, + Patches: version.GetDynamoDBPatches(), + imgTrustStore: nil, + Log: log, } err := dynamoWrapper.createVersionTable() @@ -61,17 +71,17 @@ func New( return nil, err } - err = dynamoWrapper.createRepoMetaTable() + err = dynamoWrapper.createProtoRepoMetaTable() if err != nil { return nil, err } - err = dynamoWrapper.createManifestDataTable() + err = dynamoWrapper.createProtoRepoBlobsTable() if err != nil { return nil, err } - err = dynamoWrapper.createIndexDataTable() + err = dynamoWrapper.createProtoImageDataTable() if err != nil { return nil, err } @@ -1462,6 +1472,56 @@ func (dwr *DynamoDB) createRepoMetaTable() error { return dwr.waitTableToBeCreated(dwr.RepoMetaTablename) } +func (dwr *DynamoDB) createProtoRepoMetaTable() error { + _, err := dwr.Client.CreateTable(context.Background(), &dynamodb.CreateTableInput{ + TableName: aws.String(dwr.ProtoRepoMetaTablename), + AttributeDefinitions: []types.AttributeDefinition{ + { + AttributeName: aws.String("RepoName"), + AttributeType: types.ScalarAttributeTypeS, + }, + }, + KeySchema: []types.KeySchemaElement{ + { + AttributeName: aws.String("RepoName"), + KeyType: types.KeyTypeHash, + }, + }, + BillingMode: types.BillingModePayPerRequest, + }) + + if err != nil && !strings.Contains(err.Error(), "Table already exists") { + return err + } + + return dwr.waitTableToBeCreated(dwr.ProtoRepoMetaTablename) +} + +func (dwr *DynamoDB) createProtoRepoBlobsTable() error { + _, err := dwr.Client.CreateTable(context.Background(), &dynamodb.CreateTableInput{ + TableName: aws.String(dwr.ProtoRepoBlobsTablename), + AttributeDefinitions: []types.AttributeDefinition{ + { + AttributeName: aws.String("RepoName"), + AttributeType: types.ScalarAttributeTypeS, + }, + }, + KeySchema: []types.KeySchemaElement{ + { + AttributeName: aws.String("RepoName"), + KeyType: types.KeyTypeHash, + }, + }, + BillingMode: types.BillingModePayPerRequest, + }) + + if err != nil && !strings.Contains(err.Error(), "Table already exists") { + return err + } + + return dwr.waitTableToBeCreated(dwr.ProtoRepoMetaTablename) +} + func (dwr *DynamoDB) deleteRepoMetaTable() error { _, err := dwr.Client.DeleteTable(context.Background(), &dynamodb.DeleteTableInput{ TableName: aws.String(dwr.RepoMetaTablename), @@ -1474,6 +1534,18 @@ func (dwr *DynamoDB) deleteRepoMetaTable() error { return dwr.waitTableToBeDeleted(dwr.RepoMetaTablename) } +func (dwr *DynamoDB) deleteProtoRepoMetaTable() error { + _, err := dwr.Client.DeleteTable(context.Background(), &dynamodb.DeleteTableInput{ + TableName: aws.String(dwr.ProtoRepoMetaTablename), + }) + + if temp := new(types.ResourceNotFoundException); errors.As(err, &temp) { + return nil + } + + return dwr.waitTableToBeDeleted(dwr.ProtoRepoMetaTablename) +} + func (dwr *DynamoDB) ResetRepoMetaTable() error { err := dwr.deleteRepoMetaTable() if err != nil { @@ -1483,6 +1555,40 @@ func (dwr *DynamoDB) ResetRepoMetaTable() error { return dwr.createRepoMetaTable() } +func (dwr *DynamoDB) ResetRepoRepoMetaTable() error { + err := dwr.deleteProtoRepoMetaTable() + if err != nil { + return err + } + + return dwr.createRepoMetaTable() +} + +func (dwr *DynamoDB) createProtoImageDataTable() error { + _, err := dwr.Client.CreateTable(context.Background(), &dynamodb.CreateTableInput{ + TableName: aws.String(dwr.ProtoImageDataTablename), + AttributeDefinitions: []types.AttributeDefinition{ + { + AttributeName: aws.String("Digest"), + AttributeType: types.ScalarAttributeTypeS, + }, + }, + KeySchema: []types.KeySchemaElement{ + { + AttributeName: aws.String("Digest"), + KeyType: types.KeyTypeHash, + }, + }, + BillingMode: types.BillingModePayPerRequest, + }) + + if err != nil && !strings.Contains(err.Error(), "Table already exists") { + return err + } + + return dwr.waitTableToBeCreated(dwr.ProtoImageDataTablename) +} + func (dwr *DynamoDB) waitTableToBeCreated(tableName string) error { const maxWaitTime = 20 * time.Second @@ -2212,3 +2318,1081 @@ func (dwr DynamoDB) DeleteUserData(ctx context.Context) error { return err } + +func (dwr *DynamoDB) SetProtoImageData(digest godigest.Digest, protoImageData *proto_go.ImageData) error { + bytes, err := proto.Marshal(protoImageData) + if err != nil { + return err + } + + mdAttributeValue, err := attributevalue.Marshal(bytes) + if err != nil { + return err + } + + resp, err := dwr.Client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{ + ExpressionAttributeNames: map[string]string{ + "#ID": "ImageData", + }, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":ImageData": mdAttributeValue, + }, + Key: map[string]types.AttributeValue{ + "Digest": &types.AttributeValueMemberS{ + Value: protoImageData.Digest, + }, + }, + TableName: aws.String(dwr.ProtoImageDataTablename), + UpdateExpression: aws.String("SET #ID = :ImageData"), + }) + _ = resp + + return err +} + +func (dwr *DynamoDB) ProtoSetImageData(digest godigest.Digest, imageData mTypes.ImageData2) error { + return dwr.SetProtoImageData(imageData.Digest, mConvert.GetProtoImageData(imageData)) +} + +func (dwr *DynamoDB) GetProtoImageData(digest godigest.Digest) (*proto_go.ImageData, error) { + resp, err := dwr.Client.GetItem(context.TODO(), &dynamodb.GetItemInput{ + TableName: aws.String(dwr.ProtoImageDataTablename), + Key: map[string]types.AttributeValue{ + "Digest": &types.AttributeValueMemberS{Value: digest.String()}, + }, + }) + if err != nil { + return nil, err + } + + blob := []byte{} + + err = attributevalue.Unmarshal(resp.Item["ImageData"], &blob) + if err != nil { + return nil, err + } + + imageData := &proto_go.ImageData{} + + err = proto.Unmarshal(blob, imageData) + if err != nil { + return nil, err + } + + return imageData, nil +} + +func (dwr *DynamoDB) setProtoRepoMeta(repo string, repoMeta *proto_go.ProtoRepoMeta) error { + repoMeta.Name = repo + + repoMetaBlob, err := proto.Marshal(repoMeta) + if err != nil { + return err + } + + repoAttributeValue, err := attributevalue.Marshal(repoMetaBlob) + if err != nil { + return err + } + + _, err = dwr.Client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{ + ExpressionAttributeNames: map[string]string{ + "#RM": "RepoMetadata", + }, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":RepoMetadata": repoAttributeValue, + }, + Key: map[string]types.AttributeValue{ + "RepoName": &types.AttributeValueMemberS{ + Value: repo, + }, + }, + TableName: aws.String(dwr.ProtoRepoMetaTablename), + UpdateExpression: aws.String("SET #RM = :RepoMetadata"), + }) + + return err +} + +func (dwr *DynamoDB) getProtoRepoMeta(repo string) (*proto_go.ProtoRepoMeta, error) { + resp, err := dwr.Client.GetItem(context.TODO(), &dynamodb.GetItemInput{ + TableName: aws.String(dwr.ProtoRepoMetaTablename), + Key: map[string]types.AttributeValue{ + "RepoName": &types.AttributeValueMemberS{Value: repo}, + }, + }) + if err != nil { + return nil, err + } + + if resp.Item == nil { + return nil, zerr.ErrRepoMetaNotFound + } + + blob := []byte{} + + err = attributevalue.Unmarshal(resp.Item["RepoMetadata"], &blob) + if err != nil { + return nil, err + } + + repoMeta := &proto_go.ProtoRepoMeta{} + + err = proto.Unmarshal(blob, repoMeta) + if err != nil { + return nil, err + } + + return repoMeta, nil +} + +func (dwr *DynamoDB) ProtoSetRepoReference(repo string, reference string, imageData mTypes.ImageData2) error { + if err := common.ValidateRepoReferenceInput(repo, reference, imageData.Digest); err != nil { + return err + } + + // 1. Add image data to db if needed + protoImageData := mConvert.GetProtoImageData(imageData) + + err := dwr.SetProtoImageData(imageData.Digest, protoImageData) + if err != nil { + return err + } + + repoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + if !errors.Is(err, zerr.ErrRepoMetaNotFound) { + return err + } + + repoMeta = &proto_go.ProtoRepoMeta{ + Name: repo, + Tags: map[string]*proto_go.TagDescriptor{"": {}}, + Statistics: map[string]*proto_go.DescriptorStatistics{"": {}}, + Signatures: map[string]*proto_go.ManifestSignatures{"": {Map: map[string]*proto_go.SignaturesInfo{"": {}}}}, + Referrers: map[string]*proto_go.ReferrersInfo{"": {}}, + } + } + + // 2. Referrers + if protoImageData.Subject != nil { + refList := repoMeta.Referrers[protoImageData.Subject.Digest].List + newRefList := append(refList, &proto_go.ReferrerInfo{ + Digest: protoImageData.Digest, + MediaType: protoImageData.MediaType, + ArtifactType: protoImageData.ArtifacType, + Size: protoImageData.Size, + Annotations: protoImageData.Annotations, + }) + repoMeta.Referrers[protoImageData.Subject.Digest].List = newRefList + } + + // 3. Update tag + if !common.ReferenceIsDigest(reference) { + repoMeta.Tags[reference] = &proto_go.TagDescriptor{ + Digest: imageData.Digest.String(), + MediaType: imageData.MediaType, + } + } + + if _, ok := repoMeta.Statistics[imageData.Digest.String()]; !ok { + repoMeta.Statistics[imageData.Digest.String()] = &proto_go.DescriptorStatistics{DownloadCount: 0} + } + + if _, ok := repoMeta.Signatures[imageData.Digest.String()]; !ok { + repoMeta.Signatures[imageData.Digest.String()] = &proto_go.ManifestSignatures{ + Map: map[string]*proto_go.SignaturesInfo{"": {}}, + } + } + + if _, ok := repoMeta.Referrers[imageData.Digest.String()]; !ok { + repoMeta.Referrers[imageData.Digest.String()] = &proto_go.ReferrersInfo{ + List: []*proto_go.ReferrerInfo{}, + } + } + + // 4. Blobs + repoBlobs, err := dwr.getRepoBlobsInfo(repo) + if err != nil { + return err + } + + repoMeta, repoBlobs, err = common.GetUpdatedRepoMeta(repoMeta, repoBlobs, reference, imageData) + if err != nil { + return err + } + + err = dwr.setRepoBlobsInfo(repo, repoBlobs) + if err != nil { + return err + } + + return dwr.setProtoRepoMeta(repo, repoMeta) +} + +func (dwr *DynamoDB) getRepoBlobsInfo(repo string) (*proto_go.RepoBlobs, error) { + resp, err := dwr.Client.GetItem(context.Background(), &dynamodb.GetItemInput{ + TableName: aws.String(dwr.ProtoRepoBlobsTablename), + Key: map[string]types.AttributeValue{ + "RepoName": &types.AttributeValueMemberS{Value: repo}, + }, + }) + if err != nil { + return nil, err + } + + if resp.Item == nil { + return &proto_go.RepoBlobs{Name: repo, Blobs: map[string]*proto_go.BlobInfo{"": {}}}, nil + } + + repoBlobsBytes := []byte{} + + err = attributevalue.Unmarshal(resp.Item["RepoBlobsInfo"], &repoBlobsBytes) + if err != nil { + return nil, err + } + + repoBlobs := &proto_go.RepoBlobs{} + if repoBlobsBytes == nil { + repoBlobs.Blobs = map[string]*proto_go.BlobInfo{} + } else { + err := proto.Unmarshal(repoBlobsBytes, repoBlobs) + if err != nil { + return nil, err + } + } + + return repoBlobs, nil +} + +func (dwr *DynamoDB) setRepoBlobsInfo(repo string, repoBlobs *proto_go.RepoBlobs) error { + bytes, err := proto.Marshal(repoBlobs) + if err != nil { + return err + } + + mdAttributeValue, err := attributevalue.Marshal(bytes) + if err != nil { + return err + } + + _, err = dwr.Client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{ + ExpressionAttributeNames: map[string]string{ + "#RBI": "RepoBlobsInfo", + }, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":RepoBlobsInfo": mdAttributeValue, + }, + Key: map[string]types.AttributeValue{ + "RepoName": &types.AttributeValueMemberS{ + Value: repo, + }, + }, + TableName: aws.String(dwr.ProtoRepoBlobsTablename), + UpdateExpression: aws.String("SET #RBI = :RepoBlobsInfo"), + }) + + return err +} + +func (dwr *DynamoDB) ProtoSearchRepos(ctx context.Context, searchText string) ([]mTypes.FullRepoMetadata, error) { + repos := []mTypes.FullRepoMetadata{} + + userBookmarks := getUserBookmarks(ctx, dwr) + userStars := getUserStars(ctx, dwr) + + repoMetaAttributeIterator := NewBaseDynamoAttributesIterator( + dwr.Client, dwr.ProtoRepoMetaTablename, "RepoMetadata", 0, dwr.Log, + ) + + repoMetaAttribute, err := repoMetaAttributeIterator.First(ctx) + + for ; repoMetaAttribute != nil; repoMetaAttribute, err = repoMetaAttributeIterator.Next(ctx) { + if err != nil { + return []mTypes.FullRepoMetadata{}, err + } + + repoMetaBlob := []byte{} + + err := attributevalue.Unmarshal(repoMetaAttribute, &repoMetaBlob) + if err != nil { + return []mTypes.FullRepoMetadata{}, err + } + + protoRepoMeta := &proto_go.ProtoRepoMeta{} + + err = proto.Unmarshal(repoMetaBlob, protoRepoMeta) + if err != nil { + return []mTypes.FullRepoMetadata{}, err + } + + if ok, err := reqCtx.RepoIsUserAvailable(ctx, protoRepoMeta.Name); !ok || err != nil { + continue + } + + rank := common.RankRepoName(searchText, protoRepoMeta.Name) + if rank == -1 { + continue + } + + protoRepoMeta.Rank = int32(rank) + protoRepoMeta.IsStarred = zcommon.Contains(userStars, protoRepoMeta.Name) + protoRepoMeta.IsBookmarked = zcommon.Contains(userBookmarks, protoRepoMeta.Name) + + repos = append(repos, mConvert.GetFullRepoMeta(protoRepoMeta)) + + } + + return repos, nil +} + +func (dwr *DynamoDB) ProtoSearchTags(ctx context.Context, searchText string) ([]mTypes.FullImageData, error) { + images := []mTypes.FullImageData{} + userBookmarks := getUserBookmarks(ctx, dwr) + userStars := getUserStars(ctx, dwr) + + searchedRepo, searchedTag, err := common.GetRepoTag(searchText) + if err != nil { + return []mTypes.FullImageData{}, + fmt.Errorf("metadb: error while parsing search text, invalid format %w", err) + } + + if ok, err := reqCtx.RepoIsUserAvailable(ctx, searchedRepo); !ok || err != nil { + return []mTypes.FullImageData{}, err + } + + protoRepoMeta, err := dwr.getProtoRepoMeta(searchedRepo) + if err != nil { + return nil, err + } + + delete(protoRepoMeta.Tags, "") + + protoRepoMeta.IsBookmarked = zcommon.Contains(userBookmarks, searchedRepo) + protoRepoMeta.IsStarred = zcommon.Contains(userStars, searchedRepo) + + for tag, descriptor := range protoRepoMeta.Tags { + if !strings.HasPrefix(tag, searchedTag) { + continue + } + + protoImageData := &proto_go.ImageData{} + + switch descriptor.MediaType { + case ispec.MediaTypeImageManifest: + manifestDigest := descriptor.Digest + + imageManifestData, err := dwr.GetProtoImageData(godigest.Digest(manifestDigest)) + if err != nil { + return []mTypes.FullImageData{}, + fmt.Errorf("metadb: error fetching manifest meta for manifest with digest %s %w", manifestDigest, err) + } + + imageManifestData.Repo = ref(searchedRepo) + imageManifestData.Tag = &tag + + protoImageData = imageManifestData + case ispec.MediaTypeImageIndex: + indexDigest := godigest.Digest(descriptor.Digest) + + imageIndexData, err := dwr.GetProtoImageData(indexDigest) + if err != nil { + return []mTypes.FullImageData{}, + fmt.Errorf("metadb: error fetching manifest meta for manifest with digest %s %w", indexDigest, err) + } + + for i, manifest := range imageIndexData.Manifests { + manifestDigest := godigest.Digest(manifest.Digest) + + imageManifestData, err := dwr.GetProtoImageData(manifestDigest) + if err != nil { + return []mTypes.FullImageData{}, err + } + + imageIndexData.Manifests[i] = imageManifestData.Manifests[0] + } + + imageIndexData.Repo = ref(searchedRepo) + imageIndexData.Tag = &tag + + protoImageData = imageIndexData + default: + dwr.Log.Error().Str("mediaType", descriptor.MediaType).Msg("Unsupported media type") + + continue + } + + images = append(images, mConvert.GetFullImageData(tag, protoRepoMeta, protoImageData)) + } + + return images, err +} + +func ref[T any](input T) *T { + ref := input + + return &ref +} + +func (dwr *DynamoDB) ProtoFilterTags(ctx context.Context, filterRepoTag mTypes.FilterRepoTagFunc, filterFunc mTypes.FilterProtoFunc, +) ([]mTypes.FullImageData, error) { + images := []mTypes.FullImageData{} + userBookmarks := getUserBookmarks(ctx, dwr) + userStars := getUserStars(ctx, dwr) + + repoMetaAttributeIterator := NewBaseDynamoAttributesIterator( + dwr.Client, dwr.ProtoRepoMetaTablename, "RepoMetadata", 0, dwr.Log, + ) + + repoMetaAttribute, err := repoMetaAttributeIterator.First(ctx) + + for ; repoMetaAttribute != nil; repoMetaAttribute, err = repoMetaAttributeIterator.Next(ctx) { + if err != nil { + return []mTypes.FullImageData{}, + err + } + + protoRepoMeta, err := getProtoRepoMetaFromAttribute(repoMetaAttribute) + if err != nil { + return nil, err + } + + if ok, err := reqCtx.RepoIsUserAvailable(ctx, protoRepoMeta.Name); !ok || err != nil { + continue + } + + protoRepoMeta.IsBookmarked = zcommon.Contains(userBookmarks, protoRepoMeta.Name) + protoRepoMeta.IsStarred = zcommon.Contains(userStars, protoRepoMeta.Name) + repoMeta := mConvert.GetRepoMeta(protoRepoMeta) + + for tag, descriptor := range repoMeta.Tags { + if !filterRepoTag(repoMeta.Name, tag) { + continue + } + + switch descriptor.MediaType { + case ispec.MediaTypeImageManifest: + manifestDigest := descriptor.Digest + + imageManifestData, err := dwr.GetProtoImageData(godigest.Digest(manifestDigest)) + if err != nil { + return []mTypes.FullImageData{}, + fmt.Errorf("metadb: error fetching manifest meta for manifest with digest %s %w", manifestDigest, err) + } + + imageManifestData.Repo = ref(repoMeta.Name) + imageManifestData.Tag = &tag + + imageData := mConvert.GetImageData(imageManifestData) + + if filterFunc(repoMeta, imageData) { + images = append(images, mConvert.GetFullImageData(tag, protoRepoMeta, imageManifestData)) + } + case ispec.MediaTypeImageIndex: + indexDigest := descriptor.Digest + + imageIndexData, err := dwr.GetProtoImageData(godigest.Digest(indexDigest)) + if err != nil { + return []mTypes.FullImageData{}, + fmt.Errorf("metadb: error fetching manifest meta for manifest with digest %s %w", indexDigest, err) + } + + matchedManifests := []*proto_go.ManifestData{} + + for _, manifest := range imageIndexData.Manifests { + manifestDigest := manifest.Digest + + imageManifestData, err := dwr.GetProtoImageData(godigest.Digest(manifestDigest)) + if err != nil { + return []mTypes.FullImageData{}, + fmt.Errorf("metadb: error while getting manifest data for digest %s %w", manifestDigest, err) + } + + imageData := mConvert.GetImageData(imageManifestData) + + if filterFunc(repoMeta, imageData) { + matchedManifests = append(matchedManifests, imageManifestData.Manifests[0]) + } + } + + if len(matchedManifests) > 0 { + imageIndexData.Manifests = matchedManifests + + images = append(images, mConvert.GetFullImageData(tag, protoRepoMeta, imageIndexData)) + } + default: + dwr.Log.Error().Str("mediaType", descriptor.MediaType).Msg("Unsupported media type") + + continue + } + } + } + + return images, err +} + +func getProtoRepoMetaFromAttribute(repoMetaAttribute types.AttributeValue) (*proto_go.ProtoRepoMeta, error) { + blob := []byte{} + + err := attributevalue.Unmarshal(repoMetaAttribute, &blob) + if err != nil { + return nil, err + } + + protoRepoMeta := &proto_go.ProtoRepoMeta{} + + err = proto.Unmarshal(blob, protoRepoMeta) + if err != nil { + return nil, err + } + + return protoRepoMeta, nil +} + +func getProtoImageDataFromAttribute(imageDataAttribute types.AttributeValue) (*proto_go.ImageData, error) { + blob := []byte{} + + err := attributevalue.Unmarshal(imageDataAttribute, &blob) + if err != nil { + return nil, err + } + + protoImageData := &proto_go.ImageData{} + + err = proto.Unmarshal(blob, protoImageData) + if err != nil { + return nil, err + } + + return protoImageData, nil +} + +func (dwr *DynamoDB) ProtoGetRepoMeta(repo string) (mTypes.RepoMetadata2, error) { + protoRepoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + return mTypes.RepoMetadata2{}, err + } + + delete(protoRepoMeta.Tags, "") + + return mConvert.GetRepoMeta(protoRepoMeta), nil +} + +func (dwr *DynamoDB) ProtoGetFullRepoMeta(ctx context.Context, repo string) (mTypes.FullRepoMetadata, error) { + protoRepoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + return mTypes.FullRepoMetadata{}, err + } + + delete(protoRepoMeta.Tags, "") + + return mConvert.GetFullRepoMeta(protoRepoMeta), nil +} + +func (dwr *DynamoDB) ProtoGetImageData(digest godigest.Digest) (mTypes.ImageData2, error) { + imageData, err := dwr.GetProtoImageData(digest) + if err != nil { + return mTypes.ImageData2{}, err + } + + return mConvert.GetImageData(imageData), nil +} + +func (dwr *DynamoDB) ProtoGetMultipleRepoMeta(ctx context.Context, filter func(repoMeta mTypes.RepoMetadata2) bool, +) ([]mTypes.RepoMetadata2, error) { + var ( + foundRepos = []mTypes.RepoMetadata2{} + repoMetaAttributeIterator AttributesIterator + ) + + repoMetaAttributeIterator = NewBaseDynamoAttributesIterator( + dwr.Client, dwr.ProtoRepoMetaTablename, "RepoMetadata", 0, dwr.Log, + ) + + repoMetaAttribute, err := repoMetaAttributeIterator.First(ctx) + + for ; repoMetaAttribute != nil; repoMetaAttribute, err = repoMetaAttributeIterator.Next(ctx) { + if err != nil { + return []mTypes.RepoMetadata2{}, err + } + + repoMetaBlob := []byte{} + + err := attributevalue.Unmarshal(repoMetaAttribute, &repoMetaBlob) + if err != nil { + return []mTypes.RepoMetadata2{}, err + } + + protoRepoMeta := &proto_go.ProtoRepoMeta{} + + err = proto.Unmarshal(repoMetaBlob, protoRepoMeta) + if err != nil { + return []mTypes.RepoMetadata2{}, err + } + + if ok, err := reqCtx.RepoIsUserAvailable(ctx, protoRepoMeta.Name); !ok || err != nil { + continue + } + + repoMeta := mConvert.GetRepoMeta(protoRepoMeta) + + if filter(repoMeta) { + foundRepos = append(foundRepos, repoMeta) + } + } + + return foundRepos, err +} + +func (dwr *DynamoDB) ProtoFilterRepos(ctx context.Context, rankName mTypes.FilterRepoNameFunc, filterFunc mTypes.FilterFullRepoFunc, +) ([]mTypes.FullRepoMetadata, error) { + repos := []mTypes.FullRepoMetadata{} + userBookmarks := getUserBookmarks(ctx, dwr) + userStars := getUserStars(ctx, dwr) + + repoMetaAttributeIterator := NewBaseDynamoAttributesIterator( + dwr.Client, dwr.ProtoRepoMetaTablename, "RepoMetadata", 0, dwr.Log, + ) + + repoMetaAttribute, err := repoMetaAttributeIterator.First(ctx) + + for ; repoMetaAttribute != nil; repoMetaAttribute, err = repoMetaAttributeIterator.Next(ctx) { + if err != nil { + return []mTypes.FullRepoMetadata{}, + err + } + + protoRepoMeta, err := getProtoRepoMetaFromAttribute(repoMetaAttribute) + if err != nil { + return nil, err + } + + if ok, err := reqCtx.RepoIsUserAvailable(ctx, protoRepoMeta.Name); !ok || err != nil { + continue + } + + rank := rankName(string(protoRepoMeta.Name)) + if rank < 0 { + continue + } + + protoRepoMeta.Rank = int32(rank) + protoRepoMeta.IsBookmarked = zcommon.Contains(userBookmarks, protoRepoMeta.Name) + protoRepoMeta.IsStarred = zcommon.Contains(userStars, protoRepoMeta.Name) + + fullRepoMeta := mConvert.GetFullRepoMeta(protoRepoMeta) + + if filterFunc(fullRepoMeta) { + repos = append(repos, fullRepoMeta) + } + } + + return repos, err +} + +func (dwr *DynamoDB) ProtoIncrementRepoStars(repo string) error { + repoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + return err + } + + repoMeta.Stars++ + + return dwr.setProtoRepoMeta(repo, repoMeta) +} + +func (dwr *DynamoDB) ProtoDecrementRepoStars(repo string) error { + repoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + return err + } + + repoMeta.Stars-- + + return dwr.setProtoRepoMeta(repo, repoMeta) +} + +func (dwr *DynamoDB) ProtoGetRepoStars(repo string) (int, error) { + repoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + return 0, err + } + + return int(repoMeta.Stars), nil +} + +func (dwr *DynamoDB) ProtoDeleteRepoTag(repo string, tag string) error { + resp, err := dwr.Client.GetItem(context.TODO(), &dynamodb.GetItemInput{ + TableName: aws.String(dwr.ProtoRepoMetaTablename), + Key: map[string]types.AttributeValue{ + "RepoName": &types.AttributeValueMemberS{Value: repo}, + }, + }) + if err != nil { + return err + } + + if resp.Item == nil { + return nil + } + + repoMetaBlob := []byte{} + + err = attributevalue.Unmarshal(resp.Item["RepoMetadata"], &repoMetaBlob) + if err != nil { + return err + } + + repoMeta := &proto_go.ProtoRepoMeta{} + + err = proto.Unmarshal(repoMetaBlob, repoMeta) + if err != nil { + return err + } + + delete(repoMeta.Tags, tag) + + repoMetaBlob, err = proto.Marshal(repoMeta) + if err != nil { + return err + } + + repoAttributeValue, err := attributevalue.Marshal(repoMetaBlob) + if err != nil { + return err + } + + _, err = dwr.Client.UpdateItem(context.TODO(), &dynamodb.UpdateItemInput{ + ExpressionAttributeNames: map[string]string{ + "#RM": "RepoMetadata", + }, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":RepoMetadata": repoAttributeValue, + }, + Key: map[string]types.AttributeValue{ + "RepoName": &types.AttributeValueMemberS{ + Value: repo, + }, + }, + TableName: aws.String(dwr.ProtoRepoMetaTablename), + UpdateExpression: aws.String("SET #RM = :RepoMetadata"), + }) + + return err +} + +func (dwr *DynamoDB) ProtoGetUserRepoMeta(ctx context.Context, repo string) (mTypes.RepoMetadata2, error) { + resp, err := dwr.Client.GetItem(ctx, &dynamodb.GetItemInput{ + TableName: aws.String(dwr.ProtoRepoMetaTablename), + Key: map[string]types.AttributeValue{ + "RepoName": &types.AttributeValueMemberS{Value: repo}, + }, + }) + if err != nil { + return mTypes.RepoMetadata2{}, err + } + + if resp.Item == nil { + return mTypes.RepoMetadata2{}, zerr.ErrRepoMetaNotFound + } + + var repoMeta mTypes.RepoMetadata2 + + err = attributevalue.Unmarshal(resp.Item["RepoMetadata"], &repoMeta) + if err != nil { + return mTypes.RepoMetadata2{}, err + } + + userData, err := dwr.GetUserData(ctx) + if err != nil { + return mTypes.RepoMetadata2{}, err + } + + repoMeta.IsBookmarked = zcommon.Contains(userData.BookmarkedRepos, repo) + repoMeta.IsStarred = zcommon.Contains(userData.StarredRepos, repo) + + return repoMeta, nil +} + +func (dwr *DynamoDB) ProtoSetRepoMeta(repo string, repoMeta mTypes.RepoMetadata2) error { + protoRepoMeta := mConvert.GetProtoRepoMeta(repoMeta) + + return dwr.setProtoRepoMeta(repo, protoRepoMeta) +} + +func (dwr *DynamoDB) ProtoGetReferrersInfo(repo string, referredDigest godigest.Digest, artifactTypes []string) ([]mTypes.ReferrerInfo, error) { + repoMeta, err := dwr.GetRepoMeta(repo) + if err != nil { + return []mTypes.ReferrerInfo{}, err + } + + referrersInfo := repoMeta.Referrers[referredDigest.String()] + + filteredResults := make([]mTypes.ReferrerInfo, 0, len(referrersInfo)) + + for _, referrerInfo := range referrersInfo { + if !common.MatchesArtifactTypes(referrerInfo.ArtifactType, artifactTypes) { + continue + } + + filteredResults = append(filteredResults, referrerInfo) + } + + return filteredResults, nil +} + +func (dwr *DynamoDB) ProtoIncrementImageDownloads(repo string, reference string) error { + repoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + return err + } + + descriptorDigest := reference + + if !common.ReferenceIsDigest(reference) { + // search digest for tag + descriptor, found := repoMeta.Tags[reference] + + if !found { + return zerr.ErrManifestMetaNotFound + } + + descriptorDigest = descriptor.Digest + } + + manifestStatistics := repoMeta.Statistics[descriptorDigest] + manifestStatistics.DownloadCount++ + repoMeta.Statistics[descriptorDigest] = manifestStatistics + + return dwr.setProtoRepoMeta(repo, repoMeta) +} + +func (dwr *DynamoDB) ProtoUpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error { + imgTrustStore := dwr.ImageTrustStore() + + if imgTrustStore == nil { + return nil + } + + protoImageData, err := dwr.GetProtoImageData(manifestDigest) + if err != nil { + return err + } + + // update signatures with details about validity and author + protoRepoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + return err + } + + manifestSignatures := proto_go.ManifestSignatures{Map: map[string]*proto_go.SignaturesInfo{"": {}}} + for sigType, sigs := range protoRepoMeta.Signatures[manifestDigest.String()].Map { + signaturesInfo := []*proto_go.SignatureInfo{} + + for _, sigInfo := range sigs.List { + layersInfo := []*proto_go.LayersInfo{} + + for _, layerInfo := range sigInfo.LayersInfo { + author, date, isTrusted, _ := imgTrustStore.ProtoVerifySignature(sigType, layerInfo.LayerContent, + layerInfo.SignatureKey, manifestDigest, mConvert.GetImageData(protoImageData), repo) + + if isTrusted { + layerInfo.Signer = author + } + + if !date.IsZero() { + layerInfo.Signer = author + layerInfo.Date = timestamppb.New(date) + } + + layersInfo = append(layersInfo, layerInfo) + } + + signaturesInfo = append(signaturesInfo, &proto_go.SignatureInfo{ + SignatureManifestDigest: sigInfo.SignatureManifestDigest, + LayersInfo: layersInfo, + }) + } + + manifestSignatures.Map[sigType] = &proto_go.SignaturesInfo{List: signaturesInfo} + } + + protoRepoMeta.Signatures[manifestDigest.String()] = &manifestSignatures + + return dwr.setProtoRepoMeta(protoRepoMeta.Name, protoRepoMeta) +} + +func (dwr *DynamoDB) ProtoAddManifestSignature(repo string, signedManifestDigest godigest.Digest, + sygMeta mTypes.SignatureMetadata, +) error { + protoRepoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + if errors.Is(err, zerr.ErrRepoMetaNotFound) { + protoRepoMeta = &proto_go.ProtoRepoMeta{ + Name: repo, + Tags: map[string]*proto_go.TagDescriptor{}, + Statistics: map[string]*proto_go.DescriptorStatistics{"": {}}, + Referrers: map[string]*proto_go.ReferrersInfo{"": {}}, + Signatures: map[string]*proto_go.ManifestSignatures{ + signedManifestDigest.String(): { + Map: map[string]*proto_go.SignaturesInfo{ + sygMeta.SignatureType: { + List: []*proto_go.SignatureInfo{ + { + SignatureManifestDigest: sygMeta.SignatureDigest, + LayersInfo: mConvert.GetProtoLayersInfo(sygMeta.LayersInfo), + }, + }, + }, + }, + }, + }, + } + + return dwr.setProtoRepoMeta(repo, protoRepoMeta) + } + + return err + } + + var ( + manifestSignatures *proto_go.ManifestSignatures + found bool + ) + + if manifestSignatures, found = protoRepoMeta.Signatures[signedManifestDigest.String()]; !found { + manifestSignatures = &proto_go.ManifestSignatures{Map: map[string]*proto_go.SignaturesInfo{"": {}}} + } + + signatureSlice := &proto_go.SignaturesInfo{List: []*proto_go.SignatureInfo{}} + if sigSlice, found := manifestSignatures.Map[sygMeta.SignatureType]; found { + signatureSlice = sigSlice + } + + if !common.ProtoSignatureAlreadyExists(signatureSlice.List, sygMeta) { + switch sygMeta.SignatureType { + case zcommon.NotationSignature: + signatureSlice.List = append(signatureSlice.List, &proto_go.SignatureInfo{ + SignatureManifestDigest: sygMeta.SignatureDigest, + LayersInfo: mConvert.GetProtoLayersInfo(sygMeta.LayersInfo), + }) + case zcommon.CosignSignature: + signatureSlice.List = []*proto_go.SignatureInfo{{ + SignatureManifestDigest: sygMeta.SignatureDigest, + LayersInfo: mConvert.GetProtoLayersInfo(sygMeta.LayersInfo), + }} + } + } + + manifestSignatures.Map[sygMeta.SignatureType] = signatureSlice + protoRepoMeta.Signatures[signedManifestDigest.String()] = manifestSignatures + + return dwr.setProtoRepoMeta(protoRepoMeta.Name, protoRepoMeta) +} + +func (dwr *DynamoDB) ProtoDeleteSignature(repo string, signedManifestDigest godigest.Digest, sigMeta mTypes.SignatureMetadata, +) error { + protoRepoMeta, err := dwr.getProtoRepoMeta(repo) + if err != nil { + return err + } + + sigType := sigMeta.SignatureType + + var ( + manifestSignatures *proto_go.ManifestSignatures + found bool + ) + + if manifestSignatures, found = protoRepoMeta.Signatures[signedManifestDigest.String()]; !found { + return zerr.ErrManifestMetaNotFound + } + + signatureSlice := manifestSignatures.Map[sigType] + + newSignatureSlice := make([]*proto_go.SignatureInfo, 0, len(signatureSlice.List)-1) + + for _, sigDigest := range signatureSlice.List { + if sigDigest.SignatureManifestDigest != sigMeta.SignatureDigest { + newSignatureSlice = append(newSignatureSlice, sigDigest) + } + } + + manifestSignatures.Map[sigMeta.SignatureType] = &proto_go.SignaturesInfo{List: newSignatureSlice} + + protoRepoMeta.Signatures[signedManifestDigest.String()] = manifestSignatures + + return dwr.setProtoRepoMeta(protoRepoMeta.Name, protoRepoMeta) +} + +func (dwr *DynamoDB) ProtoFilterImageData(ctx context.Context, digests []string, +) (map[string]mTypes.ImageData2, error) { + imageDataAttributes, err := dwr.fetchImageDataAttributesByDigest(ctx, digests) + if err != nil { + return nil, err + } + + results := map[string]mTypes.ImageData2{} + + for _, attributes := range imageDataAttributes { + protoImageData, err := getProtoImageDataFromAttribute(attributes["ImageData"]) + if err != nil { + return nil, err + } + + if protoImageData.MediaType == ispec.MediaTypeImageIndex { + indexDigests := []string{} + for i := range protoImageData.Manifests { + indexDigests = append(indexDigests, protoImageData.Manifests[i].Digest) + } + + manifestsAttributes, err := dwr.fetchImageDataAttributesByDigest(ctx, indexDigests) + if err != nil { + return nil, err + } + + for i, manifestAttribute := range manifestsAttributes { + imageManifestData, err := getProtoImageDataFromAttribute(manifestAttribute["ImageData"]) + if err != nil { + return nil, err + } + + protoImageData.Manifests[i] = imageManifestData.Manifests[0] + } + } + + results[protoImageData.Digest] = mConvert.GetImageData(protoImageData) + } + + return results, nil +} + +func (dwr *DynamoDB) fetchImageDataAttributesByDigest(ctx context.Context, digests []string, +) ([]map[string]types.AttributeValue, error) { + resp, err := dwr.Client.BatchGetItem(ctx, &dynamodb.BatchGetItemInput{ + RequestItems: map[string]types.KeysAndAttributes{ + dwr.ProtoImageDataTablename: { + Keys: getBatchImageKeys(digests), + }, + }, + }) + if err != nil { + return nil, err + } + + return resp.Responses[dwr.ProtoImageDataTablename], nil +} + +func getBatchImageKeys(digests []string) []map[string]types.AttributeValue { + result := []map[string]types.AttributeValue{} + + for _, digest := range digests { + result = append(result, map[string]types.AttributeValue{ + "Digest": &types.AttributeValueMemberS{ + Value: digest, + }, + }) + } + + return result +} diff --git a/pkg/meta/dynamodb/dynamodb_test.go b/pkg/meta/dynamodb/dynamodb_test.go index 4901d8ec12..fe0bb32430 100644 --- a/pkg/meta/dynamodb/dynamodb_test.go +++ b/pkg/meta/dynamodb/dynamodb_test.go @@ -2,6 +2,7 @@ package dynamodb_test import ( "context" + "fmt" "os" "strings" "testing" @@ -19,11 +20,12 @@ import ( "zotregistry.io/zot/pkg/extensions/imagetrust" "zotregistry.io/zot/pkg/log" + "zotregistry.io/zot/pkg/meta" mdynamodb "zotregistry.io/zot/pkg/meta/dynamodb" mTypes "zotregistry.io/zot/pkg/meta/types" reqCtx "zotregistry.io/zot/pkg/requestcontext" - . "zotregistry.io/zot/pkg/test/image-utils" tskip "zotregistry.io/zot/pkg/test/skip" + . "zotregistry.io/zot/pkg/test/image-utils" ) const badTablename = "bad tablename" @@ -1421,3 +1423,86 @@ func setRepoMeta(client *dynamodb.Client, repoMetadataTableName string, repoMeta return err } + +func TestProto(t *testing.T) { + Convey("Proto", t, func() { + dynamoDBDriverParams := mdynamodb.DBDriverParameters{ + Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"), + RepoMetaTablename: "RepoMetadataTable", + ManifestDataTablename: "ManifestDataTable", + IndexDataTablename: "IndexDataTable", + UserDataTablename: "UserDataTable", + APIKeyTablename: "ApiKeyTable", + VersionTablename: "Version", + Region: "us-east-2", + } + + client, err := mdynamodb.GetDynamoClient(dynamoDBDriverParams) + So(err, ShouldBeNil) + + log := log.NewLogger("debug", "") + + metaDB, err := meta.Create("dynamodb", client, dynamoDBDriverParams, log) + So(metaDB, ShouldNotBeNil) + So(err, ShouldBeNil) + + metaDB.ProtoSetRepoMeta("repo", mTypes.RepoMetadata2{ + Name: "repo", + Tags: map[string]mTypes.Descriptor{"tag": {Digest: "d", MediaType: "m"}}, + Statistics: map[string]mTypes.DescriptorStatistics{"d": {DownloadCount: 2}}, + Signatures: map[string]mTypes.ManifestSignatures{"d": {}}, + Referrers: map[string][]mTypes.ReferrerInfo{"d": {{Digest: "d"}}}, + Stars: 20, + }) + + repoMeta, _ := metaDB.ProtoGetRepoMeta("repo") + fmt.Println(repoMeta) + + img1 := CreateRandomImage() + imageData1 := mTypes.ImageData2{ + MediaType: ispec.MediaTypeImageManifest, + Digest: img1.Digest(), + Size: img1.ManifestDescriptor.Size, + Index: nil, + Manifests: []mTypes.ManifestData2{ + { + Size: img1.ManifestDescriptor.Size, + Digest: img1.Digest(), + Manifest: img1.Manifest, + ConfigContent: img1.Config, + }, + }, + } + + img2 := CreateRandomImage() + imageData2 := mTypes.ImageData2{ + MediaType: ispec.MediaTypeImageManifest, + Digest: img2.Digest(), + Size: img2.ManifestDescriptor.Size, + Index: nil, + Manifests: []mTypes.ManifestData2{ + { + Size: img2.ManifestDescriptor.Size, + Digest: img2.Digest(), + Manifest: img2.Manifest, + ConfigContent: img2.Config, + }, + }, + } + + err = metaDB.ProtoSetImageData(imageData1.Digest, imageData1) + So(err, ShouldBeNil) + + err = metaDB.ProtoSetImageData(imageData2.Digest, imageData2) + So(err, ShouldBeNil) + + imgData, err := metaDB.ProtoGetImageData(imageData1.Digest) + So(err, ShouldBeNil) + _ = imgData + + x, _ := metaDB.ProtoFilterImageData(context.Background(), []string{ + imageData1.Digest.String(), imageData2.Digest.String(), + }) + _ = x + }) +} diff --git a/pkg/meta/hooks.go b/pkg/meta/hooks.go index 3817f2c95a..21b3bb9736 100644 --- a/pkg/meta/hooks.go +++ b/pkg/meta/hooks.go @@ -61,6 +61,23 @@ func OnUpdateManifest(repo, reference, mediaType string, digest godigest.Digest, metadataSuccessfullySet = false } } + // Proto + err = metaDB.ProtoAddManifestSignature(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.ProtoUpdateSignaturesValidity(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, @@ -68,6 +85,12 @@ func OnUpdateManifest(repo, reference, mediaType string, digest godigest.Digest, if err != nil { metadataSuccessfullySet = false } + + err = ProtoSetImageMetaFromInput(repo, reference, mediaType, digest, body, + imgStore, metaDB, log) + if err != nil { + metadataSuccessfullySet = false + } } if !metadataSuccessfullySet { @@ -117,6 +140,15 @@ func OnDeleteManifest(repo, reference, mediaType string, digest godigest.Digest, log.Error().Err(err).Msg("metadb: can't check if image is a signature or not") manageRepoMetaSuccessfully = false } + + err = metaDB.ProtoDeleteSignature(repo, signedManifestDigest, mTypes.SignatureMetadata{ + SignatureDigest: digest.String(), + SignatureType: signatureType, + }) + if err != nil { + log.Error().Err(err).Msg("metadb: can't check if image is a signature or not") + manageRepoMetaSuccessfully = false + } } else { err = metaDB.RemoveRepoReference(repo, reference, digest) if err != nil { @@ -131,6 +163,19 @@ func OnDeleteManifest(repo, reference, mediaType string, digest godigest.Digest, manageRepoMetaSuccessfully = false } + err = metaDB.ProtoDeleteRepoTag(repo, reference) + if err != nil { + log.Info().Msg("metadb: restoring image store") + + // restore image store + _, _, err := imgStore.PutImageManifest(repo, reference, mediaType, manifestBlob) + if err != nil { + log.Error().Err(err).Msg("metadb: error while restoring image store, database is not consistent") + } + + manageRepoMetaSuccessfully = false + } + if referredDigest, hasSubject := common.GetReferredSubject(manifestBlob); hasSubject { err := metaDB.DeleteReferrer(repo, referredDigest, digest) if err != nil { diff --git a/pkg/meta/parse.go b/pkg/meta/parse.go index 6613d29b2b..9984d50ec5 100644 --- a/pkg/meta/parse.go +++ b/pkg/meta/parse.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "regexp" "time" godigest "github.com/opencontainers/go-digest" @@ -12,6 +13,7 @@ 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" @@ -84,61 +86,22 @@ func ParseRepo(repo string, metaDB mTypes.MetaDB, storeController storage.StoreC continue } - descriptorBlob, err := getCachedBlob(repo, descriptor, metaDB, imageStore, log) + // TODO take info from RepoDB if it exists already + descriptorBlob, _, _, err := imageStore.GetImageManifest(repo, descriptor.Digest.String()) if err != nil { - log.Error().Err(err).Msg("load-repo: error checking manifestMeta in MetaDB") - - 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") + log.Error().Err(err).Str("repository", repo).Str("digest", descriptor.Digest.String()). + Msg("load-repo: failed to get blob for 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() } - err = SetImageMetaFromInput(repo, reference, descriptor.MediaType, descriptor.Digest, descriptorBlob, + err = ProtoSetImageMetaFromInput(repo, reference, descriptor.MediaType, descriptor.Digest, descriptorBlob, imageStore, metaDB, log) if err != nil { log.Error().Err(err).Str("repository", repo).Str("tag", tag). @@ -154,7 +117,7 @@ func ParseRepo(repo string, metaDB mTypes.MetaDB, storeController storage.StoreC // 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) + repoMeta, err := metaDB.ProtoGetRepoMeta(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") @@ -167,12 +130,12 @@ func resetRepoMeta(repo string, metaDB mTypes.MetaDB, log log.Logger) error { return nil } - return metaDB.SetRepoMeta(repo, mTypes.RepoMetadata{ + return metaDB.ProtoSetRepoMeta(repo, mTypes.RepoMetadata2{ Name: repoMeta.Name, - Tags: map[string]mTypes.Descriptor{}, + Tags: map[string]mTypes.Descriptor{"": {}}, Statistics: repoMeta.Statistics, - Signatures: map[string]mTypes.ManifestSignatures{}, - Referrers: map[string][]mTypes.ReferrerInfo{}, + Signatures: map[string]mTypes.ManifestSignatures{"": {"": {}}}, + Referrers: map[string][]mTypes.ReferrerInfo{"": {}}, Stars: repoMeta.Stars, }) } @@ -436,6 +399,117 @@ func SetImageMetaFromInput(repo, reference, mediaType string, digest godigest.Di return nil } +// 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 ProtoSetImageMetaFromInput(repo, reference, mediaType string, digest godigest.Digest, descriptorBlob []byte, + imageStore storageTypes.ImageStore, metaDB mTypes.MetaDB, log log.Logger, +) error { + imageData := mTypes.ImageData2{} + + switch mediaType { + case ispec.MediaTypeImageManifest: + manifestContent := ispec.Manifest{} + configContent := ispec.Image{} + + err := json.Unmarshal(descriptorBlob, &manifestContent) + if err != nil { + return err + } + + configBlob, err := imageStore.GetBlobContent(repo, manifestContent.Config.Digest) + if err != nil { + return err + } + + err = json.Unmarshal(configBlob, &configContent) + if err != nil { + return err + } + + if isSig, sigType, signedManifestDigest := isSingature(reference, manifestContent); isSig { + layers, err := GetSignatureLayersInfo(repo, reference, digest.String(), sigType, + descriptorBlob, imageStore, log) + if err != nil { + return err + } + + err = metaDB.ProtoAddManifestSignature(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.ProtoUpdateSignaturesValidity(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 + } + + imageData = convert.GetImageManifestData(manifestContent, configContent, int64(len(descriptorBlob)), digest) + case ispec.MediaTypeImageIndex: + indexContent := ispec.Index{} + + err := json.Unmarshal(descriptorBlob, &indexContent) + if err != nil { + return err + } + + imageData = convert.GetImageIndexData(indexContent, int64(len(descriptorBlob)), digest) + } + + err := metaDB.ProtoSetRepoReference(repo, reference, imageData) + if err != nil { + log.Error().Err(err).Msg("metadb: error while putting repo meta") + + return err + } + + return nil +} + +const ( + CosignType = "cosign" + NotationType = "notation" +) + +func isSingature(reference string, manifestContent ispec.Manifest) (bool, string, godigest.Digest) { + manifestArtifactType := zcommon.GetManifestArtifactType(manifestContent) + + // check notation signature + if manifestArtifactType == zcommon.ArtifactTypeNotation && manifestContent.Subject != nil { + return true, NotationType, manifestContent.Subject.Digest + } + + // check cosign + cosignTagRule := regexp.MustCompile(`sha256\-.+\.sig`) + + if tag := reference; cosignTagRule.MatchString(reference) { + prefixLen := len("sha256-") + digestLen := 64 + signedImageManifestDigestEncoded := tag[prefixLen : prefixLen+digestLen] + + signedImageManifestDigest := godigest.NewDigestFromEncoded(godigest.SHA256, + signedImageManifestDigestEncoded) + + return true, CosignType, signedImageManifestDigest + } + + return false, "", "" +} + func GetReferredInfo(descriptorBlob []byte, referrerDigest, mediaType string, ) (godigest.Digest, mTypes.ReferrerInfo, bool, error) { var ( @@ -488,3 +562,9 @@ func GetReferredInfo(descriptorBlob []byte, referrerDigest, mediaType string, return referrerSubject.Digest, referrerInfo, true, nil } + +func ref[T any](input T) *T { + ref := input + + return &ref +} diff --git a/pkg/meta/proto/config.proto b/pkg/meta/proto/config.proto new file mode 100644 index 0000000000..7d9c3f21b2 --- /dev/null +++ b/pkg/meta/proto/config.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; +package v1; + +import "timestamp.proto"; +import "descriptor.proto"; + +// https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/config.go + +message ImageConfig { + string user = 1; + map exposedports = 2; + repeated string env = 3; + repeated string entrypoint = 4; + repeated string cmd = 5; + map volumes = 6; + optional string workingdir = 7; + map labels = 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 ConfigData { + 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; + string Digest = 7; + int64 Size = 8; +} + +message EmptyMessage{} diff --git a/pkg/meta/proto/descriptor.proto b/pkg/meta/proto/descriptor.proto new file mode 100644 index 0000000000..6a4b5757eb --- /dev/null +++ b/pkg/meta/proto/descriptor.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +package 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; + map annotations = 5; + bytes data = 6; + optional Platform platform = 7; + optional string artifactType = 8; +} + +message Platform { + string Os = 1; + string Arch = 2; +} diff --git a/pkg/meta/proto/imageData.proto b/pkg/meta/proto/imageData.proto new file mode 100644 index 0000000000..515194a469 --- /dev/null +++ b/pkg/meta/proto/imageData.proto @@ -0,0 +1,121 @@ +syntax = "proto3"; +package v1; + +import "versioned.proto"; +import "config.proto"; +import "timestamp.proto"; +import "descriptor.proto"; + +message TagDescriptor { + string MediaType = 1; + string Digest = 2; +} + +message ImageData { + Versioned Versioned = 1; + string MediaType = 2; + string ArtifacType = 3; + repeated ManifestData Manifests = 4; + optional Descriptor Subject = 5; + map Annotations = 6; + int64 Size = 7; + string Digest = 8; + + optional string Repo = 9; + optional string Tag = 10; +} + +message ManifestData { + Versioned versioned = 1; + string Digest = 2; + optional string MediaType = 4; + optional string ArtifactType = 5; + repeated Descriptor Layers = 6; + optional Descriptor Subject = 7; + map Annotations = 8; + + int64 Size = 9; + ConfigData Config = 10; +} + +message RepoLastUpdatedImage { + optional google.protobuf.Timestamp LastUpdated = 1; + string MediaType = 2; + string Digest = 3; + string Tag = 4; +} + +message ProtoRepoMeta { + string Name = 1; + map Tags = 2; + + map Statistics = 3; + map Signatures = 4; + map Referrers = 5; + + bool IsStarred = 6; + bool IsBookmarked = 7; + int32 Rank = 8; + + int32 Stars = 9; + + int32 Size = 10; + repeated string Vendors = 11; + repeated Platform Platforms = 12; + optional RepoLastUpdatedImage LastUpdatedImage = 13; +} + +message RepoBlobs { + string Name = 1; + map 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 Platform Platforms = 3; + repeated string SubBlobs = 4; + + optional google.protobuf.Timestamp LastUpdated = 5; +} + +message DescriptorStatistics { + int32 DownloadCount = 1; +} + +message ReferrersInfo { + repeated ReferrerInfo list = 1; +} + +message ReferrerInfo { + string Digest = 1; + string MediaType = 2; + string ArtifactType = 3; + int64 Size = 4; + + map Annotations = 5; +} + +message ManifestSignatures { + map 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; +} \ No newline at end of file diff --git a/pkg/meta/proto/index.proto b/pkg/meta/proto/index.proto new file mode 100644 index 0000000000..281cb84a5f --- /dev/null +++ b/pkg/meta/proto/index.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package v1; + +import "descriptor.proto"; +import "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 annotations = 6; +} diff --git a/pkg/meta/proto/manifest.proto b/pkg/meta/proto/manifest.proto new file mode 100644 index 0000000000..6d0e835c22 --- /dev/null +++ b/pkg/meta/proto/manifest.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package v1; + +import "descriptor.proto"; +import "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 annotations = 7; +} diff --git a/pkg/meta/proto/timestamp.proto b/pkg/meta/proto/timestamp.proto new file mode 100644 index 0000000000..fd0bc07dc3 --- /dev/null +++ b/pkg/meta/proto/timestamp.proto @@ -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; +} diff --git a/pkg/meta/proto/versioned.proto b/pkg/meta/proto/versioned.proto new file mode 100644 index 0000000000..f9c82bca84 --- /dev/null +++ b/pkg/meta/proto/versioned.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; +package v1; + +// https://github.com/opencontainers/image-spec/blob/main/specs-go/versioned.go + +message Versioned { + int32 schemaversion = 1; +} diff --git a/pkg/meta/proto_go/config.pb.go b/pkg/meta/proto_go/config.pb.go new file mode 100644 index 0000000000..e95795392c --- /dev/null +++ b/pkg/meta/proto_go/config.pb.go @@ -0,0 +1,644 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.15.8 +// source: config.proto + +package proto_go + +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 ImageConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Exposedports map[string]*EmptyMessage `protobuf:"bytes,2,rep,name=exposedports,proto3" json:"exposedports,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Env []string `protobuf:"bytes,3,rep,name=env,proto3" json:"env,omitempty"` + Entrypoint []string `protobuf:"bytes,4,rep,name=entrypoint,proto3" json:"entrypoint,omitempty"` + Cmd []string `protobuf:"bytes,5,rep,name=cmd,proto3" json:"cmd,omitempty"` + Volumes map[string]*EmptyMessage `protobuf:"bytes,6,rep,name=volumes,proto3" json:"volumes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Workingdir *string `protobuf:"bytes,7,opt,name=workingdir,proto3,oneof" json:"workingdir,omitempty"` + Labels map[string]string `protobuf:"bytes,8,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + 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_config_proto_msgTypes[0] + 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_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 ImageConfig.ProtoReflect.Descriptor instead. +func (*ImageConfig) Descriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{0} +} + +func (x *ImageConfig) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +func (x *ImageConfig) GetExposedports() map[string]*EmptyMessage { + if x != nil { + return x.Exposedports + } + return nil +} + +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) GetVolumes() map[string]*EmptyMessage { + if x != nil { + return x.Volumes + } + return nil +} + +func (x *ImageConfig) GetWorkingdir() string { + if x != nil && x.Workingdir != nil { + return *x.Workingdir + } + return "" +} + +func (x *ImageConfig) GetLabels() map[string]string { + if x != nil { + return x.Labels + } + return nil +} + +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_config_proto_msgTypes[1] + 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_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 RootFS.ProtoReflect.Descriptor instead. +func (*RootFS) Descriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{1} +} + +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_config_proto_msgTypes[2] + 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_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 History.ProtoReflect.Descriptor instead. +func (*History) Descriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{2} +} + +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 ConfigData 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"` + Digest string `protobuf:"bytes,7,opt,name=Digest,proto3" json:"Digest,omitempty"` + Size int64 `protobuf:"varint,8,opt,name=Size,proto3" json:"Size,omitempty"` +} + +func (x *ConfigData) Reset() { + *x = ConfigData{} + if protoimpl.UnsafeEnabled { + mi := &file_config_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ConfigData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConfigData) ProtoMessage() {} + +func (x *ConfigData) ProtoReflect() protoreflect.Message { + mi := &file_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 ConfigData.ProtoReflect.Descriptor instead. +func (*ConfigData) Descriptor() ([]byte, []int) { + return file_config_proto_rawDescGZIP(), []int{3} +} + +func (x *ConfigData) GetCreated() *timestamppb.Timestamp { + if x != nil { + return x.Created + } + return nil +} + +func (x *ConfigData) GetAuthor() string { + if x != nil && x.Author != nil { + return *x.Author + } + return "" +} + +func (x *ConfigData) GetPlatform() *Platform { + if x != nil { + return x.Platform + } + return nil +} + +func (x *ConfigData) GetConfig() *ImageConfig { + if x != nil { + return x.Config + } + return nil +} + +func (x *ConfigData) GetRootfs() *RootFS { + if x != nil { + return x.Rootfs + } + return nil +} + +func (x *ConfigData) GetHistory() []*History { + if x != nil { + return x.History + } + return nil +} + +func (x *ConfigData) GetDigest() string { + if x != nil { + return x.Digest + } + return "" +} + +func (x *ConfigData) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +type EmptyMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *EmptyMessage) Reset() { + *x = EmptyMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_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_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_config_proto_rawDescGZIP(), []int{4} +} + +var File_config_proto protoreflect.FileDescriptor + +var file_config_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, + 0x76, 0x31, 0x1a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xff, 0x04, 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x0c, 0x65, 0x78, 0x70, + 0x6f, 0x73, 0x65, 0x64, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x65, + 0x6e, 0x76, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x64, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x03, 0x63, 0x6d, 0x64, 0x12, 0x36, 0x0a, 0x07, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 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, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0a, + 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x64, 0x69, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x64, 0x69, 0x72, 0x88, 0x01, + 0x01, 0x12, 0x33, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 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, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x23, 0x0a, 0x0a, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0a, 0x73, 0x74, + 0x6f, 0x70, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x0b, 0x61, + 0x72, 0x67, 0x73, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0b, 0x61, 0x72, 0x67, 0x73, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x64, 0x1a, 0x51, 0x0a, + 0x11, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x70, 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, 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 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, 0x4c, 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, 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 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, 0x77, 0x6f, + 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x64, 0x69, 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x74, 0x6f, + 0x70, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x22, 0x36, 0x0a, 0x06, 0x52, 0x6f, 0x6f, 0x74, 0x46, + 0x53, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x69, 0x66, 0x66, 0x69, 0x64, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x69, 0x66, 0x66, 0x69, 0x64, 0x73, 0x22, + 0x88, 0x02, 0x0a, 0x07, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x39, 0x0a, 0x07, 0x63, + 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, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x62, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x62, 0x79, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x06, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x23, 0x0a, 0x0a, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x48, 0x04, 0x52, 0x0a, 0x65, 0x6d, 0x70, + 0x74, 0x79, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x62, 0x79, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x42, + 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, + 0x65, 0x6d, 0x70, 0x74, 0x79, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, 0xe5, 0x02, 0x0a, 0x0a, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x07, 0x63, 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, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x88, 0x01, + 0x01, 0x12, 0x28, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x2c, 0x0a, 0x06, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x31, + 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x02, 0x52, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x06, 0x72, 0x6f, 0x6f, + 0x74, 0x66, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x6f, 0x6f, 0x74, 0x46, 0x53, 0x48, 0x03, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x88, + 0x01, 0x01, 0x12, 0x25, 0x0a, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x52, 0x07, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x04, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x42, 0x09, 0x0a, 0x07, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x72, 0x6f, 0x6f, 0x74, + 0x66, 0x73, 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_config_proto_rawDescOnce sync.Once + file_config_proto_rawDescData = file_config_proto_rawDesc +) + +func file_config_proto_rawDescGZIP() []byte { + file_config_proto_rawDescOnce.Do(func() { + file_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_config_proto_rawDescData) + }) + return file_config_proto_rawDescData +} + +var file_config_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_config_proto_goTypes = []interface{}{ + (*ImageConfig)(nil), // 0: v1.ImageConfig + (*RootFS)(nil), // 1: v1.RootFS + (*History)(nil), // 2: v1.History + (*ConfigData)(nil), // 3: v1.ConfigData + (*EmptyMessage)(nil), // 4: v1.EmptyMessage + nil, // 5: v1.ImageConfig.ExposedportsEntry + nil, // 6: v1.ImageConfig.VolumesEntry + nil, // 7: v1.ImageConfig.LabelsEntry + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*Platform)(nil), // 9: v1.Platform +} +var file_config_proto_depIdxs = []int32{ + 5, // 0: v1.ImageConfig.exposedports:type_name -> v1.ImageConfig.ExposedportsEntry + 6, // 1: v1.ImageConfig.volumes:type_name -> v1.ImageConfig.VolumesEntry + 7, // 2: v1.ImageConfig.labels:type_name -> v1.ImageConfig.LabelsEntry + 8, // 3: v1.History.created:type_name -> google.protobuf.Timestamp + 8, // 4: v1.ConfigData.created:type_name -> google.protobuf.Timestamp + 9, // 5: v1.ConfigData.platform:type_name -> v1.Platform + 0, // 6: v1.ConfigData.config:type_name -> v1.ImageConfig + 1, // 7: v1.ConfigData.rootfs:type_name -> v1.RootFS + 2, // 8: v1.ConfigData.history:type_name -> v1.History + 4, // 9: v1.ImageConfig.ExposedportsEntry.value:type_name -> v1.EmptyMessage + 4, // 10: v1.ImageConfig.VolumesEntry.value:type_name -> 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_config_proto_init() } +func file_config_proto_init() { + if File_config_proto != nil { + return + } + file_descriptor_proto_init() + if !protoimpl.UnsafeEnabled { + file_config_proto_msgTypes[0].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_config_proto_msgTypes[1].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_config_proto_msgTypes[2].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_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ConfigData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_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_config_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_config_proto_msgTypes[2].OneofWrappers = []interface{}{} + file_config_proto_msgTypes[3].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_config_proto_rawDesc, + NumEnums: 0, + NumMessages: 8, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_config_proto_goTypes, + DependencyIndexes: file_config_proto_depIdxs, + MessageInfos: file_config_proto_msgTypes, + }.Build() + File_config_proto = out.File + file_config_proto_rawDesc = nil + file_config_proto_goTypes = nil + file_config_proto_depIdxs = nil +} diff --git a/pkg/meta/proto_go/descriptor.pb.go b/pkg/meta/proto_go/descriptor.pb.go new file mode 100644 index 0000000000..a7c056b8b9 --- /dev/null +++ b/pkg/meta/proto_go/descriptor.pb.go @@ -0,0 +1,293 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.15.8 +// source: descriptor.proto + +package proto_go + +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"` + Annotations map[string]string `protobuf:"bytes,5,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` + Platform *Platform `protobuf:"bytes,7,opt,name=platform,proto3,oneof" json:"platform,omitempty"` + ArtifactType *string `protobuf:"bytes,8,opt,name=artifactType,proto3,oneof" json:"artifactType,omitempty"` +} + +func (x *Descriptor) Reset() { + *x = Descriptor{} + if protoimpl.UnsafeEnabled { + mi := &file_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_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_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) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + 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 "" +} + +type Platform struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Os string `protobuf:"bytes,1,opt,name=Os,proto3" json:"Os,omitempty"` + Arch string `protobuf:"bytes,2,opt,name=Arch,proto3" json:"Arch,omitempty"` +} + +func (x *Platform) Reset() { + *x = Platform{} + if protoimpl.UnsafeEnabled { + mi := &file_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_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_descriptor_proto_rawDescGZIP(), []int{1} +} + +func (x *Platform) GetOs() string { + if x != nil { + return x.Os + } + return "" +} + +func (x *Platform) GetArch() string { + if x != nil { + return x.Arch + } + return "" +} + +var File_descriptor_proto protoreflect.FileDescriptor + +var file_descriptor_proto_rawDesc = []byte{ + 0x0a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0xf7, 0x02, 0x0a, 0x0a, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x75, + 0x72, 0x6c, 0x73, 0x12, 0x41, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 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, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x48, 0x00, 0x52, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x61, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x01, 0x52, 0x0c, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x88, + 0x01, 0x01, 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, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x42, + 0x0f, 0x0a, 0x0d, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x22, 0x2e, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x0e, 0x0a, 0x02, + 0x4f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x4f, 0x73, 0x12, 0x12, 0x0a, 0x04, + 0x41, 0x72, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x63, 0x68, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_descriptor_proto_rawDescOnce sync.Once + file_descriptor_proto_rawDescData = file_descriptor_proto_rawDesc +) + +func file_descriptor_proto_rawDescGZIP() []byte { + file_descriptor_proto_rawDescOnce.Do(func() { + file_descriptor_proto_rawDescData = protoimpl.X.CompressGZIP(file_descriptor_proto_rawDescData) + }) + return file_descriptor_proto_rawDescData +} + +var file_descriptor_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_descriptor_proto_goTypes = []interface{}{ + (*Descriptor)(nil), // 0: v1.Descriptor + (*Platform)(nil), // 1: v1.Platform + nil, // 2: v1.Descriptor.AnnotationsEntry +} +var file_descriptor_proto_depIdxs = []int32{ + 2, // 0: v1.Descriptor.annotations:type_name -> v1.Descriptor.AnnotationsEntry + 1, // 1: v1.Descriptor.platform:type_name -> v1.Platform + 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_descriptor_proto_init() } +func file_descriptor_proto_init() { + if File_descriptor_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_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_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_descriptor_proto_msgTypes[0].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_descriptor_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_descriptor_proto_goTypes, + DependencyIndexes: file_descriptor_proto_depIdxs, + MessageInfos: file_descriptor_proto_msgTypes, + }.Build() + File_descriptor_proto = out.File + file_descriptor_proto_rawDesc = nil + file_descriptor_proto_goTypes = nil + file_descriptor_proto_depIdxs = nil +} diff --git a/pkg/meta/proto_go/imageData.pb.go b/pkg/meta/proto_go/imageData.pb.go new file mode 100644 index 0000000000..f8d2afd3af --- /dev/null +++ b/pkg/meta/proto_go/imageData.pb.go @@ -0,0 +1,1566 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.15.8 +// source: imageData.proto + +package proto_go + +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 TagDescriptor 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"` +} + +func (x *TagDescriptor) Reset() { + *x = TagDescriptor{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TagDescriptor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TagDescriptor) ProtoMessage() {} + +func (x *TagDescriptor) ProtoReflect() protoreflect.Message { + mi := &file_imageData_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 TagDescriptor.ProtoReflect.Descriptor instead. +func (*TagDescriptor) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{0} +} + +func (x *TagDescriptor) GetMediaType() string { + if x != nil { + return x.MediaType + } + return "" +} + +func (x *TagDescriptor) GetDigest() string { + if x != nil { + return x.Digest + } + return "" +} + +type ImageData 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" json:"MediaType,omitempty"` + ArtifacType string `protobuf:"bytes,3,opt,name=ArtifacType,proto3" json:"ArtifacType,omitempty"` + Manifests []*ManifestData `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"` + Size int64 `protobuf:"varint,7,opt,name=Size,proto3" json:"Size,omitempty"` + Digest string `protobuf:"bytes,8,opt,name=Digest,proto3" json:"Digest,omitempty"` + Repo *string `protobuf:"bytes,9,opt,name=Repo,proto3,oneof" json:"Repo,omitempty"` + Tag *string `protobuf:"bytes,10,opt,name=Tag,proto3,oneof" json:"Tag,omitempty"` +} + +func (x *ImageData) Reset() { + *x = ImageData{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ImageData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImageData) ProtoMessage() {} + +func (x *ImageData) ProtoReflect() protoreflect.Message { + mi := &file_imageData_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 ImageData.ProtoReflect.Descriptor instead. +func (*ImageData) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{1} +} + +func (x *ImageData) GetVersioned() *Versioned { + if x != nil { + return x.Versioned + } + return nil +} + +func (x *ImageData) GetMediaType() string { + if x != nil { + return x.MediaType + } + return "" +} + +func (x *ImageData) GetArtifacType() string { + if x != nil { + return x.ArtifacType + } + return "" +} + +func (x *ImageData) GetManifests() []*ManifestData { + if x != nil { + return x.Manifests + } + return nil +} + +func (x *ImageData) GetSubject() *Descriptor { + if x != nil { + return x.Subject + } + return nil +} + +func (x *ImageData) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +func (x *ImageData) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *ImageData) GetDigest() string { + if x != nil { + return x.Digest + } + return "" +} + +func (x *ImageData) GetRepo() string { + if x != nil && x.Repo != nil { + return *x.Repo + } + return "" +} + +func (x *ImageData) GetTag() string { + if x != nil && x.Tag != nil { + return *x.Tag + } + return "" +} + +type ManifestData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Versioned *Versioned `protobuf:"bytes,1,opt,name=versioned,proto3" json:"versioned,omitempty"` + Digest string `protobuf:"bytes,2,opt,name=Digest,proto3" json:"Digest,omitempty"` + MediaType *string `protobuf:"bytes,4,opt,name=MediaType,proto3,oneof" json:"MediaType,omitempty"` + ArtifactType *string `protobuf:"bytes,5,opt,name=ArtifactType,proto3,oneof" json:"ArtifactType,omitempty"` + Layers []*Descriptor `protobuf:"bytes,6,rep,name=Layers,proto3" json:"Layers,omitempty"` + Subject *Descriptor `protobuf:"bytes,7,opt,name=Subject,proto3,oneof" json:"Subject,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"` + Size int64 `protobuf:"varint,9,opt,name=Size,proto3" json:"Size,omitempty"` + Config *ConfigData `protobuf:"bytes,10,opt,name=Config,proto3" json:"Config,omitempty"` +} + +func (x *ManifestData) Reset() { + *x = ManifestData{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ManifestData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ManifestData) ProtoMessage() {} + +func (x *ManifestData) ProtoReflect() protoreflect.Message { + mi := &file_imageData_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 ManifestData.ProtoReflect.Descriptor instead. +func (*ManifestData) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{2} +} + +func (x *ManifestData) GetVersioned() *Versioned { + if x != nil { + return x.Versioned + } + return nil +} + +func (x *ManifestData) GetDigest() string { + if x != nil { + return x.Digest + } + return "" +} + +func (x *ManifestData) GetMediaType() string { + if x != nil && x.MediaType != nil { + return *x.MediaType + } + return "" +} + +func (x *ManifestData) GetArtifactType() string { + if x != nil && x.ArtifactType != nil { + return *x.ArtifactType + } + return "" +} + +func (x *ManifestData) GetLayers() []*Descriptor { + if x != nil { + return x.Layers + } + return nil +} + +func (x *ManifestData) GetSubject() *Descriptor { + if x != nil { + return x.Subject + } + return nil +} + +func (x *ManifestData) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +func (x *ManifestData) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *ManifestData) GetConfig() *ConfigData { + if x != nil { + return x.Config + } + return nil +} + +type RepoLastUpdatedImage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LastUpdated *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=LastUpdated,proto3,oneof" json:"LastUpdated,omitempty"` + MediaType string `protobuf:"bytes,2,opt,name=MediaType,proto3" json:"MediaType,omitempty"` + Digest string `protobuf:"bytes,3,opt,name=Digest,proto3" json:"Digest,omitempty"` + Tag string `protobuf:"bytes,4,opt,name=Tag,proto3" json:"Tag,omitempty"` +} + +func (x *RepoLastUpdatedImage) Reset() { + *x = RepoLastUpdatedImage{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RepoLastUpdatedImage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RepoLastUpdatedImage) ProtoMessage() {} + +func (x *RepoLastUpdatedImage) ProtoReflect() protoreflect.Message { + mi := &file_imageData_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 RepoLastUpdatedImage.ProtoReflect.Descriptor instead. +func (*RepoLastUpdatedImage) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{3} +} + +func (x *RepoLastUpdatedImage) GetLastUpdated() *timestamppb.Timestamp { + if x != nil { + return x.LastUpdated + } + return nil +} + +func (x *RepoLastUpdatedImage) GetMediaType() string { + if x != nil { + return x.MediaType + } + return "" +} + +func (x *RepoLastUpdatedImage) GetDigest() string { + if x != nil { + return x.Digest + } + return "" +} + +func (x *RepoLastUpdatedImage) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +type ProtoRepoMeta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` + Tags map[string]*TagDescriptor `protobuf:"bytes,2,rep,name=Tags,proto3" json:"Tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Statistics map[string]*DescriptorStatistics `protobuf:"bytes,3,rep,name=Statistics,proto3" json:"Statistics,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Signatures map[string]*ManifestSignatures `protobuf:"bytes,4,rep,name=Signatures,proto3" json:"Signatures,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Referrers map[string]*ReferrersInfo `protobuf:"bytes,5,rep,name=Referrers,proto3" json:"Referrers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + IsStarred bool `protobuf:"varint,6,opt,name=IsStarred,proto3" json:"IsStarred,omitempty"` + IsBookmarked bool `protobuf:"varint,7,opt,name=IsBookmarked,proto3" json:"IsBookmarked,omitempty"` + Rank int32 `protobuf:"varint,8,opt,name=Rank,proto3" json:"Rank,omitempty"` + Stars int32 `protobuf:"varint,9,opt,name=Stars,proto3" json:"Stars,omitempty"` + Size int32 `protobuf:"varint,10,opt,name=Size,proto3" json:"Size,omitempty"` + Vendors []string `protobuf:"bytes,11,rep,name=Vendors,proto3" json:"Vendors,omitempty"` + Platforms []*Platform `protobuf:"bytes,12,rep,name=Platforms,proto3" json:"Platforms,omitempty"` + LastUpdatedImage *RepoLastUpdatedImage `protobuf:"bytes,13,opt,name=LastUpdatedImage,proto3,oneof" json:"LastUpdatedImage,omitempty"` +} + +func (x *ProtoRepoMeta) Reset() { + *x = ProtoRepoMeta{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProtoRepoMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoRepoMeta) ProtoMessage() {} + +func (x *ProtoRepoMeta) ProtoReflect() protoreflect.Message { + mi := &file_imageData_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 ProtoRepoMeta.ProtoReflect.Descriptor instead. +func (*ProtoRepoMeta) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{4} +} + +func (x *ProtoRepoMeta) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ProtoRepoMeta) GetTags() map[string]*TagDescriptor { + if x != nil { + return x.Tags + } + return nil +} + +func (x *ProtoRepoMeta) GetStatistics() map[string]*DescriptorStatistics { + if x != nil { + return x.Statistics + } + return nil +} + +func (x *ProtoRepoMeta) GetSignatures() map[string]*ManifestSignatures { + if x != nil { + return x.Signatures + } + return nil +} + +func (x *ProtoRepoMeta) GetReferrers() map[string]*ReferrersInfo { + if x != nil { + return x.Referrers + } + return nil +} + +func (x *ProtoRepoMeta) GetIsStarred() bool { + if x != nil { + return x.IsStarred + } + return false +} + +func (x *ProtoRepoMeta) GetIsBookmarked() bool { + if x != nil { + return x.IsBookmarked + } + return false +} + +func (x *ProtoRepoMeta) GetRank() int32 { + if x != nil { + return x.Rank + } + return 0 +} + +func (x *ProtoRepoMeta) GetStars() int32 { + if x != nil { + return x.Stars + } + return 0 +} + +func (x *ProtoRepoMeta) GetSize() int32 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *ProtoRepoMeta) GetVendors() []string { + if x != nil { + return x.Vendors + } + return nil +} + +func (x *ProtoRepoMeta) GetPlatforms() []*Platform { + if x != nil { + return x.Platforms + } + return nil +} + +func (x *ProtoRepoMeta) GetLastUpdatedImage() *RepoLastUpdatedImage { + if x != nil { + return x.LastUpdatedImage + } + return nil +} + +type RepoBlobs struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` + Blobs map[string]*BlobInfo `protobuf:"bytes,2,rep,name=Blobs,proto3" json:"Blobs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *RepoBlobs) Reset() { + *x = RepoBlobs{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RepoBlobs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RepoBlobs) ProtoMessage() {} + +func (x *RepoBlobs) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[5] + 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 RepoBlobs.ProtoReflect.Descriptor instead. +func (*RepoBlobs) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{5} +} + +func (x *RepoBlobs) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RepoBlobs) GetBlobs() map[string]*BlobInfo { + if x != nil { + return x.Blobs + } + return nil +} + +// for example this is a manifest and it has a config, and layers +// or index and has manifests +type BlobInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Size int64 `protobuf:"varint,1,opt,name=Size,proto3" json:"Size,omitempty"` + Vendors []string `protobuf:"bytes,2,rep,name=Vendors,proto3" json:"Vendors,omitempty"` + Platforms []*Platform `protobuf:"bytes,3,rep,name=Platforms,proto3" json:"Platforms,omitempty"` + SubBlobs []string `protobuf:"bytes,4,rep,name=SubBlobs,proto3" json:"SubBlobs,omitempty"` + LastUpdated *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=LastUpdated,proto3,oneof" json:"LastUpdated,omitempty"` +} + +func (x *BlobInfo) Reset() { + *x = BlobInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlobInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlobInfo) ProtoMessage() {} + +func (x *BlobInfo) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[6] + 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 BlobInfo.ProtoReflect.Descriptor instead. +func (*BlobInfo) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{6} +} + +func (x *BlobInfo) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *BlobInfo) GetVendors() []string { + if x != nil { + return x.Vendors + } + return nil +} + +func (x *BlobInfo) GetPlatforms() []*Platform { + if x != nil { + return x.Platforms + } + return nil +} + +func (x *BlobInfo) GetSubBlobs() []string { + if x != nil { + return x.SubBlobs + } + return nil +} + +func (x *BlobInfo) GetLastUpdated() *timestamppb.Timestamp { + if x != nil { + return x.LastUpdated + } + return nil +} + +type DescriptorStatistics struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DownloadCount int32 `protobuf:"varint,1,opt,name=DownloadCount,proto3" json:"DownloadCount,omitempty"` +} + +func (x *DescriptorStatistics) Reset() { + *x = DescriptorStatistics{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DescriptorStatistics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DescriptorStatistics) ProtoMessage() {} + +func (x *DescriptorStatistics) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[7] + 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 DescriptorStatistics.ProtoReflect.Descriptor instead. +func (*DescriptorStatistics) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{7} +} + +func (x *DescriptorStatistics) GetDownloadCount() int32 { + if x != nil { + return x.DownloadCount + } + return 0 +} + +type ReferrersInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + List []*ReferrerInfo `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` +} + +func (x *ReferrersInfo) Reset() { + *x = ReferrersInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReferrersInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReferrersInfo) ProtoMessage() {} + +func (x *ReferrersInfo) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[8] + 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 ReferrersInfo.ProtoReflect.Descriptor instead. +func (*ReferrersInfo) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{8} +} + +func (x *ReferrersInfo) GetList() []*ReferrerInfo { + if x != nil { + return x.List + } + return nil +} + +type ReferrerInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Digest string `protobuf:"bytes,1,opt,name=Digest,proto3" json:"Digest,omitempty"` + MediaType string `protobuf:"bytes,2,opt,name=MediaType,proto3" json:"MediaType,omitempty"` + ArtifactType string `protobuf:"bytes,3,opt,name=ArtifactType,proto3" json:"ArtifactType,omitempty"` + Size int64 `protobuf:"varint,4,opt,name=Size,proto3" json:"Size,omitempty"` + Annotations map[string]string `protobuf:"bytes,5,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 *ReferrerInfo) Reset() { + *x = ReferrerInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReferrerInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReferrerInfo) ProtoMessage() {} + +func (x *ReferrerInfo) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[9] + 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 ReferrerInfo.ProtoReflect.Descriptor instead. +func (*ReferrerInfo) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{9} +} + +func (x *ReferrerInfo) GetDigest() string { + if x != nil { + return x.Digest + } + return "" +} + +func (x *ReferrerInfo) GetMediaType() string { + if x != nil { + return x.MediaType + } + return "" +} + +func (x *ReferrerInfo) GetArtifactType() string { + if x != nil { + return x.ArtifactType + } + return "" +} + +func (x *ReferrerInfo) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *ReferrerInfo) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +type ManifestSignatures struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Map map[string]*SignaturesInfo `protobuf:"bytes,1,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *ManifestSignatures) Reset() { + *x = ManifestSignatures{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ManifestSignatures) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ManifestSignatures) ProtoMessage() {} + +func (x *ManifestSignatures) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[10] + 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 ManifestSignatures.ProtoReflect.Descriptor instead. +func (*ManifestSignatures) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{10} +} + +func (x *ManifestSignatures) GetMap() map[string]*SignaturesInfo { + if x != nil { + return x.Map + } + return nil +} + +type SignaturesInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + List []*SignatureInfo `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` +} + +func (x *SignaturesInfo) Reset() { + *x = SignaturesInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignaturesInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignaturesInfo) ProtoMessage() {} + +func (x *SignaturesInfo) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[11] + 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 SignaturesInfo.ProtoReflect.Descriptor instead. +func (*SignaturesInfo) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{11} +} + +func (x *SignaturesInfo) GetList() []*SignatureInfo { + if x != nil { + return x.List + } + return nil +} + +type SignatureInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SignatureManifestDigest string `protobuf:"bytes,1,opt,name=SignatureManifestDigest,proto3" json:"SignatureManifestDigest,omitempty"` + LayersInfo []*LayersInfo `protobuf:"bytes,2,rep,name=LayersInfo,proto3" json:"LayersInfo,omitempty"` +} + +func (x *SignatureInfo) Reset() { + *x = SignatureInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignatureInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignatureInfo) ProtoMessage() {} + +func (x *SignatureInfo) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[12] + 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 SignatureInfo.ProtoReflect.Descriptor instead. +func (*SignatureInfo) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{12} +} + +func (x *SignatureInfo) GetSignatureManifestDigest() string { + if x != nil { + return x.SignatureManifestDigest + } + return "" +} + +func (x *SignatureInfo) GetLayersInfo() []*LayersInfo { + if x != nil { + return x.LayersInfo + } + return nil +} + +type LayersInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LayerDigest string `protobuf:"bytes,1,opt,name=LayerDigest,proto3" json:"LayerDigest,omitempty"` + LayerContent []byte `protobuf:"bytes,2,opt,name=LayerContent,proto3" json:"LayerContent,omitempty"` + SignatureKey string `protobuf:"bytes,3,opt,name=SignatureKey,proto3" json:"SignatureKey,omitempty"` + Signer string `protobuf:"bytes,4,opt,name=Signer,proto3" json:"Signer,omitempty"` + Date *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=Date,proto3" json:"Date,omitempty"` +} + +func (x *LayersInfo) Reset() { + *x = LayersInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_imageData_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LayersInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LayersInfo) ProtoMessage() {} + +func (x *LayersInfo) ProtoReflect() protoreflect.Message { + mi := &file_imageData_proto_msgTypes[13] + 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 LayersInfo.ProtoReflect.Descriptor instead. +func (*LayersInfo) Descriptor() ([]byte, []int) { + return file_imageData_proto_rawDescGZIP(), []int{13} +} + +func (x *LayersInfo) GetLayerDigest() string { + if x != nil { + return x.LayerDigest + } + return "" +} + +func (x *LayersInfo) GetLayerContent() []byte { + if x != nil { + return x.LayerContent + } + return nil +} + +func (x *LayersInfo) GetSignatureKey() string { + if x != nil { + return x.SignatureKey + } + return "" +} + +func (x *LayersInfo) GetSigner() string { + if x != nil { + return x.Signer + } + return "" +} + +func (x *LayersInfo) GetDate() *timestamppb.Timestamp { + if x != nil { + return x.Date + } + return nil +} + +var File_imageData_proto protoreflect.FileDescriptor + +var file_imageData_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x02, 0x76, 0x31, 0x1a, 0x0f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x45, 0x0a, 0x0d, 0x54, 0x61, 0x67, 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, 0x22, 0xd2, + 0x03, 0x0a, 0x09, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x09, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x09, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x65, 0x64, + 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4d, 0x65, + 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x41, 0x72, 0x74, 0x69, 0x66, + 0x61, 0x63, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x41, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x09, 0x4d, 0x61, 0x6e, + 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, + 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x09, + 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x48, 0x00, 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, + 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 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, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x69, + 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x52, 0x65, 0x70, 0x6f, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, 0x52, 0x65, 0x70, 0x6f, 0x88, 0x01, 0x01, 0x12, + 0x15, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x03, + 0x54, 0x61, 0x67, 0x88, 0x01, 0x01, 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, 0x0a, 0x0a, 0x08, 0x5f, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x52, 0x65, 0x70, 0x6f, 0x42, 0x06, 0x0a, 0x04, 0x5f, + 0x54, 0x61, 0x67, 0x22, 0xe2, 0x03, 0x0a, 0x0c, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 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, 0x21, 0x0a, 0x09, 0x4d, 0x65, 0x64, + 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, 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, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x01, 0x52, 0x0c, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x06, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, + 0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, + 0x2e, 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, 0x08, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x44, + 0x61, 0x74, 0x61, 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, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x44, 0x61, 0x74, 0x61, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, 0x22, 0xb1, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x70, + 0x6f, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x12, 0x41, 0x0a, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 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, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 0x88, 0x01, 0x01, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, + 0x65, 0x18, 0x02, 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, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x54, 0x61, + 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x54, 0x61, 0x67, 0x42, 0x0e, 0x0a, 0x0c, + 0x5f, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, 0x8d, 0x07, 0x0a, + 0x0d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x12, + 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x54, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x70, 0x6f, 0x4d, + 0x65, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x54, + 0x61, 0x67, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x65, 0x74, 0x61, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x65, 0x74, 0x61, 0x2e, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x09, 0x52, 0x65, 0x66, + 0x65, 0x72, 0x72, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x70, 0x6f, 0x4d, 0x65, 0x74, 0x61, 0x2e, + 0x52, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, + 0x52, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x73, 0x53, + 0x74, 0x61, 0x72, 0x72, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x49, 0x73, + 0x53, 0x74, 0x61, 0x72, 0x72, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x49, 0x73, 0x42, 0x6f, 0x6f, + 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x49, + 0x73, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x52, + 0x61, 0x6e, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x52, 0x61, 0x6e, 0x6b, 0x12, + 0x14, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x72, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, + 0x53, 0x74, 0x61, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x6e, + 0x64, 0x6f, 0x72, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x09, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, + 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x09, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x12, + 0x49, 0x0a, 0x10, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x70, 0x6f, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x10, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x1a, 0x4a, 0x0a, 0x09, 0x54, 0x61, + 0x67, 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, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, + 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x57, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 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, 0x2e, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, + 0x55, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 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, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, + 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4f, 0x0a, 0x0e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x72, + 0x65, 0x72, 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, 0x27, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x4c, 0x61, 0x73, 0x74, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x97, 0x01, 0x0a, + 0x09, 0x52, 0x65, 0x70, 0x6f, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, + 0x0a, 0x05, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x2e, 0x42, 0x6c, 0x6f, + 0x62, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x1a, 0x46, + 0x0a, 0x0a, 0x42, 0x6c, 0x6f, 0x62, 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, 0x22, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, + 0x76, 0x31, 0x2e, 0x42, 0x6c, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd3, 0x01, 0x0a, 0x08, 0x42, 0x6c, 0x6f, 0x62, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x6e, 0x64, 0x6f, + 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, + 0x73, 0x12, 0x2a, 0x0a, 0x09, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x52, 0x09, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x53, 0x75, 0x62, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x08, 0x53, 0x75, 0x62, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x12, 0x41, 0x0a, 0x0b, 0x4c, 0x61, 0x73, + 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 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, 0x0b, 0x4c, 0x61, + 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, + 0x5f, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3c, 0x0a, 0x14, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x35, 0x0a, 0x0d, 0x52, 0x65, + 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x24, 0x0a, 0x04, 0x6c, + 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x31, 0x2e, 0x52, + 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6c, 0x69, 0x73, + 0x74, 0x22, 0x81, 0x02, 0x0a, 0x0c, 0x52, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x65, + 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4d, + 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x53, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x53, 0x69, 0x7a, 0x65, + 0x12, 0x43, 0x0a, 0x0b, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, + 0x72, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 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, 0x22, 0x93, 0x01, 0x0a, 0x12, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, + 0x73, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x03, + 0x6d, 0x61, 0x70, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x2e, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x6d, 0x61, 0x70, 0x1a, + 0x4a, 0x0a, 0x08, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x37, 0x0a, 0x0e, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x25, 0x0a, + 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, + 0x6c, 0x69, 0x73, 0x74, 0x22, 0x79, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x38, 0x0a, 0x17, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, + 0x2e, 0x0a, 0x0a, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x22, + 0xbe, 0x01, 0x0a, 0x0a, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, + 0x0a, 0x0b, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, + 0x12, 0x2e, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x65, 0x18, 0x05, 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, 0x52, 0x04, 0x44, 0x61, 0x74, 0x65, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_imageData_proto_rawDescOnce sync.Once + file_imageData_proto_rawDescData = file_imageData_proto_rawDesc +) + +func file_imageData_proto_rawDescGZIP() []byte { + file_imageData_proto_rawDescOnce.Do(func() { + file_imageData_proto_rawDescData = protoimpl.X.CompressGZIP(file_imageData_proto_rawDescData) + }) + return file_imageData_proto_rawDescData +} + +var file_imageData_proto_msgTypes = make([]protoimpl.MessageInfo, 23) +var file_imageData_proto_goTypes = []interface{}{ + (*TagDescriptor)(nil), // 0: v1.TagDescriptor + (*ImageData)(nil), // 1: v1.ImageData + (*ManifestData)(nil), // 2: v1.ManifestData + (*RepoLastUpdatedImage)(nil), // 3: v1.RepoLastUpdatedImage + (*ProtoRepoMeta)(nil), // 4: v1.ProtoRepoMeta + (*RepoBlobs)(nil), // 5: v1.RepoBlobs + (*BlobInfo)(nil), // 6: v1.BlobInfo + (*DescriptorStatistics)(nil), // 7: v1.DescriptorStatistics + (*ReferrersInfo)(nil), // 8: v1.ReferrersInfo + (*ReferrerInfo)(nil), // 9: v1.ReferrerInfo + (*ManifestSignatures)(nil), // 10: v1.ManifestSignatures + (*SignaturesInfo)(nil), // 11: v1.SignaturesInfo + (*SignatureInfo)(nil), // 12: v1.SignatureInfo + (*LayersInfo)(nil), // 13: v1.LayersInfo + nil, // 14: v1.ImageData.AnnotationsEntry + nil, // 15: v1.ManifestData.AnnotationsEntry + nil, // 16: v1.ProtoRepoMeta.TagsEntry + nil, // 17: v1.ProtoRepoMeta.StatisticsEntry + nil, // 18: v1.ProtoRepoMeta.SignaturesEntry + nil, // 19: v1.ProtoRepoMeta.ReferrersEntry + nil, // 20: v1.RepoBlobs.BlobsEntry + nil, // 21: v1.ReferrerInfo.AnnotationsEntry + nil, // 22: v1.ManifestSignatures.MapEntry + (*Versioned)(nil), // 23: v1.Versioned + (*Descriptor)(nil), // 24: v1.Descriptor + (*ConfigData)(nil), // 25: v1.ConfigData + (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp + (*Platform)(nil), // 27: v1.Platform +} +var file_imageData_proto_depIdxs = []int32{ + 23, // 0: v1.ImageData.Versioned:type_name -> v1.Versioned + 2, // 1: v1.ImageData.Manifests:type_name -> v1.ManifestData + 24, // 2: v1.ImageData.Subject:type_name -> v1.Descriptor + 14, // 3: v1.ImageData.Annotations:type_name -> v1.ImageData.AnnotationsEntry + 23, // 4: v1.ManifestData.versioned:type_name -> v1.Versioned + 24, // 5: v1.ManifestData.Layers:type_name -> v1.Descriptor + 24, // 6: v1.ManifestData.Subject:type_name -> v1.Descriptor + 15, // 7: v1.ManifestData.Annotations:type_name -> v1.ManifestData.AnnotationsEntry + 25, // 8: v1.ManifestData.Config:type_name -> v1.ConfigData + 26, // 9: v1.RepoLastUpdatedImage.LastUpdated:type_name -> google.protobuf.Timestamp + 16, // 10: v1.ProtoRepoMeta.Tags:type_name -> v1.ProtoRepoMeta.TagsEntry + 17, // 11: v1.ProtoRepoMeta.Statistics:type_name -> v1.ProtoRepoMeta.StatisticsEntry + 18, // 12: v1.ProtoRepoMeta.Signatures:type_name -> v1.ProtoRepoMeta.SignaturesEntry + 19, // 13: v1.ProtoRepoMeta.Referrers:type_name -> v1.ProtoRepoMeta.ReferrersEntry + 27, // 14: v1.ProtoRepoMeta.Platforms:type_name -> v1.Platform + 3, // 15: v1.ProtoRepoMeta.LastUpdatedImage:type_name -> v1.RepoLastUpdatedImage + 20, // 16: v1.RepoBlobs.Blobs:type_name -> v1.RepoBlobs.BlobsEntry + 27, // 17: v1.BlobInfo.Platforms:type_name -> v1.Platform + 26, // 18: v1.BlobInfo.LastUpdated:type_name -> google.protobuf.Timestamp + 9, // 19: v1.ReferrersInfo.list:type_name -> v1.ReferrerInfo + 21, // 20: v1.ReferrerInfo.Annotations:type_name -> v1.ReferrerInfo.AnnotationsEntry + 22, // 21: v1.ManifestSignatures.map:type_name -> v1.ManifestSignatures.MapEntry + 12, // 22: v1.SignaturesInfo.list:type_name -> v1.SignatureInfo + 13, // 23: v1.SignatureInfo.LayersInfo:type_name -> v1.LayersInfo + 26, // 24: v1.LayersInfo.Date:type_name -> google.protobuf.Timestamp + 0, // 25: v1.ProtoRepoMeta.TagsEntry.value:type_name -> v1.TagDescriptor + 7, // 26: v1.ProtoRepoMeta.StatisticsEntry.value:type_name -> v1.DescriptorStatistics + 10, // 27: v1.ProtoRepoMeta.SignaturesEntry.value:type_name -> v1.ManifestSignatures + 8, // 28: v1.ProtoRepoMeta.ReferrersEntry.value:type_name -> v1.ReferrersInfo + 6, // 29: v1.RepoBlobs.BlobsEntry.value:type_name -> v1.BlobInfo + 11, // 30: v1.ManifestSignatures.MapEntry.value:type_name -> v1.SignaturesInfo + 31, // [31:31] is the sub-list for method output_type + 31, // [31:31] is the sub-list for method input_type + 31, // [31:31] is the sub-list for extension type_name + 31, // [31:31] is the sub-list for extension extendee + 0, // [0:31] is the sub-list for field type_name +} + +func init() { file_imageData_proto_init() } +func file_imageData_proto_init() { + if File_imageData_proto != nil { + return + } + file_versioned_proto_init() + file_config_proto_init() + file_descriptor_proto_init() + if !protoimpl.UnsafeEnabled { + file_imageData_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TagDescriptor); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ImageData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ManifestData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RepoLastUpdatedImage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProtoRepoMeta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RepoBlobs); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlobInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DescriptorStatistics); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReferrersInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReferrerInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ManifestSignatures); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignaturesInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignatureInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_imageData_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LayersInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_imageData_proto_msgTypes[1].OneofWrappers = []interface{}{} + file_imageData_proto_msgTypes[2].OneofWrappers = []interface{}{} + file_imageData_proto_msgTypes[3].OneofWrappers = []interface{}{} + file_imageData_proto_msgTypes[4].OneofWrappers = []interface{}{} + file_imageData_proto_msgTypes[6].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_imageData_proto_rawDesc, + NumEnums: 0, + NumMessages: 23, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_imageData_proto_goTypes, + DependencyIndexes: file_imageData_proto_depIdxs, + MessageInfos: file_imageData_proto_msgTypes, + }.Build() + File_imageData_proto = out.File + file_imageData_proto_rawDesc = nil + file_imageData_proto_goTypes = nil + file_imageData_proto_depIdxs = nil +} diff --git a/pkg/meta/proto_go/index.pb.go b/pkg/meta/proto_go/index.pb.go new file mode 100644 index 0000000000..105d456566 --- /dev/null +++ b/pkg/meta/proto_go/index.pb.go @@ -0,0 +1,215 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.15.8 +// source: index.proto + +package proto_go + +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_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_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_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_index_proto protoreflect.FileDescriptor + +var file_index_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x76, + 0x31, 0x1a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x86, 0x03, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2b, + 0x0a, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, + 0x52, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x09, 0x6d, + 0x65, 0x64, 0x69, 0x61, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x27, + 0x0a, 0x0c, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0c, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x74, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x09, 0x6d, 0x61, 0x6e, 0x69, 0x66, + 0x65, 0x73, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x09, 0x6d, 0x61, 0x6e, 0x69, + 0x66, 0x65, 0x73, 0x74, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x48, 0x02, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 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, 0x61, 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, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x79, 0x70, 0x65, + 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x74, 0x79, 0x70, + 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_index_proto_rawDescOnce sync.Once + file_index_proto_rawDescData = file_index_proto_rawDesc +) + +func file_index_proto_rawDescGZIP() []byte { + file_index_proto_rawDescOnce.Do(func() { + file_index_proto_rawDescData = protoimpl.X.CompressGZIP(file_index_proto_rawDescData) + }) + return file_index_proto_rawDescData +} + +var file_index_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_index_proto_goTypes = []interface{}{ + (*Index)(nil), // 0: v1.Index + nil, // 1: v1.Index.AnnotationsEntry + (*Versioned)(nil), // 2: v1.Versioned + (*Descriptor)(nil), // 3: v1.Descriptor +} +var file_index_proto_depIdxs = []int32{ + 2, // 0: v1.Index.versioned:type_name -> v1.Versioned + 3, // 1: v1.Index.manifests:type_name -> v1.Descriptor + 3, // 2: v1.Index.subject:type_name -> v1.Descriptor + 1, // 3: v1.Index.annotations:type_name -> 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_index_proto_init() } +func file_index_proto_init() { + if File_index_proto != nil { + return + } + file_descriptor_proto_init() + file_versioned_proto_init() + if !protoimpl.UnsafeEnabled { + file_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_index_proto_msgTypes[0].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_index_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_index_proto_goTypes, + DependencyIndexes: file_index_proto_depIdxs, + MessageInfos: file_index_proto_msgTypes, + }.Build() + File_index_proto = out.File + file_index_proto_rawDesc = nil + file_index_proto_goTypes = nil + file_index_proto_depIdxs = nil +} diff --git a/pkg/meta/proto_go/manifest.pb.go b/pkg/meta/proto_go/manifest.pb.go new file mode 100644 index 0000000000..0032207340 --- /dev/null +++ b/pkg/meta/proto_go/manifest.pb.go @@ -0,0 +1,226 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.15.8 +// source: manifest.proto + +package proto_go + +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_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_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_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_manifest_proto protoreflect.FileDescriptor + +var file_manifest_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x02, 0x76, 0x31, 0x1a, 0x10, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x03, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, + 0x66, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x52, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 0x12, 0x21, 0x0a, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x79, 0x70, + 0x65, 0x88, 0x01, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0c, 0x61, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x74, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, + 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x26, 0x0a, 0x06, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, + 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x48, 0x02, + 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, 0x0b, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 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, 0x61, 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, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x79, 0x70, 0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, + 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x74, 0x79, 0x70, 0x65, 0x42, 0x0a, 0x0a, 0x08, + 0x5f, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_manifest_proto_rawDescOnce sync.Once + file_manifest_proto_rawDescData = file_manifest_proto_rawDesc +) + +func file_manifest_proto_rawDescGZIP() []byte { + file_manifest_proto_rawDescOnce.Do(func() { + file_manifest_proto_rawDescData = protoimpl.X.CompressGZIP(file_manifest_proto_rawDescData) + }) + return file_manifest_proto_rawDescData +} + +var file_manifest_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_manifest_proto_goTypes = []interface{}{ + (*Manifest)(nil), // 0: v1.Manifest + nil, // 1: v1.Manifest.AnnotationsEntry + (*Versioned)(nil), // 2: v1.Versioned + (*Descriptor)(nil), // 3: v1.Descriptor +} +var file_manifest_proto_depIdxs = []int32{ + 2, // 0: v1.Manifest.versioned:type_name -> v1.Versioned + 3, // 1: v1.Manifest.config:type_name -> v1.Descriptor + 3, // 2: v1.Manifest.layers:type_name -> v1.Descriptor + 3, // 3: v1.Manifest.subject:type_name -> v1.Descriptor + 1, // 4: v1.Manifest.annotations:type_name -> 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_manifest_proto_init() } +func file_manifest_proto_init() { + if File_manifest_proto != nil { + return + } + file_descriptor_proto_init() + file_versioned_proto_init() + if !protoimpl.UnsafeEnabled { + file_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_manifest_proto_msgTypes[0].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_manifest_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_manifest_proto_goTypes, + DependencyIndexes: file_manifest_proto_depIdxs, + MessageInfos: file_manifest_proto_msgTypes, + }.Build() + File_manifest_proto = out.File + file_manifest_proto_rawDesc = nil + file_manifest_proto_goTypes = nil + file_manifest_proto_depIdxs = nil +} diff --git a/pkg/meta/proto_go/versioned.pb.go b/pkg/meta/proto_go/versioned.pb.go new file mode 100644 index 0000000000..b865ec2fa3 --- /dev/null +++ b/pkg/meta/proto_go/versioned.pb.go @@ -0,0 +1,141 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.15.8 +// source: versioned.proto + +package proto_go + +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_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_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_versioned_proto_rawDescGZIP(), []int{0} +} + +func (x *Versioned) GetSchemaversion() int32 { + if x != nil { + return x.Schemaversion + } + return 0 +} + +var File_versioned_proto protoreflect.FileDescriptor + +var file_versioned_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0x31, 0x0a, 0x09, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_versioned_proto_rawDescOnce sync.Once + file_versioned_proto_rawDescData = file_versioned_proto_rawDesc +) + +func file_versioned_proto_rawDescGZIP() []byte { + file_versioned_proto_rawDescOnce.Do(func() { + file_versioned_proto_rawDescData = protoimpl.X.CompressGZIP(file_versioned_proto_rawDescData) + }) + return file_versioned_proto_rawDescData +} + +var file_versioned_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_versioned_proto_goTypes = []interface{}{ + (*Versioned)(nil), // 0: v1.Versioned +} +var file_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_versioned_proto_init() } +func file_versioned_proto_init() { + if File_versioned_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_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_versioned_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_versioned_proto_goTypes, + DependencyIndexes: file_versioned_proto_depIdxs, + MessageInfos: file_versioned_proto_msgTypes, + }.Build() + File_versioned_proto = out.File + file_versioned_proto_rawDesc = nil + file_versioned_proto_goTypes = nil + file_versioned_proto_depIdxs = nil +} diff --git a/pkg/meta/proto_test.go b/pkg/meta/proto_test.go new file mode 100644 index 0000000000..f5cf9e22d7 --- /dev/null +++ b/pkg/meta/proto_test.go @@ -0,0 +1,208 @@ +package meta_test + +import ( + "encoding/json" + "fmt" + "net/url" + "sync" + "testing" + + ispec "github.com/opencontainers/image-spec/specs-go/v1" + . "github.com/smartystreets/goconvey/convey" + "google.golang.org/protobuf/proto" + "gopkg.in/resty.v1" + + "zotregistry.io/zot/pkg/api" + "zotregistry.io/zot/pkg/api/config" + "zotregistry.io/zot/pkg/api/constants" + zcommon "zotregistry.io/zot/pkg/common" + extconf "zotregistry.io/zot/pkg/extensions/config" + "zotregistry.io/zot/pkg/log" + "zotregistry.io/zot/pkg/meta/proto_go" + . "zotregistry.io/zot/pkg/test" + . "zotregistry.io/zot/pkg/test/image-utils" +) + +func TestProto(t *testing.T) { + Convey("Basic conversion", t, func() { + Convey("Manifest", func() { + mediaType := ispec.MediaTypeImageManifest + manifest := &proto_go.Manifest{ + Versioned: &proto_go.Versioned{Schemaversion: 2}, + Mediatype: &mediaType, + } + + buf, err := proto.Marshal(manifest) + So(err, ShouldBeNil) + + manifest = &proto_go.Manifest{} + + err = proto.Unmarshal(buf, manifest) + So(err, ShouldBeNil) + So(manifest.GetMediatype(), ShouldEqual, ispec.MediaTypeImageManifest) + }) + + Convey("Index", func() { + mediaType := ispec.MediaTypeImageIndex + index := &proto_go.Index{ + Versioned: &proto_go.Versioned{Schemaversion: 2}, + Mediatype: &mediaType, + } + + out, err := proto.Marshal(index) + So(err, ShouldBeNil) + + index = &proto_go.Index{} + + err = proto.Unmarshal(out, index) + So(err, ShouldBeNil) + So(index.GetMediatype(), ShouldEqual, ispec.MediaTypeImageIndex) + }) + }) +} + +func TestProtoParsing(t *testing.T) { + Convey("proto parse", t, func() { + port := GetFreePort() + baseURL := GetBaseURL(port) + conf := config.New() + conf.HTTP.Port = port + rootDir := t.TempDir() + + conf.Storage.RootDirectory = rootDir + defaultVal := true + conf.Extensions = &extconf.ExtensionConfig{ + Search: &extconf.SearchConfig{ + BaseConfig: extconf.BaseConfig{Enable: &defaultVal}, + }, + } + + storeController := GetDefaultStoreController(rootDir, log.NewLogger("debug", "")) + + err := WriteImageToFileSystem(CreateDefaultImage(), "repo", "tag1", storeController) + So(err, ShouldBeNil) + + err = WriteImageToFileSystem(CreateDefaultImage(), "repo", "tag2", storeController) + So(err, ShouldBeNil) + + img1 := CreateRandomImageWith(). + Annotations(map[string]string{ + "test": "annotation", + }).Build() + + imgRef := CreateRandomImageWith(). + Subject(img1.DescriptorRef()).Build() + + err = WriteImageToFileSystem(img1, "repo", "tag-img", storeController) + So(err, ShouldBeNil) + err = WriteImageToFileSystem(imgRef, "repo", "tag-ref", storeController) + So(err, ShouldBeNil) + + err = WriteImageToFileSystem(CreateDefaultImage(), "repo", "tag2", storeController) + So(err, ShouldBeNil) + + err = WriteMultiArchImageToFileSystem(CreateRandomMultiarch(), "repo-multi", "multi-arch", storeController) + So(err, ShouldBeNil) + + ctlr := api.NewController(conf) + ctrlManager := NewControllerManager(ctlr) + ctrlManager.StartAndWait(port) + defer ctrlManager.StopServer() + + query := ` + { + GlobalSearch(query:"repo:"){ + Repos { + Name LastUpdated Size + Platforms { Os Arch } + Vendors + NewestImage { + RepoName Tag LastUpdated Size IsSigned + Authors + } + } + } + }` + + resp, err := resty.R().Get(baseURL + constants.FullSearchPrefix + "?query=" + url.QueryEscape(query)) + So(resp, ShouldNotBeNil) + So(err, ShouldBeNil) + So(resp.StatusCode(), ShouldEqual, 200) + + responseStructRepos := &zcommon.GlobalSearchResultResp{} + + err = json.Unmarshal(resp.Body(), responseStructRepos) + So(err, ShouldBeNil) + + So(responseStructRepos.Repos, ShouldNotBeEmpty) + }) +} + +func TestGenerate(t *testing.T) { + repoCount := 2000 + manifestImageCount := 10 + multiarchCount := 5 + + storeController := GetDefaultStoreController("/home/laur/dev/images/stress-test/storage", log.NewLogger("debug", "/dev/null")) + + for repoId := 0; repoId < repoCount; repoId++ { + for i := 0; i < manifestImageCount; i++ { + err := WriteImageToFileSystem( + CreateImageWith(). + RandomLayers(2, 5). + RandomConfig(). + Annotations(map[string]string{"test": "annotation"}).Build(), + fmt.Sprintf("repo%d", repoId), + fmt.Sprintf("tag%d", i), + storeController, + ) + if err != nil { + t.FailNow() + } + + t.Logf("Repo: %d, Manifest Tag: %d", repoId, i) + } + + for i := 0; i < multiarchCount; i++ { + err := WriteMultiArchImageToFileSystem( + CreateRandomMultiarch(), + fmt.Sprintf("repo%d", repoId), + fmt.Sprintf("tag-multi%d", i), + storeController, + ) + if err != nil { + t.FailNow() + } + + t.Logf("Repo: %d, Index Tag: %d", repoId, i) + } + } +} + +const ( + homeQuery1 = `{GlobalSearch(query:"", requestedPage: {limit:3 offset:0 sortBy: DOWNLOADS} ) {Page {TotalCount ItemCount} Repos {Name LastUpdated Size Platforms { Os Arch } IsStarred IsBookmarked NewestImage { Tag Vulnerabilities {MaxSeverity Count} Description IsSigned SignatureInfo { Tool IsTrusted Author } Licenses Vendor Labels } DownloadCount}}}` + homeQuery2 = `{GlobalSearch(query:"", requestedPage: {limit:2 offset:0 sortBy: UPDATE_TIME} ) {Page {TotalCount ItemCount} Repos {Name LastUpdated Size Platforms { Os Arch } IsStarred IsBookmarked NewestImage { Tag Vulnerabilities {MaxSeverity Count} Description IsSigned SignatureInfo { Tool IsTrusted Author } Licenses Vendor Labels } DownloadCount}}}` + homeQuery3 = `{GlobalSearch(query:"", requestedPage: {limit:2 offset:0 sortBy: RELEVANCE} ,filter: { IsBookmarked: true}) {Page {TotalCount ItemCount} Repos {Name LastUpdated Size Platforms { Os Arch } IsStarred IsBookmarked NewestImage { Tag Vulnerabilities {MaxSeverity Count} Description IsSigned SignatureInfo { Tool IsTrusted Author } Licenses Vendor Labels } DownloadCount}}}` +) + +func TestProfileHomePage(t *testing.T) { + for i := 0; i < 10; i++ { + wg := &sync.WaitGroup{} + + go RunQuery(homeQuery1, wg, t) + go RunQuery(homeQuery2, wg, t) + go RunQuery(homeQuery3, wg, t) + + wg.Wait() + t.Logf("Execution: %d", i) + } +} + +func RunQuery(query string, wg *sync.WaitGroup, t *testing.T) { + resp, err := resty.R().Get("http://127.0.0.1:5000" + constants.FullSearchPrefix + "?query=" + url.QueryEscape(query)) + if err != nil || resp.StatusCode() != 200 { + panic(fmt.Errorf("StatusCode: %d Err: %w", resp.StatusCode(), err)) + } + + t.Log("\t*") +} diff --git a/pkg/meta/types/types.go b/pkg/meta/types/types.go index 6e64280bef..b26c165ccd 100644 --- a/pkg/meta/types/types.go +++ b/pkg/meta/types/types.go @@ -5,6 +5,7 @@ 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 @@ -27,8 +28,33 @@ const ( ) type ( - FilterFunc func(repoMeta RepoMetadata, manifestMeta ManifestMetadata) bool - FilterRepoFunc func(repoMeta RepoMetadata) bool + FilterFunc func(repoMeta RepoMetadata, manifestMeta ManifestMetadata) bool + FilterProtoFunc func(repoMeta RepoMetadata2, imageData ImageData2) bool + FilterRepoFunc func(repoMeta RepoMetadata) bool + FilterProtoRepoFunc func(repoMeta RepoMetadata2) bool + FilterRepoNameFunc func(repo string) int + FilterFullRepoFunc func(repoMeta FullRepoMetadata) bool + FilterRepoTagFunc func(repo, tag string) bool +) + +func AcceptAllRepoNames(repo string) int { + return 1 +} + +func AcceptAllRepoMeta(repometa FullRepoMetadata) bool { + return true +} + +func AcceptAllRepoTag(repo, tag string) bool { + return true +} + +func AcceptAllImageData(repoMeta RepoMetadata2, imageData ImageData2) bool { + return true +} + +type ( + ImageDigest = string ) type MetaDB interface { //nolint:interfacebloat @@ -135,6 +161,53 @@ type MetaDB interface { //nolint:interfacebloat ImageTrustStore() ImageTrustStore SetImageTrustStore(imgTrustStore ImageTrustStore) + + // -------------------------------------------------------------------------- + + ProtoSetImageData(digest godigest.Digest, imageData ImageData2) error + + ProtoSetRepoReference(repo string, reference string, imageData ImageData2) error + + ProtoSearchRepos(ctx context.Context, searchText string) ([]FullRepoMetadata, error) + + ProtoSearchTags(ctx context.Context, searchText string) ([]FullImageData, error) + + ProtoFilterTags(ctx context.Context, filterRepoTag FilterRepoTagFunc, filterFunc FilterProtoFunc) ([]FullImageData, error) + + ProtoFilterRepos(ctx context.Context, rankName FilterRepoNameFunc, filterFunc FilterFullRepoFunc) ([]FullRepoMetadata, error) + + ProtoGetRepoMeta(repo string) (RepoMetadata2, error) + + ProtoGetFullRepoMeta(ctx context.Context, repo string) (FullRepoMetadata, error) + + ProtoGetImageData(digest godigest.Digest) (ImageData2, error) + + ProtoGetMultipleRepoMeta(ctx context.Context, filter func(repoMeta RepoMetadata2) bool) ( + []RepoMetadata2, error) + + ProtoAddManifestSignature(repo string, signedManifestDigest godigest.Digest, sm SignatureMetadata) error + + ProtoDeleteSignature(repo string, signedManifestDigest godigest.Digest, sigMeta SignatureMetadata) error + + ProtoIncrementRepoStars(repo string) error + + ProtoDecrementRepoStars(repo string) error + + ProtoGetRepoStars(repo string) (int, error) + + ProtoDeleteRepoTag(repo string, tag string) error + + ProtoGetUserRepoMeta(ctx context.Context, repo string) (RepoMetadata2, error) + + ProtoSetRepoMeta(repo string, repoMeta RepoMetadata2) error + + ProtoGetReferrersInfo(repo string, referredDigest godigest.Digest, artifactTypes []string) ([]ReferrerInfo, error) + + ProtoIncrementImageDownloads(repo string, reference string) error + + ProtoUpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error + + ProtoFilterImageData(ctx context.Context, digests []string) (map[string]ImageData2, error) } type UserDB interface { //nolint:interfacebloat @@ -176,11 +249,100 @@ 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, blob []byte, + repo string, + ) (string, time.Time, bool, error) + + ProtoVerifySignature( + signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, imageData ImageData2, repo string, ) (string, time.Time, bool, error) } +type ImageData2 struct { + MediaType string + Digest godigest.Digest + Size int64 + Index *ispec.Index + Manifests []ManifestData2 +} + +type ManifestData2 struct { + Size int64 + Digest godigest.Digest + ispec.Manifest + ConfigContent ispec.Image +} + +type RepoMetadata2 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 +} + +// used in repo search +type RepoStatistics struct { + Platforms []ispec.Platform + Vendors []string + Size string + LastUpdated time.Time +} + +type FullRepoMetadata struct { + Name string + Tags map[string]Descriptor + Size int64 + Platforms []ispec.Platform + Vendors []string + IsStarred bool + IsBookmarked bool + StarCount int + DownloadCount int + Rank int + + LastUpdatedImage *LastUpdatedImage + Statistics map[string]DescriptorStatistics + Signatures map[string]ManifestSignatures + Referrers map[string][]ReferrerInfo +} + +type FullImageData struct { + Repo string + Tag string + MediaType string + Digest godigest.Digest + Size int64 + Index *ispec.Index + Manifests []FullManifestData + + Referrers []ReferrerInfo + Statistics DescriptorStatistics + Signatures ManifestSignatures +} + +type FullManifestData struct { + ManifestData2 + + Referrers []ReferrerInfo + Statistics DescriptorStatistics + Signatures ManifestSignatures +} + +type LastUpdatedImage struct { + Descriptor + Tag string + LastUpdated *time.Time +} + type ManifestMetadata struct { ManifestBlob []byte ConfigBlob []byte diff --git a/pkg/test/mocks/repo_db_mock.go b/pkg/test/mocks/repo_db_mock.go index 9d40b4c1da..44c7ccd366 100644 --- a/pkg/test/mocks/repo_db_mock.go +++ b/pkg/test/mocks/repo_db_mock.go @@ -5,6 +5,7 @@ import ( godigest "github.com/opencontainers/go-digest" + "zotregistry.io/zot/pkg/meta/proto_go" mTypes "zotregistry.io/zot/pkg/meta/types" ) @@ -112,6 +113,30 @@ type MetaDBMock struct { ImageTrustStoreFn func() mTypes.ImageTrustStore SetImageTrustStoreFn func(mTypes.ImageTrustStore) + + SetProtoImageDataFn func(digest godigest.Digest, imageData mTypes.ImageData2) error + + ProtoSetReferrerFn func(repo string, referredDigest godigest.Digest, referrer *proto_go.ReferrerInfo) error + ProtoSetRepoReferenceFn func(repo string, reference string, manifestDigest godigest.Digest, mediaType string) error + ProtoSearchReposFn func(ctx context.Context, searchText string) ([]mTypes.RepoMetadata2, map[string]mTypes.ImageData2, error) + ProtoSearchTagsFn func(ctx context.Context, searchText string) ([]mTypes.FullImageData, error) + ProtoFilterTagFn func(ctx context.Context, filterFunc mTypes.FilterProtoFunc) ([]mTypes.RepoMetadata2, map[string]mTypes.ImageData2, error) + ProtoGetRepoMetaFn func(repo string) (mTypes.RepoMetadata2, error) + ProtoGetImageDataFn func(digest godigest.Digest) (mTypes.ImageData2, error) + ProtoGetMultipleRepoMetaFn func(ctx context.Context, filter func(repoMeta mTypes.RepoMetadata2) bool) ([]mTypes.RepoMetadata2, error) + ProtoFilterReposFn func(ctx context.Context, filter mTypes.FilterProtoRepoFunc) ([]mTypes.RepoMetadata2, map[string]mTypes.ImageData2, error) + ProtoIncrementRepoStarsFn func(repo string) error + ProtoDecrementRepoStarsFn func(repo string) error + ProtoGetRepoStarsFn func(repo string) (int, error) + ProtoDeleteRepoTagFn func(repo string, tag string) error + ProtoGetUserRepoMetaFn func(ctx context.Context, repo string) (mTypes.RepoMetadata2, error) + ProtoSetRepoMetaFn func(repo string, repoMeta mTypes.RepoMetadata2) error + ProtoDeleteReferrerFn func(repo string, referredDigest godigest.Digest, referrerDigest godigest.Digest) error + ProtoGetReferrersInfoFn func(repo string, referredDigest godigest.Digest, artifactTypes []string) ([]mTypes.ReferrerInfo, error) + ProtoIncrementImageDownloadsFn func(repo string, reference string) error + ProtoUpdateSignaturesValidityFn func(repo string, manifestDigest godigest.Digest) error + ProtoAddManifestSignatureFn func(repo string, signedManifestDigest godigest.Digest, sygMeta mTypes.SignatureMetadata) error + ProtoDeleteSignatureFn func(repo string, signedManifestDigest godigest.Digest, sigMeta mTypes.SignatureMetadata) error } func (sdm MetaDBMock) ImageTrustStore() mTypes.ImageTrustStore { @@ -498,3 +523,108 @@ func (sdm MetaDBMock) DeleteUserAPIKey(ctx context.Context, id string) error { return nil } + +// TODO +func (sdm MetaDBMock) SetProtoImageData(digest godigest.Digest, imageData mTypes.ImageData2) error { + if sdm.SetProtoImageDataFn != nil { + return sdm.SetProtoImageDataFn(digest, imageData) + } + + return nil +} + +// TODO +func (sdm MetaDBMock) ProtoSetImageData(digest godigest.Digest, imageData mTypes.ImageData2) error { + + return nil +} + +// TODO +func (bdw MetaDBMock) ProtoSetRepoReference(repo string, reference string, imageData mTypes.ImageData2) error { + return nil +} + +// TODO +func (bdw MetaDBMock) ProtoSearchRepos(ctx context.Context, searchText string) ([]mTypes.FullRepoMetadata, error) { + return []mTypes.FullRepoMetadata{}, nil +} + +// TODO +func (bdw MetaDBMock) ProtoSearchTags(ctx context.Context, searchText string) ([]mTypes.FullImageData, error) { + return []mTypes.FullImageData{}, nil +} + +func (bdw MetaDBMock) ProtoFilterTags(ctx context.Context, filterRepoTag mTypes.FilterRepoTagFunc, filterFunc mTypes.FilterProtoFunc, +) ([]mTypes.FullImageData, error) { + return []mTypes.FullImageData{}, nil +} + +func (bdw MetaDBMock) ProtoGetRepoMeta(repo string) (mTypes.RepoMetadata2, error) { + return mTypes.RepoMetadata2{}, nil +} + +func (bdw MetaDBMock) ProtoGetFullRepoMeta(ctx context.Context, repo string) (mTypes.FullRepoMetadata, error) { + return mTypes.FullRepoMetadata{}, nil +} + +func (bdw MetaDBMock) ProtoGetImageData(digest godigest.Digest) (mTypes.ImageData2, error) { + return mTypes.ImageData2{}, nil +} + +func (bdw MetaDBMock) ProtoGetMultipleRepoMeta(ctx context.Context, filter func(repoMeta mTypes.RepoMetadata2) bool) ([]mTypes.RepoMetadata2, error) { + return []mTypes.RepoMetadata2{}, nil +} + +func (bdw MetaDBMock) ProtoFilterRepos(ctx context.Context, rankName mTypes.FilterRepoNameFunc, filterFunc mTypes.FilterFullRepoFunc, +) ([]mTypes.FullRepoMetadata, error) { + return []mTypes.FullRepoMetadata{}, nil +} + +func (bdw MetaDBMock) ProtoIncrementRepoStars(repo string) error { + return nil +} + +func (bdw MetaDBMock) ProtoDecrementRepoStars(repo string) error { + return nil +} + +func (bdw MetaDBMock) ProtoGetRepoStars(repo string) (int, error) { + return 0, nil +} + +func (bdw MetaDBMock) ProtoDeleteRepoTag(repo string, tag string) error { + return nil +} + +func (bdw MetaDBMock) ProtoGetUserRepoMeta(ctx context.Context, repo string) (mTypes.RepoMetadata2, error) { + return mTypes.RepoMetadata2{}, nil +} + +func (bdw MetaDBMock) ProtoSetRepoMeta(repo string, repoMeta mTypes.RepoMetadata2) error { + return nil +} + +func (bdw MetaDBMock) ProtoGetReferrersInfo(repo string, referredDigest godigest.Digest, artifactTypes []string) ([]mTypes.ReferrerInfo, error) { + return []mTypes.ReferrerInfo{}, nil +} + +func (bdw MetaDBMock) ProtoIncrementImageDownloads(repo string, reference string) error { + return nil +} + +func (bdw MetaDBMock) ProtoUpdateSignaturesValidity(repo string, manifestDigest godigest.Digest) error { + return nil +} + +func (bdw MetaDBMock) ProtoAddManifestSignature(repo string, signedManifestDigest godigest.Digest, sygMeta mTypes.SignatureMetadata) error { + return nil +} + +func (bdw MetaDBMock) ProtoDeleteSignature(repo string, signedManifestDigest godigest.Digest, sigMeta mTypes.SignatureMetadata) error { + return nil +} + +func (bdw MetaDBMock) ProtoFilterImageData(ctx context.Context, digests []string, +) (map[string]mTypes.ImageData2, error) { + return map[string]mTypes.ImageData2{}, nil +}