ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
managed_python_env_checks.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# SPDX-License-Identifier: MIT
3# Copyright (c) 2026 Brighton Sikarskie
4"""Host managed-environment consumer contracts and hostile QA fixtures."""
5
6from __future__ import annotations
7
8import json
9import os
10import re
11import shutil
12import tempfile
13from collections.abc import Callable
14from dataclasses import dataclass
15from pathlib import Path
16from typing import NoReturn, Protocol
17
18
19class CommandResultLike(Protocol):
20 """Describe captured process fields used by the consumer runtime audit."""
21
22 returncode: int
23
24
25class CommandRunner(Protocol):
26 """Describe the authority's absolute-command runner."""
27
28 def __call__(
29 self, arguments: list[str], environment: dict[str, str], timeout_seconds: int
30 ) -> CommandResultLike:
31 """Run one command and return its status."""
32
33
34@dataclass(frozen=True)
35class FilesystemHarness:
36 """Provide the production authority operations used by hostile fixtures."""
37
38 refresh: Callable[[], object]
39 reject_environment: Callable[[str, Path, str], None]
40 make_environment: Callable[[str], Path]
41 cache_key: Callable[[str], str]
42 fail: Callable[[str], NoReturn]
43 receipt_name: str
44 receipt_mode: int
45
46
47def rewrite_receipt(
48 environment: Path, update: dict[str, object], receipt_name: str, receipt_mode: int
49) -> None:
50 """Replace a selftest receipt while preserving its required final mode."""
51 receipt = environment / receipt_name
52 payload = json.loads(receipt.read_text(encoding="ascii"))
53 payload.update(update)
54 receipt.chmod(0o600)
55 receipt.write_text(
56 json.dumps(payload, sort_keys=True, indent=2, ensure_ascii=True) + "\n",
57 encoding="ascii",
58 )
59 receipt.chmod(receipt_mode)
60
61
62def _contracts() -> tuple[tuple[str, str], ...]:
63 """Return every exact authority invocation each consumer must own once."""
64 return (
65 (
66 "setup_python.sh",
67 '/usr/bin/python3 -I "$MANAGED_ENV_AUTHORITY" verify --env "$selected_venv" '
68 '--pyproject "$PYPROJECT" --lock "$LOCKFILE" --group ci --print-bin',
69 ),
70 (
71 "tool_env.sh",
72 '/usr/bin/python3 -I "${repo_root}/scripts/dev/managed_python_env.py" cache-key '
73 '--env "${selected}" --pyproject "${repo_root}/pyproject.toml" '
74 '--lock "${repo_root}/uv.lock" --group ci',
75 ),
76 (
77 "tool_env.sh",
78 '/usr/bin/python3 -I "${repo_root}/scripts/dev/managed_python_env.py" verify '
79 '--env "${selected}" --pyproject "${repo_root}/pyproject.toml" '
80 '--lock "${repo_root}/uv.lock" --group ci --print-bin',
81 ),
82 (
83 "provision_dev_box_toolchain.sh",
84 'as_root /usr/bin/python3 -I "${ROOT}/scripts/dev/managed_python_env.py" write '
85 '--env "${venv}" --pyproject "${ROOT}/pyproject.toml" '
86 '--lock "${ROOT}/uv.lock" --group ci',
87 ),
88 (
89 "provision_dev_box_toolchain.sh",
90 '/usr/bin/python3 -I "${ROOT}/scripts/dev/managed_python_env.py" verify '
91 '--env "${python_venv}" --pyproject "${ROOT}/pyproject.toml" '
92 '--lock "${ROOT}/uv.lock" --group ci',
93 ),
94 )
95
96
97def _dockerfile_instructions(source: str) -> tuple[tuple[str, str], ...]:
98 """Return normalized active Dockerfile instructions without comments."""
99 instructions: list[tuple[str, str]] = []
100 chunks: list[str] = []
101 for raw_line in source.splitlines():
102 stripped = raw_line.strip()
103 if stripped.startswith("#") or (not chunks and not stripped):
104 continue
105 continued = raw_line.rstrip().endswith("\\")
106 chunk = raw_line.rstrip()
107 if continued:
108 chunk = chunk[:-1]
109 chunks.append(chunk.strip())
110 if continued:
111 continue
112 logical = " ".join(" ".join(chunks).split())
113 chunks.clear()
114 keyword, separator, body = logical.partition(" ")
115 instructions.append((keyword.upper(), body if separator else ""))
116 if chunks:
117 instructions.append(("INCOMPLETE", " ".join(chunks)))
118 return tuple(instructions)
119
120
121def _dockerfile_receipt_contract() -> tuple[str, str, str]:
122 """Return lock cleanup, receipt seal, and inherited-image verification."""
123 cleanup = 'rm -f -- "${PYTHON_TOOL_VENV}/.lock"'
124 authority = "/usr/bin/python3 -I /opt/ra8-uv-bootstrap/managed_python_env.py"
125 devcontainer_inputs = (
126 '--env "${PYTHON_TOOL_VENV}" '
127 "--pyproject /opt/ra8-python-project/pyproject.toml "
128 "--lock /opt/ra8-python-project/uv.lock --group ci"
129 )
130 runner_inputs = (
131 '--env "${RA8_TOOL_VENV}" '
132 "--pyproject /opt/ra8-python-project/pyproject.toml "
133 "--lock /opt/ra8-python-project/uv.lock --group ci"
134 )
135 verify = f"{authority} verify {devcontainer_inputs}"
136 runtime_probe = '"${PYTHON_TOOL_VENV}/bin/python3" -c "import PIL.Image"'
137 receipt = f"{authority} write {devcontainer_inputs} && {verify} && {runtime_probe} && {verify}"
138 marker = "printf '%s\\n' 'localhost/ra8-ci-runner (infra/images/runner/Dockerfile)'"
139 runner_verify = f"{marker} > /etc/ra8-ci-runner && {authority} verify {runner_inputs}"
140 return cleanup, receipt, runner_verify
141
142
143def _receipt_root_user(instructions: tuple[tuple[str, str], ...], end: int) -> str:
144 """Return the effective Docker build user immediately before one instruction."""
145 user = "root"
146 for keyword, body in instructions[:end]:
147 if keyword == "FROM":
148 user = "root"
149 elif keyword == "USER":
150 user = body.split(maxsplit=1)[0]
151 return user
152
153
154def dockerfile_receipt_findings(source: str) -> list[str]:
155 """Require one root-owned receipt seal after lock cleanup and Python use."""
156 cleanup, receipt, _ = _dockerfile_receipt_contract()
157 instructions = _dockerfile_instructions(source)
158 managed_environment = (
159 'PYTHONDONTWRITEBYTECODE="1" '
160 'PYTHONNOUSERSITE="1" '
161 'RA8_TOOL_VENV="${PYTHON_TOOL_VENV}" '
162 'RA8_UV_CACHE_ROOT="/opt/ra8-uv-cache" '
163 'VIRTUAL_ENV="${PYTHON_TOOL_VENV}" '
164 'UV_PYTHON_DOWNLOADS="never" '
165 'PATH="${PYTHON_TOOL_VENV}/bin:${PATH}"'
166 )
167 receipt_indices = [
168 index
169 for index, (keyword, body) in enumerate(instructions)
170 if keyword == "RUN" and body == receipt
171 ]
172 cleanup_indices = [
173 index
174 for index, (keyword, body) in enumerate(instructions)
175 if keyword == "RUN" and body.endswith(cleanup)
176 ]
177 findings: list[str] = []
178 if len(receipt_indices) != 1:
179 findings.append("Dockerfile must own exactly one active exact managed receipt RUN")
180 if len(cleanup_indices) != 1:
181 findings.append("Dockerfile must remove the transient uv lock exactly once")
182 if instructions.count(("ENV", managed_environment)) != 1:
183 findings.append("Dockerfile must bind the exact inherited managed-environment authority")
184 if len(receipt_indices) != 1 or len(cleanup_indices) != 1:
185 return findings
186 receipt_index = receipt_indices[0]
187 if cleanup_indices[0] >= receipt_index:
188 findings.append("Dockerfile must remove the transient uv lock before sealing the receipt")
189 if _receipt_root_user(instructions, receipt_index) not in {"0", "0:0", "root"}:
190 findings.append("Dockerfile must seal the managed receipt as root")
191 if instructions[receipt_index + 1 :] != (("USER", "${USERNAME}"),):
192 findings.append(
193 "Dockerfile receipt seal must be followed only by exact non-root USER restoration"
194 )
195 return findings
196
197
198def runner_dockerfile_receipt_findings(source: str) -> list[str]:
199 """Require the final ARC image to authenticate the inherited receipt."""
200 _, _, verify = _dockerfile_receipt_contract()
201 instructions = _dockerfile_instructions(source)
202 verify_indices = [
203 index
204 for index, (keyword, body) in enumerate(instructions)
205 if keyword == "RUN" and body == verify
206 ]
207 findings: list[str] = []
208 if len(verify_indices) != 1:
209 findings.append("runner Dockerfile must own one active exact receipt verification RUN")
210 return findings
211 verify_index = verify_indices[0]
212 if _receipt_root_user(instructions, verify_index) not in {"0", "0:0", "root"}:
213 findings.append("runner Dockerfile must verify the managed receipt as root")
214 expected_tail = (
215 ("ENV", "RUNNER_MANUALLY_TRAP_SIG=1 ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1"),
216 ("WORKDIR", "/home/runner"),
217 ("USER", "runner"),
218 ("ENTRYPOINT", "[]"),
219 ("CMD", '["/bin/bash"]'),
220 )
221 if instructions[verify_index + 1 :] != expected_tail:
222 findings.append("runner receipt verification must precede only its exact runtime metadata")
223 if any(
224 keyword == "ENV" and "RA8_TOOL_VENV" in body
225 for keyword, body in instructions[:verify_index]
226 ):
227 findings.append("runner Dockerfile must not redirect the inherited RA8_TOOL_VENV authority")
228 return findings
229
230
231def consumer_findings(root: Path) -> list[str]:
232 """Return source-contract drift between all managed-environment consumers."""
233 paths = {
234 "setup_python.sh": root / "scripts/dev/setup_python.sh",
235 "tool_env.sh": root / "scripts/ci/lib/tool_env.sh",
236 "Dockerfile": root / ".devcontainer/Dockerfile",
237 "runner Dockerfile": root / "infra/images/runner/Dockerfile",
238 "provision_dev_box_toolchain.sh": root / "scripts/dev/provision_dev_box_toolchain.sh",
239 }
240 sources = {label: path.read_text(encoding="ascii") for label, path in paths.items()}
241 flattened = {
242 label: " ".join(content.replace("\\\n", " ").split()) for label, content in sources.items()
243 }
244 findings = [
245 f"{label} is missing the exact authenticated managed-environment invocation"
246 for label, invocation in _contracts()
247 if flattened[label].count(invocation) != 1
248 ]
249 findings.extend(dockerfile_receipt_findings(sources["Dockerfile"]))
250 findings.extend(runner_dockerfile_receipt_findings(sources["runner Dockerfile"]))
251 weak_patterns = (
252 r"RA8_TOOL_VENV[^\n]{0,160}bin/python3[^\n]{0,40}-x",
253 r"\‍[\‍[?\s+-x\s+[^\n]*RA8_TOOL_VENV",
254 )
255 for label in ("setup_python.sh", "tool_env.sh"):
256 findings.extend(
257 f"{label} still accepts an executable-only managed environment"
258 for pattern in weak_patterns
259 if re.search(pattern, sources[label])
260 )
261 return findings
262
263
264def consumer_runtime_findings(root: Path, run_command: CommandRunner) -> list[str]:
265 """Drive direct setup and real root-Just evaluation in both directions."""
266 findings: list[str] = []
267 with tempfile.TemporaryDirectory(prefix="ra8-managed-forged-") as tmp:
268 forged = Path(tmp) / "managed"
269 (forged / "bin").mkdir(parents=True)
270 shutil.copy2("/bin/true", forged / "bin/python3")
271 base_env = os.environ.copy()
272 base_env.update({"BASH_ENV": "/dev/null", "ENV": "/dev/null", "PATH": "/usr/bin:/bin"})
273 base_env.pop("PYTHONHOME", None)
274 base_env.pop("PYTHONPATH", None)
275 setup = root / "scripts/dev/setup_python.sh"
276 normal_env = dict(base_env)
277 normal_env["RA8_TOOL_VENV"] = ""
278 normal = run_command(["/bin/bash", "-p", str(setup), "--print-path"], normal_env, 30)
279 if normal.returncode != 0:
280 findings.append("setup_python.sh rejects the native no-managed-environment path")
281 hostile_env = dict(base_env)
282 hostile_env["RA8_TOOL_VENV"] = str(forged)
283 hostile = run_command(["/bin/bash", "-p", str(setup), "--print-path"], hostile_env, 30)
284 if hostile.returncode == 0:
285 findings.append("setup_python.sh accepted an arbitrary executable managed environment")
286 just = shutil.which("just", path="/usr/local/bin:/usr/bin:/opt/homebrew/bin")
287 if just is None:
288 findings.append("cannot exercise the real root Justfile because just is missing")
289 else:
290 command = [just, "--justfile", str(root / "justfile"), "--evaluate", "PATH"]
291 if run_command(command, normal_env, 30).returncode != 0:
292 findings.append("real root Just evaluation rejects the native environment")
293 if run_command(command, hostile_env, 30).returncode == 0:
294 findings.append("real root Just evaluation accepted a forged managed environment")
295 return findings
296
297
298def _dockerfile_receipt_contract_selftest(dockerfile: Path, good: str) -> list[str]:
299 """Return failures from independent hostile Docker receipt mutations."""
300 cleanup, receipt, _ = _dockerfile_receipt_contract()
301 managed_environment = next(
302 line for line in good.splitlines() if line.startswith("ENV PYTHONDONTWRITEBYTECODE=")
303 )
304 runtime_probe = '"${PYTHON_TOOL_VENV}/bin/python3" -c "import PIL.Image"'
305 mutations = (
306 (f"RUN {receipt}\n", "RUN true\n", "a deleted receipt step"),
307 (
308 f"RUN true; {cleanup}\n{managed_environment}\nRUN {receipt}\n",
309 f"RUN {receipt}\nRUN true; {cleanup}\n{managed_environment}\n",
310 "a receipt moved before transient-lock cleanup",
311 ),
312 ("--group ci", "--group dev", "a weakened dependency-group binding"),
313 (runtime_probe, "true", "a deleted bytecode-stability runtime import"),
314 ('PYTHONDONTWRITEBYTECODE="1"', 'PYTHONDONTWRITEBYTECODE="0"', "bytecode enabled"),
315 (
316 'RA8_TOOL_VENV="${PYTHON_TOOL_VENV}"',
317 'RA8_TOOL_VENV=""',
318 "a redirected inherited managed-environment authority",
319 ),
320 (f"RUN {receipt}", f"# RUN {receipt}", "receipt tokens present only in a comment"),
321 (
322 f"RUN {receipt}\nUSER ${{USERNAME}}",
323 f"USER ${{USERNAME}}\nRUN {receipt}",
324 "a non-root receipt writer",
325 ),
326 (
327 f"RUN {receipt}\nUSER ${{USERNAME}}",
328 f"RUN {receipt}\nRUN git config --global probe true\nUSER ${{USERNAME}}",
329 "a later RUN after receipt sealing",
330 ),
331 (
332 f"RUN {receipt}\nUSER ${{USERNAME}}",
333 f"RUN {receipt}\nCOPY uv.lock /opt/ra8-python-project/uv.lock\nUSER ${{USERNAME}}",
334 "a later COPY after receipt sealing",
335 ),
336 (
337 f"RUN {receipt}\nUSER ${{USERNAME}}",
338 f"RUN {receipt}\nONBUILD RUN true\nUSER ${{USERNAME}}",
339 "a deferred ONBUILD mutation after receipt sealing",
340 ),
341 (
342 f"RUN {receipt}\nUSER ${{USERNAME}}",
343 f"RUN {receipt}\nUSER root",
344 "a root final image user",
345 ),
346 )
347 failures: list[str] = []
348 for old, new, label in mutations:
349 dockerfile.write_text(good.replace(old, new, 1), encoding="ascii")
350 if not consumer_findings(dockerfile.parents[1]):
351 failures.append(f"consumer selftest missed {label}")
352 return failures
353
354
355def _runner_receipt_contract_selftest(dockerfile: Path, good: str) -> list[str]:
356 """Return failures from hostile final ARC-image receipt mutations."""
357 _, _, verify = _dockerfile_receipt_contract()
358 mutations = (
359 (f"RUN {verify}\n", "RUN true\n", "a deleted runner receipt verification"),
360 (f"RUN {verify}", f"# RUN {verify}", "runner verify tokens only in a comment"),
361 ("--group ci", "--group dev", "a weakened runner dependency-group binding"),
362 (
363 '--env "${RA8_TOOL_VENV}"',
364 '--env "${PYTHON_TOOL_VENV}"',
365 "a parent-only ARG used instead of the inherited environment authority",
366 ),
367 (
368 "USER root\nRUN true\nRUN " + verify,
369 "USER root\nRUN true\nUSER runner\nRUN " + verify,
370 "a non-root runner receipt verifier",
371 ),
372 (
373 f"RUN {verify}\nENV RUNNER_MANUALLY_TRAP_SIG=1",
374 f"RUN {verify}\nRUN printf later\nENV RUNNER_MANUALLY_TRAP_SIG=1",
375 "a later runner-image RUN",
376 ),
377 (
378 f"RUN {verify}\nENV RUNNER_MANUALLY_TRAP_SIG=1",
379 f"RUN {verify}\nCOPY uv.lock /opt/ra8-python-project/uv.lock\n"
380 "ENV RUNNER_MANUALLY_TRAP_SIG=1",
381 "a later runner-image COPY",
382 ),
383 (
384 f"RUN {verify}\nENV RUNNER_MANUALLY_TRAP_SIG=1",
385 f"RUN {verify}\nONBUILD RUN true\nENV RUNNER_MANUALLY_TRAP_SIG=1",
386 "a deferred runner-image mutation",
387 ),
388 (
389 "USER root\nRUN true\nRUN " + verify,
390 'USER root\nENV RA8_TOOL_VENV="/tmp/forged"\nRUN ' + verify,
391 "a redirected inherited environment authority before verification",
392 ),
393 ("\nUSER runner\nENTRYPOINT", "\nUSER root\nENTRYPOINT", "a root ARC image user"),
394 )
395 failures: list[str] = []
396 for old, new, label in mutations:
397 dockerfile.write_text(good.replace(old, new, 1), encoding="ascii")
398 if not consumer_findings(dockerfile.parents[3]):
399 failures.append(f"consumer selftest missed {label}")
400 return failures
401
402
403def consumer_contract_selftest() -> list[str]:
404 """Return failures from positive and hostile static-consumer fixtures."""
405 with tempfile.TemporaryDirectory(prefix="ra8-managed-consumers-") as tmp:
406 root = Path(tmp)
407 paths = {
408 "setup_python.sh": "scripts/dev/setup_python.sh",
409 "tool_env.sh": "scripts/ci/lib/tool_env.sh",
410 "Dockerfile": ".devcontainer/Dockerfile",
411 "runner Dockerfile": "infra/images/runner/Dockerfile",
412 "provision_dev_box_toolchain.sh": "scripts/dev/provision_dev_box_toolchain.sh",
413 }
414 grouped = {label: [] for label in paths}
415 for label, invocation in _contracts():
416 grouped[label].append(invocation)
417 for label, relative in paths.items():
418 path = root / relative
419 path.parent.mkdir(parents=True, exist_ok=True)
420 path.write_text("\n".join(grouped[label]) + "\n", encoding="ascii")
421 cleanup, receipt, verify = _dockerfile_receipt_contract()
422 managed_environment = (
423 'ENV PYTHONDONTWRITEBYTECODE="1" '
424 'PYTHONNOUSERSITE="1" '
425 'RA8_TOOL_VENV="${PYTHON_TOOL_VENV}" '
426 'RA8_UV_CACHE_ROOT="/opt/ra8-uv-cache" '
427 'VIRTUAL_ENV="${PYTHON_TOOL_VENV}" '
428 'UV_PYTHON_DOWNLOADS="never" '
429 'PATH="${PYTHON_TOOL_VENV}/bin:${PATH}"\n'
430 )
431 good_dockerfile = (
432 f"FROM ubuntu:24.04\nRUN true; {cleanup}\n{managed_environment}"
433 f"RUN {receipt}\nUSER ${{USERNAME}}\n"
434 )
435 dockerfile = root / ".devcontainer/Dockerfile"
436 dockerfile.write_text(good_dockerfile, encoding="ascii")
437 good_runner = (
438 f"FROM base\nUSER root\nRUN true\nRUN {verify}\n"
439 "ENV RUNNER_MANUALLY_TRAP_SIG=1 \\\n"
440 " ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1\n"
441 'WORKDIR /home/runner\nUSER runner\nENTRYPOINT []\nCMD ["/bin/bash"]\n'
442 )
443 runner_dockerfile = root / "infra/images/runner/Dockerfile"
444 runner_dockerfile.write_text(good_runner, encoding="ascii")
445 findings = consumer_findings(root)
446 (root / "scripts/dev/setup_python.sh").write_text(
447 '[[ -x "$RA8_TOOL_VENV/bin/python3" ]]\n', encoding="ascii"
448 )
449 if not consumer_findings(root):
450 findings.append("consumer selftest missed an executable-only managed environment")
451 (root / "scripts/dev/setup_python.sh").write_text(
452 "\n".join(grouped["setup_python.sh"]) + "\n", encoding="ascii"
453 )
454 findings.extend(_dockerfile_receipt_contract_selftest(dockerfile, good_dockerfile))
455 dockerfile.write_text(good_dockerfile, encoding="ascii")
456 runner_dockerfile.write_text(good_runner, encoding="ascii")
457 findings.extend(_runner_receipt_contract_selftest(runner_dockerfile, good_runner))
458 return findings
459
460
461def nested_tree_selftest(environment: Path, harness: FilesystemHarness) -> None:
462 """Reject writable or changed package and command bytes below trusted roots."""
463 site_packages = next(environment.glob("lib/python*/site-packages"))
464 package_file = site_packages / "ra8_managed_env_selftest.py"
465 command_file = environment / "bin/ra8-managed-env-selftest"
466 package_file.write_text("VALUE = 1\n", encoding="ascii")
467 command_file.write_text("#!/bin/sh\nexit 0\n", encoding="ascii")
468 command_file.chmod(0o755)
469 harness.refresh()
470 package_file.chmod(0o666)
471 harness.reject_environment("a group/other-writable nested package file", environment, "ci")
472 package_file.chmod(0o644)
473 site_packages.chmod(0o775)
474 harness.reject_environment("a group-writable nested package directory", environment, "ci")
475 site_packages.chmod(0o755)
476 command_file.chmod(0o775)
477 harness.reject_environment("a group-writable managed command", environment, "ci")
478 command_file.chmod(0o755)
479 package_file.write_text("VALUE = 2\n", encoding="ascii")
480 harness.reject_environment(
481 "changed nested package bytes with unchanged distribution metadata", environment, "ci"
482 )
483
484
485def stale_receipt_selftest(
486 root: Path,
487 environment: Path,
488 pyproject: Path,
489 lockfile: Path,
490 harness: FilesystemHarness,
491) -> None:
492 """Exercise lock, group, copied-receipt, and symlink-root rejection."""
493 stale_lock = lockfile.read_text(encoding="ascii")
494 lockfile.write_text("version = 2\n", encoding="ascii")
495 harness.reject_environment("a receipt stale against uv.lock", environment, "ci")
496 lockfile.write_text(stale_lock, encoding="ascii")
497 stale_project = pyproject.read_text(encoding="ascii")
498 pyproject.write_text("[dependency-groups]\nci=['stale']\n", encoding="ascii")
499 harness.reject_environment("a receipt stale against pyproject.toml", environment, "ci")
500 pyproject.write_text(stale_project, encoding="ascii")
501 harness.reject_environment("the wrong dependency group", environment, "dev")
502 arbitrary = harness.make_environment("arbitrary")
503 harness.reject_environment(
504 "an arbitrary executable environment without a receipt", arbitrary, "ci"
505 )
506 copied = harness.make_environment("copied")
507 shutil.copy2(environment / harness.receipt_name, copied / harness.receipt_name)
508 harness.reject_environment("a copied receipt at another path", copied, "ci")
509 alias = root / "managed-link"
510 alias.symlink_to(environment, target_is_directory=True)
511 harness.reject_environment("a symlinked environment root", alias, "ci")
512
513
514def cache_key_selftest(
515 environment: Path, pyproject: Path, lockfile: Path, harness: FilesystemHarness
516) -> None:
517 """Prove every source and receipt mutation invalidates the warm key."""
518 key = harness.cache_key("ci")
519 for label, path in (("pyproject.toml", pyproject), ("uv.lock", lockfile)):
520 original = path.read_bytes()
521 path.write_bytes(original + b"\n")
522 if key == harness.cache_key("ci"):
523 harness.fail(f"selftest cache key ignored changed {label} bytes")
524 path.write_bytes(original)
525 if key == harness.cache_key("dev"):
526 harness.fail("selftest cache key ignored the dependency group")
527 receipt = environment / harness.receipt_name
528 receipt_bytes = receipt.read_bytes()
529 receipt.chmod(0o600)
530 receipt.write_bytes(receipt_bytes + b" ")
531 receipt.chmod(harness.receipt_mode)
532 if key == harness.cache_key("ci"):
533 harness.fail("selftest cache key ignored changed receipt bytes")
534 receipt.chmod(0o600)
535 receipt.write_bytes(receipt_bytes)
536 receipt.chmod(harness.receipt_mode)