From 3082ce6a22b1c1356da533a26225150298264a4b Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 3 Nov 2023 12:50:30 +0100 Subject: oci parsing: make image name case insensitive (#40858) --- lib/spack/spack/oci/image.py | 13 ++++++++++--- lib/spack/spack/test/oci/image.py | 4 ++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/spack/spack/oci/image.py b/lib/spack/spack/oci/image.py index 1954bf013d..b61591b7be 100644 --- a/lib/spack/spack/oci/image.py +++ b/lib/spack/spack/oci/image.py @@ -9,8 +9,10 @@ from typing import Optional, Union import spack.spec -# all the building blocks -alphanumeric = r"[a-z0-9]+" +# notice: Docker is more strict (no uppercase allowed). We parse image names *with* uppercase +# and normalize, so: example.com/Organization/Name -> example.com/organization/name. Tags are +# case sensitive though. +alphanumeric_with_uppercase = r"[a-zA-Z0-9]+" separator = r"(?:[._]|__|[-]+)" localhost = r"localhost" domainNameComponent = r"(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])" @@ -25,7 +27,7 @@ host = rf"(?:{domainName}|{ipv6address})" domainAndPort = rf"{host}{optionalPort}" # image name -pathComponent = rf"{alphanumeric}(?:{separator}{alphanumeric})*" +pathComponent = rf"{alphanumeric_with_uppercase}(?:{separator}{alphanumeric_with_uppercase})*" remoteName = rf"{pathComponent}(?:\/{pathComponent})*" namePat = rf"(?:{domainAndPort}\/)?{remoteName}" @@ -130,6 +132,11 @@ class ImageReference: name = f"{domain}/{name}" domain = "index.docker.io" + # Lowercase the image name. This is enforced by Docker, although the OCI spec isn't clear? + # We do this anyways, cause for example in Github Actions the / + # part can have uppercase, and may be interpolated when specifying the relevant OCI image. + name = name.lower() + if not tag: tag = "latest" diff --git a/lib/spack/spack/test/oci/image.py b/lib/spack/spack/test/oci/image.py index 17899d1f43..b074cc679a 100644 --- a/lib/spack/spack/test/oci/image.py +++ b/lib/spack/spack/test/oci/image.py @@ -34,6 +34,10 @@ from spack.oci.image import Digest, ImageReference, default_tag, tag ("myname:1234/myimage:abc", ("myname:1234", "myimage", "abc", None)), ("localhost/myimage:abc", ("localhost", "myimage", "abc", None)), ("localhost:1234/myimage:abc", ("localhost:1234", "myimage", "abc", None)), + ( + "example.com/UPPERCASE/lowercase:AbC", + ("example.com", "uppercase/lowercase", "AbC", None), + ), ], ) def test_name_parsing(image_ref, expected): -- cgit v1.2.3-70-g09d2