"""The images a Dockerfile builds on, so their signatures can be checked first. Every link of the chain (base-os → base-python → engine; base-os → ui) checks the signature of what it pins before it builds. That starts with the external references of its FROM lines: a stage of the same file is no image, and an image not pinned by digest cannot be verified at all. """ from __future__ import annotations import pytest from image_tools.dockerfile import external_bases BASE = "registry.netork.io/netork/base-python:3.12.15-13-20261020.1@sha256:" + "c" * 64 OS = "registry.netork.io/netork/base-os:13-20261022.2@sha256:" + "f" * 64 def test_stages_of_the_same_file_are_not_images(): text = f""" FROM {BASE} AS builder RUN true FROM builder AS drivers FROM {BASE} AS runtime COPY --from=drivers /opt /opt """ assert external_bases(text) == [BASE] def test_every_distinct_image_once_in_order(): text = f"FROM {OS} AS builder\nFROM {BASE} AS runtime\nFROM {OS}\n" assert external_bases(text) == [OS, BASE] def test_flags_and_case_do_not_hide_an_image(): text = f"from --platform=$BUILDPLATFORM {OS} as build\n" assert external_bases(text) == [OS] def test_scratch_is_no_image(): assert external_bases("FROM scratch\n") == [] def test_continuation_lines_are_joined(): text = f"FROM \\\n {OS} \\\n AS runtime\n" assert external_bases(text) == [OS] @pytest.mark.parametrize( "ref", ["debian:trixie-slim", "registry.netork.io/netork/base-os:pinned", "${BASE_IMAGE}"], ) def test_an_image_without_a_digest_is_refused(ref): """A tag can move; only a digest says which image was checked.""" with pytest.raises(ValueError, match="digest"): external_bases(f"FROM {ref}\n")