Skip to content

Commit

Permalink
When copying containers, make sure tags are valid OCI tags
Browse files Browse the repository at this point in the history
Not everything that is a valid <version>-<release> is a valid tag
for an OCI registry. Coerce the tags that we push containers to to
be valid.

Signed-off-by: Owen W. Taylor <[email protected]>
  • Loading branch information
owtaylor authored and mattiaverga committed Oct 3, 2023
1 parent 1a9e8eb commit 05521e1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
31 changes: 30 additions & 1 deletion bodhi-server/bodhi/server/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,34 @@ def _get_build_repository_and_digest(build):
return repository, digest


def make_valid_container_tag(original_tag):
"""
Create a valid container tag from an arbitrary string.
Turns an arbitrary string (typically a koji 'version' or 'version-release' string),
into a valid OCI registry tag. This operation isn't reversable - multiple
tags might end up as the same thing. For example, 1.0_a5', '1.0^a5', and '1.0~a5'
all end up as '1.0_a5'.
Args:
original_tag: str: an arbitrary string
Returns:
str: a valid OCI registry tag based on original tag
"""
# https://github.com/opencontainers/distribution-spec/blob/main/spec.md#pulling-manifests
#
# Throughout this document, <reference> as a tag MUST be at most 128 characters in length
# and MUST match the following regular expression
#
# [a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}

# Replace invalid characters with _
new_tag = re.sub(r'^[^a-zA-Z0-9_]|[^a-zA-Z0-9._-]', '_', original_tag)

# Truncate to 128 characters
return new_tag[0:128]


def copy_container(build, destination_registry=None, destination_tag=None):
"""
Copy a ContainerBuild from the source registry to a destination registry under the given tag.
Expand All @@ -1186,7 +1214,8 @@ def copy_container(build, destination_registry=None, destination_tag=None):
repository, digest = _get_build_repository_and_digest(build)

source_url = _container_image_url(source_registry, repository, digest=digest)
destination_url = _container_image_url(destination_registry, repository, tag=destination_tag)
destination_url = _container_image_url(destination_registry, repository,
tag=make_valid_container_tag(destination_tag))

skopeo_cmd = [
config.get('skopeo.cmd'), 'copy', source_url, destination_url]
Expand Down
15 changes: 15 additions & 0 deletions bodhi-server/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,21 @@ def test_build_evr(self):
assert util.build_evr(build) == ('2', '1', '2.fc30')


class TestMakeValidContainerTag(base.BasePyTestCase):
"""Test the make_valid_container_tag() function."""

def test_valid_tag(self):
def E(input, result):
assert util.make_valid_container_tag(input) == result

# Invalid characters turned to _
E("%{foo}-%{bar}", "__foo_-__bar_")
# . is only invalid when leading
E(".f-.g", "_f-.g")
# truncate to 128 characters
E("x" * 129, "x" * 128)


@mock.patch('bodhi.server.util.cmd', autospec=True)
@mock.patch('bodhi.server.util._container_image_url',
new=lambda sr, r, tag=None, digest=None:
Expand Down
1 change: 1 addition & 0 deletions news/PR5497.bug
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix handling container tags which aren't valid OCI tags

0 comments on commit 05521e1

Please sign in to comment.