test: cover image input policy failure paths
prd-number-check / require-numbered-prds (pull_request) Successful in 29s
test / image-input-builds (pull_request) Successful in 23s
lint / lint (push) Successful in 1m2s
tracker-policy-pr / check-pr (pull_request) Successful in 30s
test / unit (pull_request) Successful in 1m3s
test / integration-docker (pull_request) Successful in 1m13s
test / coverage (pull_request) Successful in 18s

This commit is contained in:
2026-07-26 09:47:50 +00:00
parent 377f8d125b
commit 6a4c45e0b1
3 changed files with 150 additions and 1 deletions
+33 -1
View File
@@ -3,11 +3,16 @@
from __future__ import annotations from __future__ import annotations
import json import json
import io
import tempfile import tempfile
import unittest import unittest
from contextlib import redirect_stdout
from pathlib import Path from pathlib import Path
from unittest.mock import patch
from scripts.complete_npm_lock_integrity import complete_lock from scripts import complete_npm_lock_integrity as integrity_tool
complete_lock = integrity_tool.complete_lock
class TestCompleteLock(unittest.TestCase): class TestCompleteLock(unittest.TestCase):
@@ -61,6 +66,33 @@ class TestCompleteLock(unittest.TestCase):
with self.assertRaisesRegex(ValueError, "conflicting integrity"): with self.assertRaisesRegex(ValueError, "conflicting integrity"):
complete_lock(path) complete_lock(path)
def test_ignores_local_entries_and_leaves_complete_lock_unchanged(self):
with tempfile.TemporaryDirectory() as directory:
path = self._lock(directory, {
"": {"name": "root"},
"node_modules/local": {"resolved": "file:../local"},
"node_modules/complete": {
"resolved": "https://registry.example/complete.tgz",
"integrity": "sha512-complete",
},
})
before = path.read_text()
self.assertEqual(0, complete_lock(path))
self.assertEqual(before, path.read_text())
def test_main_processes_every_requested_lock(self):
with tempfile.TemporaryDirectory() as directory:
first = self._lock(directory, {})
second = Path(directory) / "second-lock.json"
second.write_text(first.read_text())
stdout = io.StringIO()
with patch(
"sys.argv",
["complete_npm_lock_integrity.py", str(first), str(second)],
), redirect_stdout(stdout):
self.assertEqual(0, integrity_tool.main())
self.assertEqual(2, stdout.getvalue().count("completed 0"))
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
+18
View File
@@ -223,6 +223,24 @@ class TestPinnedLocalImageRef(unittest.TestCase):
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
docker_mod.pinned_local_image_ref("base:latest") docker_mod.pinned_local_image_ref("base:latest")
def test_rejects_content_tag_that_resolves_to_another_image(self):
image = "sha256:" + "e" * 64
with patch.object(
docker_mod,
"image_id",
side_effect=[image, "sha256:" + "f" * 64],
), patch.object(
docker_mod,
"run_docker",
return_value=_ok(),
), patch.object(
docker_mod,
"die",
side_effect=SystemExit("die"),
):
with self.assertRaises(SystemExit):
docker_mod.pinned_local_image_ref("base:latest")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
+99
View File
@@ -3,9 +3,12 @@
from __future__ import annotations from __future__ import annotations
import json import json
import io
import tempfile import tempfile
import unittest import unittest
from contextlib import redirect_stderr, redirect_stdout
from pathlib import Path from pathlib import Path
from unittest.mock import patch
from scripts import check_image_inputs as policy from scripts import check_image_inputs as policy
@@ -55,6 +58,35 @@ class TestDockerfilePolicy(unittest.TestCase):
problems = policy.check_dockerfile(Path("Dockerfile"), text) problems = policy.check_dockerfile(Path("Dockerfile"), text)
self.assertTrue(any("fixed Debian snapshot" in item for item in problems)) self.assertTrue(any("fixed Debian snapshot" in item for item in problems))
def test_rejects_missing_dynamic_and_malformed_bases(self):
cases = (
("RUN true\n", "missing FROM"),
("FROM ${BASE_IMAGE}\n", "dynamic base"),
(
"ARG ORCHESTRATOR_BASE_IMAGE=base:latest\n"
"FROM ${ORCHESTRATOR_BASE_IMAGE}\n",
"mutable default",
),
("FROM node:22@sha256:abc\n", "64 lowercase hex"),
)
for text, expected in cases:
with self.subTest(expected=expected):
problems = policy.check_dockerfile(Path("Dockerfile"), text)
self.assertTrue(any(expected in item for item in problems))
def test_requires_gateway_lock_and_verified_codex_markers(self):
base = "FROM node:22.23.1@sha256:" + "a" * 64 + "\n"
gateway = policy.check_dockerfile(Path("Dockerfile.gateway"), base)
self.assertTrue(any("require hashes" in item for item in gateway))
self.assertTrue(any("lock is not consumed" in item for item in gateway))
codex = policy.check_dockerfile(
Path("bot_bottle/contrib/codex/Dockerfile"),
base,
)
self.assertEqual(3, len(codex))
self.assertTrue(all("verified pinned Codex install" in item for item in codex))
class TestNpmLockPolicy(unittest.TestCase): class TestNpmLockPolicy(unittest.TestCase):
def _write(self, root: Path, *, version: str, integrity: str = "") -> Path: def _write(self, root: Path, *, version: str, integrity: str = "") -> Path:
@@ -97,11 +129,78 @@ class TestNpmLockPolicy(unittest.TestCase):
self.assertTrue(any("not an exact version" in item for item in problems)) self.assertTrue(any("not an exact version" in item for item in problems))
self.assertTrue(any("lacks sha512 integrity" in item for item in problems)) self.assertTrue(any("lacks sha512 integrity" in item for item in problems))
def test_rejects_unreadable_stale_or_old_lock(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
missing = policy.check_npm_manifest(root, Path("missing/package.json"))
self.assertTrue(any("cannot read" in item for item in missing))
path = self._write(root, version="1.2.3", integrity="sha512-abc")
lock_path = root / path.with_name("package-lock.json")
lock = json.loads(lock_path.read_text())
lock["lockfileVersion"] = 2
lock["packages"][""]["dependencies"] = {}
lock_path.write_text(json.dumps(lock))
problems = policy.check_npm_manifest(root, path)
self.assertTrue(any("root dependencies are stale" in item for item in problems))
self.assertTrue(any("lockfileVersion 3" in item for item in problems))
class TestPythonLockPolicy(unittest.TestCase):
def test_rejects_missing_or_empty_lock(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
missing = policy.check_python_lock(root)
self.assertTrue(any("cannot read lock" in item for item in missing))
(root / "requirements.gateway.lock").write_text("# empty\n")
problems = policy.check_python_lock(root)
self.assertTrue(any("contains no exact requirements" in item for item in problems))
self.assertTrue(any("cannot read input" in item for item in problems))
def test_rejects_unhashed_and_stale_direct_requirements(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / "requirements.gateway.lock").write_text(
"example== \\\n"
" # deliberately malformed and unhashed\n"
)
(root / "requirements.gateway.in").write_text(
"example>=1\n"
"missing==2.0.0\n"
)
problems = policy.check_python_lock(root)
self.assertTrue(any("example is not exact" in item for item in problems))
self.assertTrue(any("example lacks a sha256 hash" in item for item in problems))
self.assertTrue(any("direct dependency is not exact" in item for item in problems))
self.assertTrue(any("missing direct dependency" in item for item in problems))
class TestRepositoryPolicy(unittest.TestCase): class TestRepositoryPolicy(unittest.TestCase):
def test_repository_image_inputs_pass(self): def test_repository_image_inputs_pass(self):
self.assertEqual([], policy.check_repo()) self.assertEqual([], policy.check_repo())
def test_missing_repository_inputs_are_reported(self):
with tempfile.TemporaryDirectory() as directory, patch.object(
policy,
"DOCKERFILES",
(Path("missing.Dockerfile"),),
), patch.object(policy, "NPM_MANIFESTS", ()):
problems = policy.check_repo(Path(directory))
self.assertTrue(any("cannot read Dockerfile" in item for item in problems))
def test_main_reports_success_and_failure(self):
with patch.object(policy, "check_repo", return_value=[]), redirect_stdout(io.StringIO()):
self.assertEqual(0, policy.main())
stderr = io.StringIO()
with patch.object(
policy,
"check_repo",
return_value=["bad base"],
), redirect_stderr(stderr):
self.assertEqual(1, policy.main())
self.assertIn("bad base", stderr.getvalue())
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()