Files
admin 804884a749
gates / gates (push) Successful in 2s
image_digest.resolve honours a @digest: asks the registry for THAT manifest (R-746)
The digest was dropped and the tag's current digest returned, so 'is this digest still served' got a false yes
(measured: redis:7-alpine@sha256:000…0 resolved to the tag's digest; now HTTP 404). A malformed digest is refused
without a request. test_image_digest.py (no network); red-proof: the pre-fix resolver fails 3 of 4 cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-01 07:54:39 +02:00

76 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""R-746: image_digest.resolve honours a `@digest` — it asks the registry for THAT manifest and never answers the tag's
current digest. No network: urlopen is replaced by a fake registry that serves one tag and one digest.
COMPANION RED-PROOF: with the pre-fix resolve (it dropped the digest and asked for the tag), the absent-digest case
answers the tag's digest and this test fails ("a digest the registry does not serve was resolved")."""
import io
import os
import sys
import unittest
import urllib.error
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import image_digest # noqa: E402
SERVED = "sha256:" + "a" * 64
GONE = "sha256:" + "0" * 64
class _Resp:
def __init__(self, digest):
self.headers = {"Docker-Content-Digest": digest}
self.status = 200
def __enter__(self):
return self
def __exit__(self, *a):
return False
class FakeRegistry:
def __init__(self):
self.urls = []
def __call__(self, req, timeout=30):
url = req.full_url
self.urls.append(url)
last = url.rsplit("/", 1)[-1]
if last in ("7-alpine", SERVED): # the tag and the digest it serves
return _Resp(SERVED)
raise urllib.error.HTTPError(url, 404, "not found", {}, io.BytesIO(b""))
class ResolveDigest(unittest.TestCase):
def setUp(self):
self.fake = FakeRegistry()
self.orig = image_digest.urllib.request.urlopen
image_digest.urllib.request.urlopen = self.fake
def tearDown(self):
image_digest.urllib.request.urlopen = self.orig
def test_plain_tag_unchanged(self):
self.assertEqual(image_digest.resolve("redis:7-alpine"), (SERVED, None))
self.assertTrue(self.fake.urls[-1].endswith("/manifests/7-alpine"))
def test_served_digest_is_asked_by_digest(self):
d, why = image_digest.resolve("redis:7-alpine@" + SERVED)
self.assertEqual(d, SERVED, why)
self.assertTrue(self.fake.urls[-1].endswith("/manifests/" + SERVED), self.fake.urls)
def test_absent_digest_is_refused(self):
d, why = image_digest.resolve("redis:7-alpine@" + GONE)
self.assertIsNone(d, "a digest the registry does not serve was resolved (to %s)" % d)
self.assertIn("404", why)
def test_malformed_digest_is_refused(self):
d, why = image_digest.resolve("redis:7-alpine@sha256:abc")
self.assertIsNone(d)
self.assertEqual(self.fake.urls, [], "a malformed digest must not reach the registry")
if __name__ == "__main__":
unittest.main()