ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
python_lock_policy_uv_runner.py
Go to the documentation of this file.
1# SPDX-License-Identifier: MIT
2# Copyright (c) 2026 Brighton Sikarskie
3"""Run lock-policy uv operations through the authenticated bootstrap boundary."""
4
5from __future__ import annotations
6
7import hashlib
8import importlib.util
9import json
10import os
11import platform
12import shlex
13import shutil
14import subprocess
15import sys
16import tempfile
17from collections.abc import Mapping
18from dataclasses import dataclass, field
19from pathlib import Path
20from types import ModuleType
21
22
23@dataclass(frozen=True)
24class AuthenticatedUv:
25 """Describe one bootstrap-owned uv execution authority."""
26
27 bootstrap: Path
28 manifest: Path
29 cache_root: Path
30 extra_environment: Mapping[str, str] = field(default_factory=dict)
31
32 def run(
33 self,
34 arguments: list[str],
35 *,
36 cwd: Path | None = None,
37 env: Mapping[str, str] | None = None,
38 timeout: int = 30,
39 ) -> subprocess.CompletedProcess[str]:
40 """Run exact uv arguments without receiving or executing a cache path."""
41 environment = {**(os.environ if env is None else env), **self.extra_environment}
42 return subprocess.run( # noqa: S603 -- fixed interpreter/bootstrap and exact argv.
43 [
44 "/usr/bin/python3",
45 "-I",
46 "-S",
47 str(self.bootstrap),
48 "--manifest",
49 str(self.manifest),
50 "--cache-root",
51 str(self.cache_root),
52 "--run",
53 *arguments,
54 ],
55 cwd=cwd,
56 check=False,
57 capture_output=True,
58 text=True,
59 timeout=timeout,
60 env=environment,
61 )
62
63
64def find_uv(
65 root: Path,
66 version: str,
67 manifest: Path,
68 cache_roots: tuple[Path, ...],
69) -> AuthenticatedUv:
70 """Resolve an authenticated bootstrap runner without returning a uv path."""
71 bootstrap = root / "scripts/dev/bootstrap_uv.py"
72 for cache_root in cache_roots:
73 candidate = AuthenticatedUv(bootstrap, manifest, cache_root)
74 probe = candidate.run(["--version"], timeout=10)
75 if probe.returncode == 0 and probe.stdout.split()[:2] == ["uv", version]:
76 return candidate
77 message = "authenticated pinned uv is unavailable; run just setup"
78 raise ValueError(message)
79
80
81def export_findings(
82 root: Path,
83 exports: Mapping[str, Path],
84 uv: AuthenticatedUv,
85) -> list[str]:
86 """Offline-regenerate every managed-target export and byte-compare it."""
87 findings: list[str] = []
88 environment = {**os.environ, "UV_PYTHON_DOWNLOADS": "never"}
89 lock_check = uv.run(
90 ["--directory", str(root), "--no-config", "lock", "--check", "--offline"],
91 env=environment,
92 )
93 if lock_check.returncode != 0:
94 return [f"uv.lock is stale: {lock_check.stderr.strip()}"]
95 with tempfile.TemporaryDirectory(prefix="ra8-uv-policy-") as raw:
96 temp = Path(raw)
97 shutil.copy2(root / "pyproject.toml", temp / "pyproject.toml")
98 shutil.copy2(root / "uv.lock", temp / "uv.lock")
99 for group, relative in exports.items():
100 findings.extend(_one_export_findings(root, temp, group, relative, uv))
101 return findings
102
103
104def _one_export_findings(
105 root: Path,
106 temp: Path,
107 group: str,
108 relative: Path,
109 uv: AuthenticatedUv,
110) -> list[str]:
111 """Generate and compare one locked requirements export."""
112 output = temp / relative
113 output.parent.mkdir(parents=True, exist_ok=True)
114 arguments = [
115 "--no-config",
116 "export",
117 "--offline",
118 "--locked",
119 "--only-group",
120 group,
121 "--no-emit-project",
122 "--format",
123 "requirements-txt",
124 "--output-file",
125 str(relative),
126 ]
127 environment = {**os.environ, "UV_PYTHON_DOWNLOADS": "never"}
128 result = uv.run(arguments, cwd=temp, env=environment)
129 if result.returncode != 0:
130 return [f"{group} export failed: {result.stderr.strip()}"]
131 if output.read_bytes() != (root / relative).read_bytes():
132 return [f"{relative} is stale versus uv.lock group {group}"]
133 return []
134
135
136def _load_bootstrap(bootstrap_path: Path) -> ModuleType:
137 """Load the reviewed bootstrap only to build offline adversarial fixtures."""
138 spec = importlib.util.spec_from_file_location("ra8_uv_runner_fixture", bootstrap_path)
139 if spec is None or spec.loader is None:
140 message = "cannot load uv bootstrap fixture helper"
141 raise RuntimeError(message)
142 module = importlib.util.module_from_spec(spec)
143 sys.modules[spec.name] = module
144 spec.loader.exec_module(module)
145 return module
146
147
148def _attack_runner(
149 root: Path,
150 bootstrap_path: Path,
151 mode: str,
152) -> tuple[AuthenticatedUv, Path]:
153 """Build one exact-cache runner whose trusted payload mutates its cache."""
154 bootstrap = _load_bootstrap(bootstrap_path)
155 key = bootstrap.asset_key(platform.system(), platform.machine())
156 asset_name = bootstrap.expected_asset_name(key)
157 victim = root / "unauthenticated-executed"
158 binary = _attack_script(mode, victim)
159 payload = bootstrap.synthetic_archive(asset_name, binary)
160 manifest = {
161 "schema": 1,
162 "repository": "astral-sh/uv",
163 "version": "0.0.0",
164 "assets": {key: {"name": asset_name, "sha256": hashlib.sha256(payload).hexdigest()}},
165 }
166 manifest_path = root / "uv_release.json"
167 manifest_path.write_text(json.dumps(manifest), encoding="ascii")
168 destination = bootstrap.cache_destination(root / "cache", "0.0.0", asset_name)
169 destination.parent.mkdir(parents=True)
170 archive = destination.parent / asset_name
171 archive.write_bytes(payload)
172 destination.write_bytes(binary)
173 archive.chmod(bootstrap.PUBLIC_ARCHIVE_MODE)
174 destination.chmod(bootstrap.PUBLIC_EXECUTABLE_MODE)
175 replacement = root / "replacement"
176 replacement.write_bytes(_victim_script(victim))
177 replacement.chmod(bootstrap.PUBLIC_EXECUTABLE_MODE)
178 environment = {
179 "RA8_UV_ATTACK_CACHE": str(destination),
180 "RA8_UV_ATTACK_REPLACEMENT": str(replacement),
181 }
182 return AuthenticatedUv(bootstrap_path, manifest_path, root / "cache", environment), victim
183
184
185def _attack_script(mode: str, victim: Path) -> bytes:
186 """Return a pinned test uv that attacks its cache only after execution starts."""
187 mutation = (
188 'cat "$RA8_UV_ATTACK_REPLACEMENT" >"$RA8_UV_ATTACK_CACHE"'
189 if mode == "inode"
190 else (
191 'mv "$RA8_UV_ATTACK_CACHE" "$RA8_UV_ATTACK_CACHE.displaced"\n'
192 'mv "$RA8_UV_ATTACK_REPLACEMENT" "$RA8_UV_ATTACK_CACHE"'
193 )
194 )
195 return (
196 "#!/bin/sh\nset -eu\n"
197 f"{mutation}\n"
198 'if [ "${1:-}" = --version ]; then echo uv 0.0.0; fi\n'
199 f"test ! -e {shlex.quote(str(victim))}\n"
200 ).encode("ascii")
201
202
203def _victim_script(victim: Path) -> bytes:
204 """Return the unauthenticated replacement that must never execute."""
205 return f"#!/bin/sh\ntouch {victim}\necho uv 0.0.0\n".encode("ascii")
206
207
208def execution_attack_selftest(
209 bootstrap: Path,
210 exports: Mapping[str, Path],
211) -> list[str]:
212 """Prove actual lock/export calls reject path and same-inode cache races."""
213 failures: list[str] = []
214 for mode in ("path", "inode"):
215 with tempfile.TemporaryDirectory(prefix=f"ra8-uv-runner-{mode}-") as raw:
216 root = Path(raw)
217 (root / "pyproject.toml").write_text("[project]\nname='fixture'\n", encoding="ascii")
218 (root / "uv.lock").write_text("version = 1\n", encoding="ascii")
219 for relative in exports.values():
220 target = root / relative
221 target.parent.mkdir(parents=True, exist_ok=True)
222 target.write_bytes(b"")
223 runner, victim = _attack_runner(root, bootstrap, mode)
224 findings = export_findings(root, exports, runner)
225 if not findings:
226 failures.append(f"post-auth {mode} cache attack passed lock/export execution")
227 if victim.exists():
228 failures.append(f"post-auth {mode} replacement executed through lock/export")
229 return failures