Skip to content

Commit 719b151

Browse files
authored
Fix OCI manifest parser (#34797)
Do not parse the media type we don't know.
1 parent 4f32d32 commit 719b151

File tree

4 files changed

+34
-28
lines changed

4 files changed

+34
-28
lines changed

modules/packages/container/metadata.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package container
55

66
import (
7-
"errors"
87
"fmt"
98
"io"
109
"strings"
@@ -72,20 +71,39 @@ type Manifest struct {
7271
Size int64 `json:"size"`
7372
}
7473

74+
func IsMediaTypeValid(mt string) bool {
75+
return strings.HasPrefix(mt, "application/vnd.docker.") || strings.HasPrefix(mt, "application/vnd.oci.")
76+
}
77+
78+
func IsMediaTypeImageManifest(mt string) bool {
79+
return strings.EqualFold(mt, oci.MediaTypeImageManifest) || strings.EqualFold(mt, "application/vnd.docker.distribution.manifest.v2+json")
80+
}
81+
82+
func IsMediaTypeImageIndex(mt string) bool {
83+
return strings.EqualFold(mt, oci.MediaTypeImageIndex) || strings.EqualFold(mt, "application/vnd.docker.distribution.manifest.list.v2+json")
84+
}
85+
7586
// ParseImageConfig parses the metadata of an image config
76-
func ParseImageConfig(mt string, r io.Reader) (*Metadata, error) {
77-
if strings.EqualFold(mt, helm.ConfigMediaType) {
87+
func ParseImageConfig(mediaType string, r io.Reader) (*Metadata, error) {
88+
if strings.EqualFold(mediaType, helm.ConfigMediaType) {
7889
return parseHelmConfig(r)
7990
}
8091

8192
// fallback to OCI Image Config
82-
return parseOCIImageConfig(r)
93+
// FIXME: this fallback is not right, we should strictly check the media type in the future
94+
metadata, err := parseOCIImageConfig(r)
95+
if err != nil {
96+
if !IsMediaTypeImageManifest(mediaType) {
97+
return &Metadata{Platform: "unknown/unknown"}, nil
98+
}
99+
return nil, err
100+
}
101+
return metadata, nil
83102
}
84103

85104
func parseOCIImageConfig(r io.Reader) (*Metadata, error) {
86105
var image oci.Image
87-
// EOF means empty input, still use the default data
88-
if err := json.NewDecoder(r).Decode(&image); err != nil && !errors.Is(err, io.EOF) {
106+
if err := json.NewDecoder(r).Decode(&image); err != nil {
89107
return nil, err
90108
}
91109

modules/packages/container/metadata_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ func TestParseImageConfig(t *testing.T) {
5959
assert.ElementsMatch(t, []string{author}, metadata.Authors)
6060
assert.Equal(t, projectURL, metadata.ProjectURL)
6161
assert.Equal(t, repositoryURL, metadata.RepositoryURL)
62-
}
6362

64-
func TestParseOCIImageConfig(t *testing.T) {
65-
metadata, err := parseOCIImageConfig(strings.NewReader(""))
63+
metadata, err = ParseImageConfig("anything-unknown", strings.NewReader(""))
6664
require.NoError(t, err)
67-
assert.Equal(t, &Metadata{Type: TypeOCI, Platform: DefaultPlatform, ImageLayers: []string{}}, metadata)
65+
assert.Equal(t, &Metadata{Platform: "unknown/unknown"}, metadata)
6866
}

routers/api/packages/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,8 @@ func ContainerRoutes() *web.Router {
693693
&container.Auth{},
694694
})
695695

696+
// TODO: Content Discovery / References (not implemented yet)
697+
696698
r.Get("", container.ReqContainerAccess, container.DetermineSupport)
697699
r.Group("/token", func() {
698700
r.Get("", container.Authenticate)

routers/api/packages/container/manifest.go

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,6 @@ import (
2929
oci "github.com/opencontainers/image-spec/specs-go/v1"
3030
)
3131

32-
func isMediaTypeValid(mt string) bool {
33-
return strings.HasPrefix(mt, "application/vnd.docker.") || strings.HasPrefix(mt, "application/vnd.oci.")
34-
}
35-
36-
func isMediaTypeImageManifest(mt string) bool {
37-
return strings.EqualFold(mt, oci.MediaTypeImageManifest) || strings.EqualFold(mt, "application/vnd.docker.distribution.manifest.v2+json")
38-
}
39-
40-
func isMediaTypeImageIndex(mt string) bool {
41-
return strings.EqualFold(mt, oci.MediaTypeImageIndex) || strings.EqualFold(mt, "application/vnd.docker.distribution.manifest.list.v2+json")
42-
}
43-
4432
// manifestCreationInfo describes a manifest to create
4533
type manifestCreationInfo struct {
4634
MediaType string
@@ -66,16 +54,16 @@ func processManifest(ctx context.Context, mci *manifestCreationInfo, buf *packag
6654
return "", err
6755
}
6856

69-
if !isMediaTypeValid(mci.MediaType) {
57+
if !container_module.IsMediaTypeValid(mci.MediaType) {
7058
mci.MediaType = index.MediaType
71-
if !isMediaTypeValid(mci.MediaType) {
59+
if !container_module.IsMediaTypeValid(mci.MediaType) {
7260
return "", errManifestInvalid.WithMessage("MediaType not recognized")
7361
}
7462
}
7563

76-
if isMediaTypeImageManifest(mci.MediaType) {
64+
if container_module.IsMediaTypeImageManifest(mci.MediaType) {
7765
return processOciImageManifest(ctx, mci, buf)
78-
} else if isMediaTypeImageIndex(mci.MediaType) {
66+
} else if container_module.IsMediaTypeImageIndex(mci.MediaType) {
7967
return processOciImageIndex(ctx, mci, buf)
8068
}
8169
return "", errManifestInvalid
@@ -201,7 +189,7 @@ func processOciImageIndex(ctx context.Context, mci *manifestCreationInfo, buf *p
201189
}
202190

203191
for _, manifest := range index.Manifests {
204-
if !isMediaTypeImageManifest(manifest.MediaType) {
192+
if !container_module.IsMediaTypeImageManifest(manifest.MediaType) {
205193
return errManifestInvalid
206194
}
207195

@@ -336,7 +324,7 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
336324
return nil, err
337325
}
338326

339-
if isMediaTypeImageIndex(mci.MediaType) {
327+
if container_module.IsMediaTypeImageIndex(mci.MediaType) {
340328
if pv.CreatedUnix.AsTime().Before(time.Now().Add(-24 * time.Hour)) {
341329
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
342330
return nil, err

0 commit comments

Comments
 (0)