Pārlūkot izejas kodu

use custom config type for OCI v1.0

Signed-off-by: Milas Bowman <[email protected]>
Milas Bowman 1 gadu atpakaļ
vecāks
revīzija
9c29d2236d
1 mainītis faili ar 36 papildinājumiem un 7 dzēšanām
  1. 36 7
      internal/ocipush/push.go

+ 36 - 7
internal/ocipush/push.go

@@ -34,6 +34,28 @@ import (
 	v1 "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
+const (
+	// ComposeProjectArtifactType is the OCI 1.1-compliant artifact type value
+	// for the generated image manifest.
+	ComposeProjectArtifactType = "application/vnd.docker.compose.project"
+	// ComposeYAMLMediaType is the media type for each layer (Compose file)
+	// in the image manifest.
+	ComposeYAMLMediaType = "application/vnd.docker.compose.file+yaml"
+	// ComposeEmptyConfigMediaType is a media type used for the config descriptor
+	// when doing OCI 1.0-style pushes.
+	//
+	// The content is always `{}`, the same as a normal empty descriptor, but
+	// the specific media type allows clients to fall back to the config media
+	// type to recognize the manifest as a Compose project since the artifact
+	// type field is not available in OCI 1.0.
+	//
+	// This is based on guidance from the OCI 1.1 spec:
+	//	> Implementers note: artifacts have historically been created without
+	// 	> an artifactType field, and tooling to work with artifacts should
+	//	> fallback to the config.mediaType value.
+	ComposeEmptyConfigMediaType = "application/vnd.docker.compose.config.empty.v1+json"
+)
+
 // clientAuthStatusCodes are client (4xx) errors that are authentication
 // related.
 var clientAuthStatusCodes = []int{
@@ -49,7 +71,7 @@ type Pushable struct {
 
 func DescriptorForComposeFile(path string, content []byte) v1.Descriptor {
 	return v1.Descriptor{
-		MediaType: "application/vnd.docker.compose.file+yaml",
+		MediaType: ComposeYAMLMediaType,
 		Digest:    digest.FromString(string(content)),
 		Size:      int64(len(content)),
 		Annotations: map[string]string{
@@ -133,12 +155,19 @@ func generateManifest(layers []v1.Descriptor, ociCompat api.OCIVersion) ([]Pusha
 	var artifactType string
 	switch ociCompat {
 	case api.OCIVersion1_0:
-		configData, err := json.Marshal(v1.ImageConfig{})
-		if err != nil {
-			return nil, err
-		}
+		// "Content other than OCI container images MAY be packaged using the image manifest.
+		// When this is done, the config.mediaType value MUST be set to a value specific to
+		// the artifact type or the empty value."
+		// Source: https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidelines-for-artifact-usage
+		//
+		// The `ComposeEmptyConfigMediaType` is used specifically for this purpose:
+		// there is no config, and an empty descriptor is used for OCI 1.1 in
+		// conjunction with the `ArtifactType`, but for OCI 1.0 compatibility,
+		// tooling falls back to the config media type, so this is used to
+		// indicate that it's not a container image but custom content.
+		configData := []byte("{}")
 		config = v1.Descriptor{
-			MediaType: v1.MediaTypeImageConfig,
+			MediaType: ComposeEmptyConfigMediaType,
 			Digest:    digest.FromBytes(configData),
 			Size:      int64(len(configData)),
 		}
@@ -148,7 +177,7 @@ func generateManifest(layers []v1.Descriptor, ociCompat api.OCIVersion) ([]Pusha
 		toPush = append(toPush, Pushable{Descriptor: config, Data: configData})
 	case api.OCIVersion1_1:
 		config = v1.DescriptorEmptyJSON
-		artifactType = "application/vnd.docker.compose.project"
+		artifactType = ComposeProjectArtifactType
 		// N.B. the descriptor has the data embedded in it
 		toPush = append(toPush, Pushable{Descriptor: config, Data: nil})
 	default: