Skip to content

Commit

Permalink
Set layer media types consistently (#776)
Browse files Browse the repository at this point in the history
* Set layer media types consistently

* Also test that base image mediaType is not changed
  • Loading branch information
imjasonh authored Jul 21, 2022
1 parent 562039f commit 2f230b8
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 5 deletions.
25 changes: 20 additions & 5 deletions pkg/build/gobuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,20 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl

ref := newRef(refStr)

// Layers should be typed to match the underlying image, since some
// registries reject mixed-type layers.
var layerMediaType types.MediaType
mt, err := base.MediaType()
if err != nil {
return nil, err
}
switch mt {
case types.OCIManifestSchema1:
layerMediaType = types.OCILayer
case types.DockerManifestSchema2:
layerMediaType = types.DockerLayer
}

cf, err := base.ConfigFile()
if err != nil {
return nil, err
Expand Down Expand Up @@ -762,7 +776,7 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl
dataLayerBytes := dataLayerBuf.Bytes()
dataLayer, err := tarball.LayerFromOpener(func() (io.ReadCloser, error) {
return ioutil.NopCloser(bytes.NewBuffer(dataLayerBytes)), nil
}, tarball.WithCompressedCaching)
}, tarball.WithCompressedCaching, tarball.WithMediaType(layerMediaType))
if err != nil {
return nil, err
}
Expand All @@ -780,7 +794,7 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl
appPath := path.Join(appDir, appFilename(ref.Path()))

miss := func() (v1.Layer, error) {
return buildLayer(appPath, file, platform)
return buildLayer(appPath, file, platform, layerMediaType)
}

binaryLayer, err := g.cache.get(ctx, file, miss)
Expand All @@ -789,7 +803,8 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl
}

layers = append(layers, mutate.Addendum{
Layer: binaryLayer,
Layer: binaryLayer,
MediaType: layerMediaType,
History: v1.History{
Author: "ko",
Created: g.creationTime,
Expand Down Expand Up @@ -860,7 +875,7 @@ func (g *gobuild) buildOne(ctx context.Context, refStr string, base v1.Image, pl
return si, nil
}

func buildLayer(appPath, file string, platform *v1.Platform) (v1.Layer, error) {
func buildLayer(appPath, file string, platform *v1.Platform, layerMediaType types.MediaType) (v1.Layer, error) {
// Construct a tarball with the binary and produce a layer.
binaryLayerBuf, err := tarBinary(appPath, file, platform)
if err != nil {
Expand All @@ -872,7 +887,7 @@ func buildLayer(appPath, file string, platform *v1.Platform) (v1.Layer, error) {
}, tarball.WithCompressedCaching, tarball.WithEstargzOptions(estargz.WithPrioritizedFiles([]string{
// When using estargz, prioritize downloading the binary entrypoint.
appPath,
})))
})), tarball.WithMediaType(layerMediaType))
}

// Append appPath to the PATH environment variable, if it exists. Otherwise,
Expand Down
73 changes: 73 additions & 0 deletions pkg/build/gobuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1152,3 +1152,76 @@ func TestMatchesPlatformSpec(t *testing.T) {
}
}
}

func TestGoBuildConsistentMediaTypes(t *testing.T) {
for _, c := range []struct {
desc string
mediaType, layerMediaType types.MediaType
}{{
desc: "docker types",
mediaType: types.DockerManifestSchema2,
layerMediaType: types.DockerLayer,
}, {
desc: "oci types",
mediaType: types.OCIManifestSchema1,
layerMediaType: types.OCILayer,
}} {
t.Run(c.desc, func(t *testing.T) {
base := mutate.MediaType(empty.Image, c.mediaType)
l, err := random.Layer(10, c.layerMediaType)
if err != nil {
t.Fatal(err)
}
base, err = mutate.AppendLayers(base, l)
if err != nil {
t.Fatal(err)
}

ng, err := NewGo(
context.Background(),
"",
WithBaseImages(func(context.Context, string) (name.Reference, Result, error) { return baseRef, base, nil }),
withBuilder(writeTempFile),
withSBOMber(fauxSBOM),
)
if err != nil {
t.Fatalf("NewGo() = %v", err)
}

importpath := "github.com/google/ko"

result, err := ng.Build(context.Background(), StrictScheme+importpath)
if err != nil {
t.Fatalf("Build() = %v", err)
}

img, ok := result.(v1.Image)
if !ok {
t.Fatalf("Build() not an Image: %T", result)
}

ls, err := img.Layers()
if err != nil {
t.Fatalf("Layers() = %v", err)
}

for i, l := range ls {
gotMT, err := l.MediaType()
if err != nil {
t.Fatal(err)
}
if gotMT != c.layerMediaType {
t.Errorf("layer %d: got mediaType %q, want %q", i, gotMT, c.layerMediaType)
}
}

gotMT, err := img.MediaType()
if err != nil {
t.Fatal(err)
}
if gotMT != c.mediaType {
t.Errorf("got image mediaType %q, want %q", gotMT, c.layerMediaType)
}
})
}
}

0 comments on commit 2f230b8

Please sign in to comment.