From c7f5979dd445d26139faab2634e1c92717f919a3 Mon Sep 17 00:00:00 2001
From: Tonis Tiigi <tonistiigi@gmail.com>
Date: Sun, 11 Oct 2020 22:41:08 -0700
Subject: [PATCH] exporter: avoid descriptor annotations on docker manifests

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
---
 exporter/containerimage/export.go | 19 ++++++++++++++++++-
 exporter/containerimage/writer.go | 13 +++++++++++++
 util/push/push.go                 | 20 +++++++++++++++++---
 3 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/exporter/containerimage/export.go b/exporter/containerimage/export.go
index 26c64748ee82..5dd83785dbec 100644
--- a/exporter/containerimage/export.go
+++ b/exporter/containerimage/export.go
@@ -239,6 +239,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
 				}
 			}
 			if e.push {
+				annotations := map[digest.Digest]map[string]string{}
 				mprovider := contentutil.NewMultiProvider(e.opt.ImageWriter.ContentStore())
 				if src.Ref != nil {
 					remote, err := src.Ref.GetRemote(ctx, false, e.layerCompression)
@@ -247,6 +248,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
 					}
 					for _, desc := range remote.Descriptors {
 						mprovider.Add(desc.Digest, remote.Provider)
+						addAnnotations(annotations, desc)
 					}
 				}
 				if len(src.Refs) > 0 {
@@ -257,11 +259,12 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
 						}
 						for _, desc := range remote.Descriptors {
 							mprovider.Add(desc.Digest, remote.Provider)
+							addAnnotations(annotations, desc)
 						}
 					}
 				}
 
-				if err := push.Push(ctx, e.opt.SessionManager, sessionID, mprovider, e.opt.ImageWriter.ContentStore(), desc.Digest, targetName, e.insecure, e.opt.RegistryHosts, e.pushByDigest); err != nil {
+				if err := push.Push(ctx, e.opt.SessionManager, sessionID, mprovider, e.opt.ImageWriter.ContentStore(), desc.Digest, targetName, e.insecure, e.opt.RegistryHosts, e.pushByDigest, annotations); err != nil {
 					return nil, err
 				}
 			}
@@ -357,3 +360,17 @@ func getLayers(ctx context.Context, descs []ocispec.Descriptor, manifest ocispec
 	}
 	return layers, nil
 }
+
+func addAnnotations(m map[digest.Digest]map[string]string, desc ocispec.Descriptor) {
+	if desc.Annotations == nil {
+		return
+	}
+	a, ok := m[desc.Digest]
+	if !ok {
+		m[desc.Digest] = desc.Annotations
+		return
+	}
+	for k, v := range desc.Annotations {
+		a[k] = v
+	}
+}
diff --git a/exporter/containerimage/writer.go b/exporter/containerimage/writer.go
index 589ee1201f50..05a8b90faec5 100644
--- a/exporter/containerimage/writer.go
+++ b/exporter/containerimage/writer.go
@@ -5,6 +5,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"strings"
 	"time"
 
 	"github.com/containerd/containerd/content"
@@ -235,6 +236,18 @@ func (ic *ImageWriter) commitDistributionManifest(ctx context.Context, ref cache
 	}
 
 	for i, desc := range remote.Descriptors {
+		// oci supports annotations but don't export internal annotations
+		if oci {
+			delete(desc.Annotations, "containerd.io/uncompressed")
+			delete(desc.Annotations, "buildkit/createdat")
+			for k := range desc.Annotations {
+				if strings.HasPrefix(k, "containerd.io/distribution.source.") {
+					delete(desc.Annotations, k)
+				}
+			}
+		} else {
+			desc.Annotations = nil
+		}
 		mfst.Layers = append(mfst.Layers, desc)
 		labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = desc.Digest.String()
 	}
diff --git a/util/push/push.go b/util/push/push.go
index d553974d4e09..e73caf8b23e2 100644
--- a/util/push/push.go
+++ b/util/push/push.go
@@ -26,7 +26,7 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
-func Push(ctx context.Context, sm *session.Manager, sid string, provider content.Provider, manager content.Manager, dgst digest.Digest, ref string, insecure bool, hosts docker.RegistryHosts, byDigest bool) error {
+func Push(ctx context.Context, sm *session.Manager, sid string, provider content.Provider, manager content.Manager, dgst digest.Digest, ref string, insecure bool, hosts docker.RegistryHosts, byDigest bool, annotations map[digest.Digest]map[string]string) error {
 	desc := ocispec.Descriptor{
 		Digest: dgst,
 	}
@@ -87,7 +87,7 @@ func Push(ctx context.Context, sm *session.Manager, sid string, provider content
 	}
 
 	handlers := append([]images.Handler{},
-		images.HandlerFunc(annotateDistributionSourceHandler(manager, childrenHandler(provider))),
+		images.HandlerFunc(annotateDistributionSourceHandler(manager, annotations, childrenHandler(provider))),
 		filterHandler,
 		dedupeHandler(pushUpdateSourceHandler),
 	)
@@ -121,7 +121,7 @@ func Push(ctx context.Context, sm *session.Manager, sid string, provider content
 	return mfstDone(nil)
 }
 
-func annotateDistributionSourceHandler(manager content.Manager, f images.HandlerFunc) func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+func annotateDistributionSourceHandler(manager content.Manager, annotations map[digest.Digest]map[string]string, f images.HandlerFunc) func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
 	return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
 		children, err := f(ctx, desc)
 		if err != nil {
@@ -138,6 +138,20 @@ func annotateDistributionSourceHandler(manager content.Manager, f images.Handler
 
 		for i := range children {
 			child := children[i]
+
+			if m, ok := annotations[child.Digest]; ok {
+				for k, v := range m {
+					if !strings.HasPrefix(k, "containerd.io/distribution.source.") {
+						continue
+					}
+					if child.Annotations == nil {
+						child.Annotations = map[string]string{}
+					}
+					child.Annotations[k] = v
+				}
+			}
+			children[i] = child
+
 			info, err := manager.Info(ctx, child.Digest)
 			if errors.Is(err, errdefs.ErrNotFound) {
 				continue