Skip to content

[Feature]: digest support for OCI transport #17308

Open
@mwopfner

Description

@mwopfner

Feature request description

Using digest in the oci transport currently does not work (podman pull oci:/tmp/local/alpine@sha256:3d426b0bfc361d6e8303f51459f17782b219dece42a1c7fe463b6014b189c86d) because the parsing only handles the :tag notation.
From the documentation (https://github.com/containers/image/blob/main/docs/containers-transports.5.md#ocipathreference) I'm not sure if this is desired behavior or a bug.
I looked into the problem and found that it is not much needed to support it (see patch below). I'm not sure if this is the right place to request the feature, because all changes have to be made in vendor libs.

Suggest potential solution

I created a path oci_digest_support.txt and tested it on my system:

diff --git i/vendor/github.com/containers/common/libimage/pull.go w/vendor/github.com/containers/common/libimage/pull.go
index 51712bb3b..70703e1d4 100644
--- i/vendor/github.com/containers/common/libimage/pull.go
+++ w/vendor/github.com/containers/common/libimage/pull.go
@@ -227,7 +227,11 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference,
 		storageName = imageName
 
 	case ociTransport.Transport.Name():
-		split := strings.SplitN(ref.StringWithinTransport(), ":", 2)
+		split := strings.SplitN(ref.StringWithinTransport(), "@", 2)
+
+		if len(split) == 1 {
+			split = strings.SplitN(ref.StringWithinTransport(), ":", 2)
+		}
 		storageName = toLocalImageName(split[0])
 		imageName = storageName
 
diff --git i/vendor/github.com/containers/image/v5/oci/internal/oci_util.go w/vendor/github.com/containers/image/v5/oci/internal/oci_util.go
index 148bc12fa..6849459f5 100644
--- i/vendor/github.com/containers/image/v5/oci/internal/oci_util.go
+++ w/vendor/github.com/containers/image/v5/oci/internal/oci_util.go
@@ -58,7 +58,14 @@ func splitPathAndImageWindows(reference string) (string, string) {
 }
 
 func splitPathAndImageNonWindows(reference string) (string, string) {
-	sep := strings.SplitN(reference, ":", 2)
+
+	sep := strings.SplitN(reference, "@", 2)
+
+	if len(sep) == 1 {
+		sep = strings.SplitN(reference, ":", 2)
+	}
+
+	// sep := strings.SplitN(reference, ":", 2)
 	path := sep[0]
 
 	var image string
diff --git i/vendor/github.com/containers/image/v5/oci/layout/oci_transport.go w/vendor/github.com/containers/image/v5/oci/layout/oci_transport.go
index be22bed6d..527cadbb8 100644
--- i/vendor/github.com/containers/image/v5/oci/layout/oci_transport.go
+++ w/vendor/github.com/containers/image/v5/oci/layout/oci_transport.go
@@ -103,7 +103,15 @@ func (ref ociReference) Transport() types.ImageTransport {
 // e.g. default attribute values omitted by the user may be filled in in the return value, or vice versa.
 // WARNING: Do not use the return value
[oci_digest_support.txt](https://github.com/containers/podman/files/10555452/oci_digest_support.txt)
 in the UI to describe an image, it does not contain the Transport().Name() prefix.
 func (ref ociReference) StringWithinTransport() string {
-	return fmt.Sprintf("%s:%s", ref.dir, ref.image)
+
+	// if we use a digest for the image
+	_, err := digest.Parse(ref.image)
+	if err == nil {
+		return fmt.Sprintf("%s@%s", ref.dir, ref.image)
+	} else {
+		// if we use a normal tag for the image
+		return fmt.Sprintf("%s:%s", ref.dir, ref.image)
+	}
 }
 
 // DockerReference returns a Docker reference associated with this reference
@@ -194,13 +202,26 @@ func (ref ociReference) getManifestDescriptor() (imgspecv1.Descriptor, error) {
 			if md.MediaType != imgspecv1.MediaTypeImageManifest && md.MediaType != imgspecv1.MediaTypeImageIndex {
 				continue
 			}
-			refName, ok := md.Annotations[imgspecv1.AnnotationRefName]
-			if !ok {
-				continue
-			}
-			if refName == ref.image {
-				d = &md
-				break
+
+			// if we use a digest for the image
+			digest, err := digest.Parse(ref.image)
+			if err == nil {
+				if md.Digest == digest {
+					d = &md
+					break
+				} else {
+					continue
+				}
+			} else {
+				// if we use a tag
+				refName, ok := md.Annotations[imgspecv1.AnnotationRefName]
+				if !ok {
+					continue
+				}
+				if refName == ref.image {
+					d = &md
+					break
+				}
 			}
 		}
 	}

Have you considered any alternatives?

I considered using :tag but i don't have any tags. I only have digests.

Additional context

The version section of podman info

version:
  APIVersion: 4.3.1
  Built: 1668026638
  BuiltTime: Wed Nov  9 20:43:58 2022
  GitCommit: 814b7b003cc630bf6ab188274706c383f9fb9915-dirty
  GoVersion: go1.17.13
  Os: linux
  OsArch: linux/amd64
  Version: 4.3.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/featureCategorizes issue or PR as related to a new feature.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions