package convert import ( "time" godigest "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/specs-go" ispec "github.com/opencontainers/image-spec/specs-go/v1" "google.golang.org/protobuf/types/known/timestamppb" "zotregistry.dev/zot/pkg/common" proto_go "zotregistry.dev/zot/pkg/meta/proto/gen" mTypes "zotregistry.dev/zot/pkg/meta/types" ) func GetHistory(history []*proto_go.History) []ispec.History { if history == nil { return nil } results := make([]ispec.History, 0, len(history)) for _, his := range history { results = append(results, ispec.History{ Created: ref(his.GetCreated().AsTime()), CreatedBy: his.GetCreatedBy(), Author: his.GetAuthor(), Comment: his.GetComment(), EmptyLayer: his.GetEmptyLayer(), }) } return results } func GetImageArtifactType(imageMeta *proto_go.ImageMeta) string { switch imageMeta.GetMediaType() { case ispec.MediaTypeImageManifest: manifestArtifactType := imageMeta.GetManifests()[0].GetManifest().GetArtifactType() if manifestArtifactType != "" { return manifestArtifactType } return imageMeta.GetManifests()[0].GetManifest().GetConfig().GetMediaType() case ispec.MediaTypeImageIndex: return imageMeta.GetIndex().GetIndex().GetArtifactType() default: return "" } } func GetImageManifestSize(imageMeta *proto_go.ImageMeta) int64 { switch imageMeta.GetMediaType() { case ispec.MediaTypeImageManifest: return imageMeta.GetManifests()[0].GetSize() case ispec.MediaTypeImageIndex: return imageMeta.GetIndex().GetSize() default: return 0 } } func GetImageDigest(imageMeta *proto_go.ImageMeta) godigest.Digest { switch imageMeta.GetMediaType() { case ispec.MediaTypeImageManifest: return godigest.Digest(imageMeta.GetManifests()[0].GetDigest()) case ispec.MediaTypeImageIndex: return godigest.Digest(imageMeta.GetIndex().GetDigest()) default: return "" } } func GetImageDigestStr(imageMeta *proto_go.ImageMeta) string { switch imageMeta.GetMediaType() { case ispec.MediaTypeImageManifest: return imageMeta.GetManifests()[0].GetDigest() case ispec.MediaTypeImageIndex: return imageMeta.GetIndex().GetDigest() default: return "" } } func GetImageAnnotations(imageMeta *proto_go.ImageMeta) map[string]string { switch imageMeta.GetMediaType() { case ispec.MediaTypeImageManifest: return imageMeta.GetManifests()[0].GetManifest().GetAnnotations() case ispec.MediaTypeImageIndex: return imageMeta.GetIndex().GetIndex().GetAnnotations() default: return map[string]string{} } } func GetImageSubject(imageMeta *proto_go.ImageMeta) *ispec.Descriptor { switch imageMeta.GetMediaType() { case ispec.MediaTypeImageManifest: if imageMeta.GetManifests()[0].GetManifest().GetSubject() == nil { return nil } return GetDescriptorRef(imageMeta.GetManifests()[0].GetManifest().GetSubject()) case ispec.MediaTypeImageIndex: return GetDescriptorRef(imageMeta.GetIndex().GetIndex().GetSubject()) default: return nil } } func GetDescriptorRef(descriptor *proto_go.Descriptor) *ispec.Descriptor { if descriptor == nil { return nil } platform := GetPlatformRef(descriptor.GetPlatform()) return &ispec.Descriptor{ MediaType: descriptor.GetMediaType(), Digest: godigest.Digest(descriptor.GetDigest()), Size: descriptor.GetSize(), URLs: descriptor.GetURLs(), Data: descriptor.GetData(), Platform: platform, ArtifactType: descriptor.GetArtifactType(), Annotations: descriptor.GetAnnotations(), } } func GetPlatform(platform *proto_go.Platform) ispec.Platform { if platform == nil { return ispec.Platform{} } return ispec.Platform{ Architecture: platform.GetArchitecture(), OS: platform.GetOS(), OSVersion: platform.GetOSVersion(), OSFeatures: platform.GetOSFeatures(), Variant: platform.GetVariant(), } } func GetPlatformRef(platform *proto_go.Platform) *ispec.Platform { if platform == nil { return nil } return &ispec.Platform{ Architecture: platform.GetArchitecture(), OS: platform.GetOS(), OSVersion: platform.GetOSVersion(), OSFeatures: platform.GetOSFeatures(), Variant: platform.GetVariant(), } } 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.GetMediaType(), Digest: godigest.Digest(desc.GetDigest()), Size: desc.GetSize(), }) } return results } func GetSubject(subj *proto_go.Descriptor) *ispec.Descriptor { if subj == nil { return nil } return &ispec.Descriptor{ MediaType: subj.GetMediaType(), Digest: godigest.Digest(subj.GetDigest()), Size: subj.GetSize(), } } 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.GetList() { referrers = append(referrers, mTypes.ReferrerInfo{ Digest: dbRef.GetDigest(), MediaType: dbRef.GetMediaType(), ArtifactType: dbRef.GetArtifactType(), Size: int(dbRef.GetSize()), // int64 to int32, need to review this later Annotations: dbRef.GetAnnotations(), }) } results[digest] = referrers } return results } func GetImageReferrers(refs *proto_go.ReferrersInfo) []mTypes.ReferrerInfo { if refs == nil { return []mTypes.ReferrerInfo{} } results := []mTypes.ReferrerInfo{} for _, dbRef := range refs.GetList() { results = append(results, mTypes.ReferrerInfo{ Digest: dbRef.GetDigest(), MediaType: dbRef.GetMediaType(), ArtifactType: dbRef.GetArtifactType(), Size: int(dbRef.GetSize()), // int64 to int32, need to review this later Annotations: dbRef.GetAnnotations(), }) } 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.GetMap() { imageSignatures[signatureName] = GetSignaturesInfo(signatureInfo.GetList()) } results[digest] = imageSignatures } return results } func GetImageSignatures(sigs *proto_go.ManifestSignatures) mTypes.ManifestSignatures { if sigs == nil { return mTypes.ManifestSignatures{} } results := mTypes.ManifestSignatures{} for signatureName, signatureInfo := range sigs.GetMap() { results[signatureName] = GetSignaturesInfo(signatureInfo.GetList()) } return results } func GetSignaturesInfo(sigsInfo []*proto_go.SignatureInfo) []mTypes.SignatureInfo { results := []mTypes.SignatureInfo{} for _, siginfo := range sigsInfo { results = append(results, mTypes.SignatureInfo{ SignatureManifestDigest: siginfo.GetSignatureManifestDigest(), LayersInfo: GetLayersInfo(siginfo.GetLayersInfo()), }) } return results } func GetLayersInfo(layersInfo []*proto_go.LayersInfo) []mTypes.LayerInfo { results := []mTypes.LayerInfo{} for _, layerInfo := range layersInfo { date := time.Time{} if layerInfo.GetDate() != nil { date = layerInfo.GetDate().AsTime() } results = append(results, mTypes.LayerInfo{ LayerDigest: layerInfo.GetLayerDigest(), LayerContent: layerInfo.GetLayerContent(), SignatureKey: layerInfo.GetSignatureKey(), Signer: layerInfo.GetSigner(), Date: date, }) } return results } func GetStatisticsMap(stats map[mTypes.ImageDigest]*proto_go.DescriptorStatistics, ) map[mTypes.ImageDigest]mTypes.DescriptorStatistics { results := map[mTypes.ImageDigest]mTypes.DescriptorStatistics{} for digest, stat := range stats { results[digest] = mTypes.DescriptorStatistics{ DownloadCount: int(stat.GetDownloadCount()), LastPullTimestamp: stat.GetLastPullTimestamp().AsTime(), PushTimestamp: stat.GetPushTimestamp().AsTime(), PushedBy: stat.GetPushedBy(), } } return results } func GetImageStatistics(stats *proto_go.DescriptorStatistics) mTypes.DescriptorStatistics { if stats == nil { return mTypes.DescriptorStatistics{} } return mTypes.DescriptorStatistics{ DownloadCount: int(stats.GetDownloadCount()), LastPullTimestamp: stats.GetLastPullTimestamp().AsTime(), PushTimestamp: stats.GetPushTimestamp().AsTime(), PushedBy: stats.GetPushedBy(), } } func GetImageManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest godigest.Digest, ) mTypes.ImageMeta { return mTypes.ImageMeta{ MediaType: ispec.MediaTypeImageManifest, Digest: digest, Size: size, Manifests: []mTypes.ManifestMeta{ { Digest: digest, Size: size, Config: configContent, Manifest: manifestContent, }, }, } } func GetImageIndexMeta(indexContent ispec.Index, size int64, digest godigest.Digest) mTypes.ImageMeta { return mTypes.ImageMeta{ MediaType: ispec.MediaTypeImageIndex, Index: &indexContent, Manifests: GetManifests(indexContent.Manifests), Size: size, Digest: digest, } } func GetTags(tags map[mTypes.Tag]*proto_go.TagDescriptor) map[mTypes.Tag]mTypes.Descriptor { resultMap := map[mTypes.Tag]mTypes.Descriptor{} for tag, tagDescriptor := range tags { resultMap[tag] = mTypes.Descriptor{ Digest: tagDescriptor.GetDigest(), MediaType: tagDescriptor.GetMediaType(), } } return resultMap } func GetManifests(descriptors []ispec.Descriptor) []mTypes.ManifestMeta { manifestList := []mTypes.ManifestMeta{} for _, manifest := range descriptors { manifestList = append(manifestList, mTypes.ManifestMeta{ Digest: manifest.Digest, Size: manifest.Size, }) } return manifestList } func GetTime(time *timestamppb.Timestamp) *time.Time { if time == nil { return nil } return ref(time.AsTime()) } func GetFullImageMetaFromProto(tag string, protoRepoMeta *proto_go.RepoMeta, protoImageMeta *proto_go.ImageMeta, ) mTypes.FullImageMeta { if protoRepoMeta == nil { return mTypes.FullImageMeta{} } imageMeta := GetImageMeta(protoImageMeta) imageDigest := imageMeta.Digest.String() return mTypes.FullImageMeta{ Repo: protoRepoMeta.GetName(), Tag: tag, MediaType: imageMeta.MediaType, Digest: imageMeta.Digest, Size: imageMeta.Size, Index: imageMeta.Index, Manifests: GetFullManifestData(protoRepoMeta, imageMeta.Manifests), IsStarred: protoRepoMeta.GetIsStarred(), IsBookmarked: protoRepoMeta.GetIsBookmarked(), Referrers: GetImageReferrers(protoRepoMeta.GetReferrers()[imageDigest]), Statistics: GetImageStatistics(protoRepoMeta.GetStatistics()[imageDigest]), Signatures: GetImageSignatures(protoRepoMeta.GetSignatures()[imageDigest]), } } func GetFullManifestData(protoRepoMeta *proto_go.RepoMeta, manifestData []mTypes.ManifestMeta, ) []mTypes.FullManifestMeta { if protoRepoMeta == nil { return []mTypes.FullManifestMeta{} } results := []mTypes.FullManifestMeta{} for i := range manifestData { results = append(results, mTypes.FullManifestMeta{ ManifestMeta: manifestData[i], Referrers: GetImageReferrers(protoRepoMeta.GetReferrers()[manifestData[i].Digest.String()]), Statistics: GetImageStatistics(protoRepoMeta.GetStatistics()[manifestData[i].Digest.String()]), Signatures: GetImageSignatures(protoRepoMeta.GetSignatures()[manifestData[i].Digest.String()]), }) } return results } func GetRepoMeta(protoRepoMeta *proto_go.RepoMeta) mTypes.RepoMeta { if protoRepoMeta == nil { return mTypes.RepoMeta{} } repoDownloads := int32(0) for _, descriptor := range protoRepoMeta.GetTags() { if statistic := protoRepoMeta.GetStatistics()[descriptor.GetDigest()]; statistic != nil { repoDownloads += statistic.GetDownloadCount() } } return mTypes.RepoMeta{ Name: protoRepoMeta.GetName(), Tags: GetTags(protoRepoMeta.GetTags()), Rank: int(protoRepoMeta.GetRank()), Size: protoRepoMeta.GetSize(), Platforms: GetPlatforms(protoRepoMeta.GetPlatforms()), Vendors: protoRepoMeta.GetVendors(), IsStarred: protoRepoMeta.GetIsStarred(), IsBookmarked: protoRepoMeta.GetIsBookmarked(), StarCount: int(protoRepoMeta.GetStars()), DownloadCount: int(repoDownloads), LastUpdatedImage: GetLastUpdatedImage(protoRepoMeta.GetLastUpdatedImage()), Statistics: GetStatisticsMap(protoRepoMeta.GetStatistics()), Signatures: GetSignatures(protoRepoMeta.GetSignatures()), Referrers: GetReferrers(protoRepoMeta.GetReferrers()), } } func GetPlatforms(platforms []*proto_go.Platform) []ispec.Platform { result := []ispec.Platform{} for i := range platforms { result = append(result, GetPlatform(platforms[i])) } return result } func AddProtoPlatforms(platforms []*proto_go.Platform, newPlatforms []*proto_go.Platform) []*proto_go.Platform { for _, newPlatform := range newPlatforms { if !ContainsProtoPlatform(platforms, newPlatform) { platforms = append(platforms, newPlatform) } } return platforms } func ContainsProtoPlatform(platforms []*proto_go.Platform, platform *proto_go.Platform) bool { for i := range platforms { if platforms[i].GetOS() == platform.GetOS() && platforms[i].GetArchitecture() == platform.GetArchitecture() { return true } } return false } func AddVendors(vendors []string, newVendors []string) []string { for _, newVendor := range newVendors { if !common.Contains(vendors, newVendor) { vendors = append(vendors, newVendor) } } return vendors } func GetLastUpdatedImage(protoLastUpdated *proto_go.RepoLastUpdatedImage) *mTypes.LastUpdatedImage { if protoLastUpdated == nil { return nil } return &mTypes.LastUpdatedImage{ Descriptor: mTypes.Descriptor{ Digest: protoLastUpdated.GetDigest(), MediaType: protoLastUpdated.GetMediaType(), }, Tag: protoLastUpdated.GetTag(), LastUpdated: GetTime(protoLastUpdated.GetLastUpdated()), } } func GetImageMeta(dbImageMeta *proto_go.ImageMeta) mTypes.ImageMeta { if dbImageMeta == nil { return mTypes.ImageMeta{} } imageMeta := mTypes.ImageMeta{ MediaType: dbImageMeta.GetMediaType(), Size: GetImageManifestSize(dbImageMeta), Digest: GetImageDigest(dbImageMeta), } if dbImageMeta.GetMediaType() == ispec.MediaTypeImageIndex { manifests := make([]ispec.Descriptor, 0, len(dbImageMeta.GetManifests())) for _, manifest := range dbImageMeta.GetIndex().GetIndex().GetManifests() { manifests = append(manifests, ispec.Descriptor{ MediaType: manifest.GetMediaType(), Digest: godigest.Digest(manifest.GetDigest()), Size: manifest.GetSize(), }) } imageMeta.Index = &ispec.Index{ Versioned: specs.Versioned{SchemaVersion: int(dbImageMeta.GetIndex().GetIndex().Versioned.GetSchemaVersion())}, MediaType: ispec.MediaTypeImageIndex, Manifests: manifests, Subject: GetImageSubject(dbImageMeta), ArtifactType: GetImageArtifactType(dbImageMeta), Annotations: GetImageAnnotations(dbImageMeta), } } manifestDataList := make([]mTypes.ManifestMeta, 0, len(dbImageMeta.GetManifests())) for _, manifest := range dbImageMeta.GetManifests() { manifestDataList = append(manifestDataList, mTypes.ManifestMeta{ Size: manifest.GetSize(), Digest: godigest.Digest(manifest.GetDigest()), Manifest: ispec.Manifest{ Versioned: specs.Versioned{SchemaVersion: int(manifest.GetManifest().GetVersioned().GetSchemaVersion())}, MediaType: manifest.GetManifest().GetMediaType(), ArtifactType: manifest.GetManifest().GetArtifactType(), Config: ispec.Descriptor{ MediaType: manifest.GetManifest().GetConfig().GetMediaType(), Size: manifest.GetManifest().GetConfig().GetSize(), Digest: godigest.Digest(manifest.GetManifest().GetConfig().GetDigest()), }, Layers: GetLayers(manifest.GetManifest().GetLayers()), Subject: GetSubject(manifest.GetManifest().GetSubject()), Annotations: manifest.GetManifest().GetAnnotations(), }, Config: ispec.Image{ Created: GetTime(manifest.GetConfig().GetCreated()), Author: manifest.GetConfig().GetAuthor(), Platform: GetPlatform(manifest.GetConfig().GetPlatform()), Config: ispec.ImageConfig{ User: manifest.GetConfig().GetConfig().GetUser(), ExposedPorts: GetExposedPorts(manifest.GetConfig().GetConfig().GetExposedPorts()), Env: manifest.GetConfig().GetConfig().GetEnv(), Entrypoint: manifest.GetConfig().GetConfig().GetEntrypoint(), Cmd: manifest.GetConfig().GetConfig().GetCmd(), Volumes: GetConfigVolumes(manifest.GetConfig().GetConfig().GetVolumes()), WorkingDir: manifest.GetConfig().GetConfig().GetWorkingDir(), Labels: manifest.GetConfig().GetConfig().GetLabels(), StopSignal: manifest.GetConfig().GetConfig().GetStopSignal(), }, RootFS: ispec.RootFS{ Type: manifest.GetConfig().GetRootFS().GetType(), DiffIDs: GetDiffIDs(manifest.GetConfig().GetRootFS().GetDiffIDs()), }, History: GetHistory(manifest.GetConfig().GetHistory()), }, }) } imageMeta.Manifests = manifestDataList return imageMeta } func GetExposedPorts(exposedPorts map[string]*proto_go.EmptyMessage) map[string]struct{} { if exposedPorts == nil { return nil } result := map[string]struct{}{} for key := range exposedPorts { result[key] = struct{}{} } return result } func GetConfigVolumes(configVolumes map[string]*proto_go.EmptyMessage) map[string]struct{} { if configVolumes == nil { return nil } result := map[string]struct{}{} for key := range configVolumes { result[key] = struct{}{} } return result } func GetDiffIDs(diffIDs []string) []godigest.Digest { result := make([]godigest.Digest, 0, len(diffIDs)) for i := range diffIDs { result = append(result, godigest.Digest(diffIDs[i])) } return result }