← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~twom/launchpad:oci-policy-enforce-branch-format-on-api into launchpad:master

 

Tom Wardill has proposed merging ~twom/launchpad:oci-policy-enforce-branch-format-on-api into launchpad:master.

Commit message:
Enforce the ROCKs branch format at the API level

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~twom/launchpad/+git/launchpad/+merge/402208

Prevent creating a new OCIRecipe with an invalid branch format name at all, rather than just via the UI.

* Make sure we get a nice HTTP error on the API, the UI has it's own error handling for that case.
* Reuse the existing validator so it's centralised.
* Update the tests to use the new format
* Allow existing recipes with the old format to still function
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~twom/launchpad:oci-policy-enforce-branch-format-on-api into launchpad:master.
diff --git a/lib/lp/oci/browser/tests/test_ocirecipe.py b/lib/lp/oci/browser/tests/test_ocirecipe.py
index 2f46c22..9dc3fc3 100644
--- a/lib/lp/oci/browser/tests/test_ocirecipe.py
+++ b/lib/lp/oci/browser/tests/test_ocirecipe.py
@@ -13,7 +13,6 @@ from datetime import (
     timedelta,
     )
 from operator import attrgetter
-import re
 
 from fixtures import FakeLogger
 import pytz
@@ -651,7 +650,8 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
     def test_edit_recipe(self):
         oci_project = self.factory.makeOCIProject()
         oci_project_display = oci_project.display_name
-        [old_git_ref] = self.factory.makeGitRefs()
+        [old_git_ref] = self.factory.makeGitRefs(
+            paths=['refs/heads/v1.0-20.04'])
         recipe = self.factory.makeOCIRecipe(
             registrant=self.person, owner=self.person,
             oci_project=oci_project, git_ref=old_git_ref)
@@ -696,7 +696,8 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
     def test_edit_recipe_invalid_branch(self):
         oci_project = self.factory.makeOCIProject()
         repository = self.factory.makeGitRepository()
-        [old_git_ref] = self.factory.makeGitRefs(repository=repository)
+        [old_git_ref] = self.factory.makeGitRefs(
+            paths=['refs/heads/v1.0-20.04'], repository=repository)
         recipe = self.factory.makeOCIRecipe(
             registrant=self.person, owner=self.person,
             oci_project=oci_project, git_ref=old_git_ref)
@@ -966,7 +967,8 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
         self.setUpDistroSeries()
         repo = self.factory.makeGitRepository(
             owner=self.person, registrant=self.person)
-        [git_ref] = self.factory.makeGitRefs(repository=repo)
+        [git_ref] = self.factory.makeGitRefs(
+            repository=repo, paths=['refs/heads/v1.0-20.04'])
         oci_project = self.factory.makeOCIProject(
             registrant=self.person, pillar=self.distribution)
         recipe = self.factory.makeOCIRecipe(
@@ -986,7 +988,8 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
         self.setUpDistroSeries()
         oci_project = self.factory.makeOCIProject(
             registrant=self.person, pillar=self.distribution)
-        [random_git_ref] = self.factory.makeGitRefs()
+        [random_git_ref] = self.factory.makeGitRefs(
+            paths=['refs/heads/v1.0-20.04'])
         recipe = self.factory.makeOCIRecipe(
             registrant=self.person, owner=self.person, oci_project=oci_project,
             git_ref=random_git_ref)
@@ -1018,7 +1021,8 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
             name=oci_project.name,
             target=oci_project, owner=self.person, registrant=self.person)
 
-        [git_ref] = self.factory.makeGitRefs(repository=default_repo)
+        [git_ref] = self.factory.makeGitRefs(
+            repository=default_repo, paths=['refs/heads/v1.0-20.04'])
         recipe = self.factory.makeOCIRecipe(
             registrant=self.person, owner=self.person, oci_project=oci_project,
             git_ref=git_ref)
@@ -1035,7 +1039,7 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
         oci_project = self.factory.makeOCIProject(
             registrant=self.person, pillar=self.distribution)
 
-        [git_ref] = self.factory.makeGitRefs()
+        [git_ref] = self.factory.makeGitRefs(paths=['refs/heads/v1.0-20.04'])
         recipe = self.factory.makeOCIRecipe(
             registrant=self.person, owner=self.person, oci_project=oci_project,
             git_ref=git_ref)
@@ -1290,7 +1294,7 @@ class TestOCIRecipeView(BaseTestOCIRecipeView):
         oci_project_display = oci_project.display_name
         [ref] = self.factory.makeGitRefs(
             owner=self.person, target=self.person, name="recipe-repository",
-            paths=["refs/heads/master"])
+            paths=["refs/heads/v1.0-20.04"])
         recipe = self.makeRecipe(
             processor_names=["amd64", "386"],
             build_file="Dockerfile", git_ref=ref,
@@ -1320,7 +1324,7 @@ class TestOCIRecipeView(BaseTestOCIRecipeView):
             OCI recipe information
             Owner: Test Person
             OCI project: %s
-            Source: ~test-person/\\+git/recipe-repository:master
+            Source: ~test-person/\\+git/recipe-repository:v1.0-20.04
             Build file path: Dockerfile
             Build context directory: %s
             Build schedule: Built on request
@@ -1385,11 +1389,10 @@ class TestOCIRecipeView(BaseTestOCIRecipeView):
     def test_index_with_build_args(self):
         oci_project = self.factory.makeOCIProject(
             pillar=self.distroseries.distribution)
-        oci_project_name = oci_project.name
         oci_project_display = oci_project.display_name
         [ref] = self.factory.makeGitRefs(
             owner=self.person, target=self.person, name="recipe-repository",
-            paths=["refs/heads/master"])
+            paths=["refs/heads/v1.0-20.04"])
         recipe = self.makeOCIRecipe(
             oci_project=oci_project, git_ref=ref, build_file="Dockerfile",
             build_args={"VAR1": "123", "VAR2": "XXX"})
@@ -1403,7 +1406,7 @@ class TestOCIRecipeView(BaseTestOCIRecipeView):
             OCI recipe information
             Owner: Test Person
             OCI project: %s
-            Source: ~test-person/\\+git/recipe-repository:master
+            Source: ~test-person/\\+git/recipe-repository:v1.0-20.04
             Build file path: Dockerfile
             Build context directory: %s
             Build schedule: Built on request
@@ -1429,11 +1432,10 @@ class TestOCIRecipeView(BaseTestOCIRecipeView):
     def test_index_for_subscriber_without_git_repo_access(self):
         oci_project = self.factory.makeOCIProject(
             pillar=self.distroseries.distribution)
-        oci_project_name = oci_project.name
         oci_project_display = oci_project.display_name
         [ref] = self.factory.makeGitRefs(
             owner=self.person, target=self.person, name="recipe-repository",
-            paths=["refs/heads/master"],
+            paths=["refs/heads/v1.0-20.04"],
             information_type=InformationType.PRIVATESECURITY)
         recipe = self.makeOCIRecipe(
             oci_project=oci_project, git_ref=ref, build_file="Dockerfile",
@@ -1514,7 +1516,7 @@ class TestOCIRecipeView(BaseTestOCIRecipeView):
             pillar=self.distroseries.distribution)
         [ref] = self.factory.makeGitRefs(
             owner=self.person, target=self.person, name="recipe-repository",
-            paths=["refs/heads/master"])
+            paths=["refs/heads/v1.0-20.04"])
         recipe = self.makeRecipe(
             processor_names=["amd64", "386"],
             build_file="Dockerfile", git_ref=ref,
diff --git a/lib/lp/oci/browser/tests/test_ocirecipesubscription.py b/lib/lp/oci/browser/tests/test_ocirecipesubscription.py
index 7f23b06..1f60710 100644
--- a/lib/lp/oci/browser/tests/test_ocirecipesubscription.py
+++ b/lib/lp/oci/browser/tests/test_ocirecipesubscription.py
@@ -42,7 +42,7 @@ class BaseTestOCIRecipeView(OCIConfigHelperMixin, BrowserTestCase):
     def makeOCIRecipe(self, oci_project=None, **kwargs):
         [ref] = self.factory.makeGitRefs(
             owner=self.person, target=self.person, name="recipe-repository",
-            paths=["refs/heads/master"])
+            paths=["refs/heads/v1.0-20.04"])
         if oci_project is None:
             project = self.factory.makeProduct(
                 owner=self.person, registrant=self.person)
diff --git a/lib/lp/oci/interfaces/ocirecipe.py b/lib/lp/oci/interfaces/ocirecipe.py
index bf83392..2c1179d 100644
--- a/lib/lp/oci/interfaces/ocirecipe.py
+++ b/lib/lp/oci/interfaces/ocirecipe.py
@@ -19,6 +19,7 @@ __all__ = [
     'NoSuchOCIRecipe',
     'OCIRecipeBuildAlreadyPending',
     'OCIRecipeFeatureDisabled',
+    'OCIRecipeBranchHasInvalidFormat',
     'OCIRecipeNotOwner',
     'OCIRecipePrivacyMismatch',
     'OCI_RECIPE_ALLOW_CREATE',
@@ -164,6 +165,15 @@ class OCIRecipePrivacyMismatch(Exception):
             "OCI recipe contains private information and cannot be public.")
 
 
+@error_status(http_client.BAD_REQUEST)
+class OCIRecipeBranchHasInvalidFormat(Exception):
+    """The branch name for the OCI recipe does not match the correct format."""
+
+    def __init__(self):
+        super(OCIRecipeBranchHasInvalidFormat, self).__init__(
+            "The branch name for the OCI recipe does not "
+            "match the correct format.")
+
 @exported_as_webservice_entry(
     publish_web_link=True, as_of="devel",
     singular_name="oci_recipe_build_request")
diff --git a/lib/lp/oci/model/ocirecipe.py b/lib/lp/oci/model/ocirecipe.py
index adcbd6c..c16be3e 100644
--- a/lib/lp/oci/model/ocirecipe.py
+++ b/lib/lp/oci/model/ocirecipe.py
@@ -87,6 +87,7 @@ from lp.oci.interfaces.ocirecipe import (
     OCI_RECIPE_BUILD_DISTRIBUTION,
     OCIRecipeBuildAlreadyPending,
     OCIRecipeFeatureDisabled,
+    OCIRecipeBranchHasInvalidFormat,
     OCIRecipeNotOwner,
     OCIRecipePrivacyMismatch,
     UsingDistributionCredentials,
@@ -841,6 +842,9 @@ class OCIRecipeSet:
         if self.exists(owner, oci_project, name):
             raise DuplicateOCIRecipeName
 
+        if not validate_oci_branch_name(git_ref.name):
+            raise OCIRecipeBranchHasInvalidFormat
+
         if build_path is None:
             build_path = "."
 
diff --git a/lib/lp/oci/tests/test_ocirecipe.py b/lib/lp/oci/tests/test_ocirecipe.py
index 8cd3705..95e30a8 100644
--- a/lib/lp/oci/tests/test_ocirecipe.py
+++ b/lib/lp/oci/tests/test_ocirecipe.py
@@ -848,7 +848,8 @@ class TestOCIRecipe(OCIConfigHelperMixin, TestCaseWithFactory):
 
         [private_git_ref] = self.factory.makeGitRefs(
             target=pillar, owner=owner,
-            information_type=InformationType.PROPRIETARY)
+            information_type=InformationType.PROPRIETARY,
+            paths=['refs/heads/v1.0-20.04'])
 
         private_recipe = self.factory.makeOCIRecipe(
             owner=private_team, registrant=owner,
@@ -1092,7 +1093,8 @@ class TestOCIRecipeProcessors(TestCaseWithFactory):
         recipe = getUtility(IOCIRecipeSet).new(
             name=self.factory.getUniqueUnicode(), registrant=owner,
             owner=owner, oci_project=oci_project,
-            git_ref=self.factory.makeGitRefs()[0],
+            git_ref=self.factory.makeGitRefs(
+                paths=['refs/heads/v1.0-20.04'])[0],
             build_file=self.factory.getUniqueUnicode())
         self.assertContentEqual(
             ["386", "amd64", "hppa", "default"],
@@ -1106,7 +1108,8 @@ class TestOCIRecipeProcessors(TestCaseWithFactory):
         recipe = getUtility(IOCIRecipeSet).new(
             name=self.factory.getUniqueUnicode(), registrant=owner,
             owner=owner, oci_project=oci_project,
-            git_ref=self.factory.makeGitRefs()[0],
+            git_ref=self.factory.makeGitRefs(
+                paths=['refs/heads/v1.0-20.04'])[0],
             build_file=self.factory.getUniqueUnicode(), processors=[self.arm])
         self.assertContentEqual(
             ["arm"], [processor.name for processor in recipe.processors])
@@ -1164,20 +1167,25 @@ class TestOCIRecipeProcessors(TestCaseWithFactory):
         self.assertTrue(recipe.is_valid_branch_format)
 
     def test_valid_branch_format_invalid(self):
+        # We can't use OCIRecipeSet.new with an invalid path
+        # so create a valid one, then change it after
+        recipe = self.factory.makeOCIRecipe()
         [git_ref] = self.factory.makeGitRefs(paths=["refs/heads/v1.0-foo"])
-        recipe = self.factory.makeOCIRecipe(git_ref=git_ref)
+        recipe.git_ref = git_ref
         self.assertFalse(recipe.is_valid_branch_format)
 
     def test_valid_branch_format_invalid_uses_risk(self):
         for risk in ["stable", "candidate", "beta", "edge"]:
+            recipe = self.factory.makeOCIRecipe()
             path = "refs/heads/{}-20.04".format(risk)
             [git_ref] = self.factory.makeGitRefs(paths=[path])
-            recipe = self.factory.makeOCIRecipe(git_ref=git_ref)
+            recipe.git_ref = git_ref
             self.assertFalse(recipe.is_valid_branch_format)
 
     def test_valid_branch_format_invalid_with_slash(self):
+        recipe = self.factory.makeOCIRecipe()
         [git_ref] = self.factory.makeGitRefs(paths=["refs/heads/v1.0/bar-foo"])
-        recipe = self.factory.makeOCIRecipe(git_ref=git_ref)
+        recipe.git_ref = git_ref
         self.assertFalse(recipe.is_valid_branch_format)
 
 
@@ -1198,7 +1206,8 @@ class TestOCIRecipeSet(TestCaseWithFactory):
         registrant = self.factory.makePerson()
         owner = self.factory.makeTeam(members=[registrant])
         oci_project = self.factory.makeOCIProject()
-        [git_ref] = self.factory.makeGitRefs()
+        [git_ref] = self.factory.makeGitRefs(
+                paths=['refs/heads/v1.0-20.04'])
         target = getUtility(IOCIRecipeSet).new(
             name='a name',
             registrant=registrant,
@@ -1251,7 +1260,8 @@ class TestOCIRecipeSet(TestCaseWithFactory):
         owner = self.factory.makePerson()
         oci_project = self.factory.makeOCIProject()
         recipe_set = getUtility(IOCIRecipeSet)
-        [git_ref] = self.factory.makeGitRefs()
+        [git_ref]=self.factory.makeGitRefs(
+                paths=['refs/heads/v1.0-20.04']),
         self.assertRaises(
             NoSourceForOCIRecipe,
             recipe_set.new,
@@ -1295,7 +1305,9 @@ class TestOCIRecipeSet(TestCaseWithFactory):
         oci_recipes = []
         for repository in repositories:
             for i in range(2):
-                [ref] = self.factory.makeGitRefs(repository=repository)
+                [ref] = self.factory.makeGitRefs(
+                    repository=repository,
+                    paths=['refs/heads/v1.0-20.04'])
                 oci_recipes.append(self.factory.makeOCIRecipe(git_ref=ref))
         oci_recipe_set = getUtility(IOCIRecipeSet)
         self.assertContentEqual(
@@ -1311,7 +1323,10 @@ class TestOCIRecipeSet(TestCaseWithFactory):
         oci_recipes = []
         for repository in repositories:
             for i in range(3):
-                [ref] = self.factory.makeGitRefs(repository=repository)
+                [ref] = self.factory.makeGitRefs(
+                    repository=repository,
+                    # Needs a unique path, otherwise we can't search for it.
+                    paths=['refs/heads/v1.{}-20.04'.format(str(i))])
                 oci_recipes.append(self.factory.makeOCIRecipe(git_ref=ref))
         oci_recipe_set = getUtility(IOCIRecipeSet)
         self.assertContentEqual(
@@ -1334,7 +1349,9 @@ class TestOCIRecipeSet(TestCaseWithFactory):
         refs = []
         for repository in repositories:
             for i in range(2):
-                [ref] = self.factory.makeGitRefs(repository=repository)
+                [ref] = self.factory.makeGitRefs(
+                    repository=repository,
+                    paths=['refs/heads/v1.0-20.04'])
                 paths.append(ref.path)
                 refs.append(ref)
                 oci_recipes.append(self.factory.makeOCIRecipe(
@@ -1458,7 +1475,8 @@ class TestOCIRecipeWebservice(OCIConfigHelperMixin, TestCaseWithFactory):
                 owner=self.person)
             oci_project = self.factory.makeOCIProject(
                 pillar=distro, registrant=self.person)
-            git_ref = self.factory.makeGitRefs()[0]
+            [git_ref] = self.factory.makeGitRefs(
+                paths=['refs/heads/v1.0-20.04'])
 
             oci_project_url = api_url(oci_project)
             git_ref_url = api_url(git_ref)
@@ -1490,6 +1508,30 @@ class TestOCIRecipeWebservice(OCIConfigHelperMixin, TestCaseWithFactory):
                 build_args=Equals({"VAR": "VAR VALUE"})
             )))
 
+    def test_api_create_oci_recipe_invalid_branch_format(self):
+        with person_logged_in(self.person):
+            distro = self.factory.makeDistribution(
+                owner=self.person)
+            oci_project = self.factory.makeOCIProject(
+                pillar=distro, registrant=self.person)
+            [git_ref] = self.factory.makeGitRefs(
+                paths=['refs/heads/invalid-branch'])
+
+            oci_project_url = api_url(oci_project)
+            git_ref_url = api_url(git_ref)
+            person_url = api_url(self.person)
+
+        obj = {
+            "name": "my-recipe",
+            "owner": person_url,
+            "git_ref": git_ref_url,
+            "build_file": "./Dockerfile",
+            "build_args": {"VAR": "VAR VALUE"},
+            "description": "My recipe"}
+
+        resp = self.webservice.named_post(oci_project_url, "newRecipe", **obj)
+        self.assertEqual(400, resp.status, resp.body)
+
     def test_api_create_oci_recipe_non_legitimate_user(self):
         """Ensure that a non-legitimate user cannot create recipe using API"""
         self.pushConfig(
@@ -1527,7 +1569,8 @@ class TestOCIRecipeWebservice(OCIConfigHelperMixin, TestCaseWithFactory):
                 owner=self.person)
             oci_project = self.factory.makeOCIProject(
                 pillar=distro, registrant=self.person)
-            git_ref = self.factory.makeGitRefs()[0]
+            [git_ref] = self.factory.makeGitRefs(
+                paths=['refs/heads/v1.0-20.04'])
 
             oci_project_url = api_url(oci_project)
             git_ref_url = api_url(git_ref)
diff --git a/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py b/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py
index 0fb7574..ad4f625 100644
--- a/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py
+++ b/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py
@@ -208,7 +208,7 @@ class TestAsyncOCIRecipeBuildBehaviour(
 
     @defer.inlineCallbacks
     def test_composeBuildRequest(self):
-        [ref] = self.factory.makeGitRefs()
+        [ref] = self.factory.makeGitRefs(paths=['refs/heads/v1.0-20.04'])
         job = self.makeJob(git_ref=ref)
         lfa = self.factory.makeLibraryFileAlias(db_only=True)
         job.build.distro_arch_series.addOrUpdateChroot(lfa)
@@ -547,7 +547,8 @@ class TestAsyncOCIRecipeBuildBehaviour(
         # If the source Git reference has been deleted, composeBuildRequest
         # raises CannotBuild.
         repository = self.factory.makeGitRepository()
-        [ref] = self.factory.makeGitRefs(repository=repository)
+        [ref] = self.factory.makeGitRefs(
+            repository=repository, paths=['refs/heads/v1.0-20.04'])
         owner = self.factory.makePerson(name="oci-owner")
 
         distribution = self.factory.makeDistribution()
diff --git a/lib/lp/oci/tests/test_ociregistryclient.py b/lib/lp/oci/tests/test_ociregistryclient.py
index 5fe9f2f..44241bc 100644
--- a/lib/lp/oci/tests/test_ociregistryclient.py
+++ b/lib/lp/oci/tests/test_ociregistryclient.py
@@ -125,7 +125,7 @@ class TestOCIRegistryClient(OCIConfigHelperMixin, SpyProxyCallsMixin,
         # This produces a git ref that does not match the 'valid' OCI branch
         # format, so will not get multiple tags. Multiple tags are tested
         # explicitly.
-        [git_ref] = self.factory.makeGitRefs()
+        [git_ref] = self.factory.makeGitRefs(paths=['refs/heads/v1.0-20.04'])
         recipe = self.factory.makeOCIRecipe(git_ref=git_ref)
         self.build = self.factory.makeOCIRecipeBuild(recipe=recipe)
         self.push_rule = self.factory.makeOCIPushRule(recipe=self.build.recipe)
@@ -748,7 +748,7 @@ class TestOCIRegistryClient(OCIConfigHelperMixin, SpyProxyCallsMixin,
 
         push_rule = self.build.recipe.push_rules[0]
         responses.add(
-            "GET", "{}/v2/{}/manifests/edge".format(
+            "GET", "{}/v2/{}/manifests/v1.0-20.04_edge".format(
                 push_rule.registry_url, push_rule.image_name),
             status=404)
         self.addManifestResponses(push_rule, status_code=201)
@@ -763,7 +763,7 @@ class TestOCIRegistryClient(OCIConfigHelperMixin, SpyProxyCallsMixin,
         auth_call, get_manifest_call, send_manifest_call = responses.calls
         self.assertEndsWith(
             send_manifest_call.request.url,
-            "/v2/%s/manifests/edge" % push_rule.image_name)
+            "/v2/%s/manifests/v1.0-20.04_edge" % push_rule.image_name)
         self.assertEqual({
             "schemaVersion": 2,
             "mediaType": "application/"
@@ -834,7 +834,7 @@ class TestOCIRegistryClient(OCIConfigHelperMixin, SpyProxyCallsMixin,
 
         push_rule = self.build.recipe.push_rules[0]
         responses.add(
-            "GET", "{}/v2/{}/manifests/edge".format(
+            "GET", "{}/v2/{}/manifests/v1.0-20.04_edge".format(
                 push_rule.registry_url, push_rule.image_name),
             json=current_manifest,
             status=200)
@@ -849,7 +849,7 @@ class TestOCIRegistryClient(OCIConfigHelperMixin, SpyProxyCallsMixin,
         auth_call, get_manifest_call, send_manifest_call = responses.calls
         self.assertEndsWith(
             send_manifest_call.request.url,
-            "/v2/%s/manifests/edge" % push_rule.image_name)
+            "/v2/%s/manifests/v1.0-20.04_edge" % push_rule.image_name)
         self.assertEqual({
             "schemaVersion": 2,
             "mediaType": "application/"
@@ -901,7 +901,7 @@ class TestOCIRegistryClient(OCIConfigHelperMixin, SpyProxyCallsMixin,
 
         push_rule = self.build.recipe.push_rules[0]
         responses.add(
-            "GET", "{}/v2/{}/manifests/edge".format(
+            "GET", "{}/v2/{}/manifests/v1.0-20.04_edge".format(
                 push_rule.registry_url, push_rule.image_name),
             json=current_manifest,
             status=200)
@@ -916,7 +916,7 @@ class TestOCIRegistryClient(OCIConfigHelperMixin, SpyProxyCallsMixin,
         auth_call, get_manifest_call, send_manifest_call = responses.calls
         self.assertEndsWith(
             send_manifest_call.request.url,
-            "/v2/%s/manifests/edge" % push_rule.image_name)
+            "/v2/%s/manifests/v1.0-20.04_edge" % push_rule.image_name)
         self.assertEqual({
             "schemaVersion": 2,
             "mediaType": "application/"
@@ -948,7 +948,7 @@ class TestOCIRegistryClient(OCIConfigHelperMixin, SpyProxyCallsMixin,
 
         push_rule = self.build.recipe.push_rules[0]
         responses.add(
-            "GET", "{}/v2/{}/manifests/edge".format(
+            "GET", "{}/v2/{}/manifests/v1.0-20.04_edge".format(
                 push_rule.registry_url, push_rule.image_name),
             json={"error": "Unknown"},
             status=503)