diff --git a/delivery/ci/publish_mcp_artifacts.py b/delivery/ci/publish_mcp_artifacts.py index 4a82eaf..e2694f6 100644 --- a/delivery/ci/publish_mcp_artifacts.py +++ b/delivery/ci/publish_mcp_artifacts.py @@ -803,6 +803,9 @@ def registry_tags(): return [] require(status == 200, "registry_tags_unavailable") value = strict_json(raw) + # GHCR returns null while the repository contains only untagged digests. + if "tags" in value and value["tags"] is None: + value["tags"] = [] require(value.get("name") == IMAGE.removeprefix("ghcr.io/") and isinstance(value.get("tags"), list) and len(value["tags"]) < 1000 and all(isinstance(tag, str) for tag in value["tags"]), "registry_tags_window") return value["tags"] diff --git a/tests/test_mcp_publication.py b/tests/test_mcp_publication.py index d78d606..a14fc68 100644 --- a/tests/test_mcp_publication.py +++ b/tests/test_mcp_publication.py @@ -730,6 +730,16 @@ class TransportBoundaryTests(unittest.TestCase): def setUp(self): self.p = importlib.import_module("delivery.ci.publish_mcp_artifacts") + def test_registry_without_tagged_images_has_no_reusable_runtime(self): + with patch.object(self.p, "registry_request", return_value=(200, b'{"name":"zeegin/v8std-mcp","tags":null}')): + self.assertEqual(self.p.registry_tags(), []) + for value in ({"name": "zeegin/v8std-mcp"}, + {"name": "other/repository", "tags": None}, + {"name": "zeegin/v8std-mcp", "tags": "stable"}): + with self.subTest(value=value), patch.object(self.p, "registry_request", return_value=(200, json.dumps(value).encode())): + with self.assertRaisesRegex(self.p.PublicationError, "registry_tags_window"): + self.p.registry_tags() + def test_real_local_smoke_validates_inspect_array_for_both_platforms_and_cleans_failures(self): good = {"Config": {"User": "10001:10001", "Labels": {"org.opencontainers.image.revision": "d" * 40}}, "HostConfig": {"Privileged": False, "ReadonlyRootfs": True}}