Refuse stale installed owner packages despite matching version metadata
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
parent
be42de7caf
commit
7a61383e59
4 changed files with 86 additions and 3 deletions
|
|
@ -43,6 +43,33 @@ def install_claude(output: Path, source: Path, sha256: str, version: str) -> dic
|
|||
"expected_version": version, "source": str(source)}
|
||||
|
||||
|
||||
def verify_source_files(site: Path, mappings: list[tuple[Path, str, str]]) -> dict:
|
||||
"""Refuse stale/missing/extra package contents even when versions match."""
|
||||
expected = {}
|
||||
for source, prefix, destination in mappings:
|
||||
tracked = checked(["git", "-C", str(source), "ls-files", prefix]).splitlines()
|
||||
if not tracked:
|
||||
raise ValueError("owner package source mapping is empty")
|
||||
for name in tracked:
|
||||
relative = Path(destination) / Path(name).relative_to(prefix)
|
||||
wanted = hashlib.sha256((source / name).read_bytes()).hexdigest()
|
||||
installed = site / relative
|
||||
if (not installed.is_file() or installed.is_symlink()
|
||||
or hashlib.sha256(installed.read_bytes()).hexdigest() != wanted):
|
||||
raise ValueError(f"owner package content mismatch: {relative}")
|
||||
expected[relative.as_posix()] = wanted
|
||||
actual = set()
|
||||
for package in {Path(name).parts[0] for name in expected}:
|
||||
for path in (site / package).rglob("*"):
|
||||
if path.is_file() and "__pycache__" not in path.parts:
|
||||
actual.add(path.relative_to(site).as_posix())
|
||||
if actual != set(expected):
|
||||
raise ValueError("owner package has unexpected installed files")
|
||||
return {"files_verified": len(expected), "manifest_sha256": hashlib.sha256(
|
||||
json.dumps(expected, sort_keys=True, separators=(",", ":")).encode()
|
||||
).hexdigest()}
|
||||
|
||||
|
||||
def build(output: Path, rein_source: Path, llm_source: Path,
|
||||
claude_binary: Path | None = None, claude_sha256: str | None = None,
|
||||
claude_version: str | None = None, *, owner_runtime: bool = False) -> dict:
|
||||
|
|
@ -68,8 +95,10 @@ def build(output: Path, rein_source: Path, llm_source: Path,
|
|||
output.mkdir(parents=True, exist_ok=False)
|
||||
checked(["/usr/bin/python3", "-m", "venv", "--copies", "--without-pip", str(output)])
|
||||
if owner_runtime:
|
||||
refresh = [arg for name in revisions for arg in ("--refresh-package", name)]
|
||||
checked(["uv", "sync", "--project", str(rein_source), "--frozen", "--no-editable",
|
||||
"--no-dev", "--extra", "glas", "--extra", "llm", "--python", "/usr/bin/python3"],
|
||||
"--no-dev", "--extra", "glas", "--extra", "llm", "--python", "/usr/bin/python3",
|
||||
*refresh],
|
||||
env={**os.environ, "UV_PROJECT_ENVIRONMENT": str(output)})
|
||||
else:
|
||||
checked(["uv", "pip", "install", "--python", str(output / "bin/python3"),
|
||||
|
|
@ -93,6 +122,23 @@ def build(output: Path, rein_source: Path, llm_source: Path,
|
|||
metadata["claude"] = install_claude(output, claude_binary, claude_sha256, claude_version)
|
||||
metadata["source_revisions"] = revisions
|
||||
if owner_runtime:
|
||||
lock = json.loads((rein_source / "deploy/runtime-contract-lock.json").read_text())
|
||||
sources = {x["distribution"]: (rein_source / x["source"]).resolve()
|
||||
for x in lock["dependencies"]}
|
||||
site = Path(checked([str(output / "bin/python3"), "-I", "-B", "-c",
|
||||
"import sysconfig; print(sysconfig.get_path('purelib'))"]))
|
||||
if not site.resolve().is_relative_to(output.resolve()):
|
||||
raise ValueError("owner site-packages is outside artifact")
|
||||
metadata["source_contents"] = verify_source_files(site, [
|
||||
(rein_source, "rein_aharness", "rein_aharness"),
|
||||
(sources["llm-connect"], "llm_connect", "llm_connect"),
|
||||
(sources["glas-harness"], "src/glas_harness", "glas_harness"),
|
||||
(sources["glas-harness"], "profiles", "glas_harness/data/profiles"),
|
||||
(sources["glas-harness"], "registry/reins", "glas_harness/data/reins"),
|
||||
(sources["sandboxer"], "src/sandboxer", "sandboxer"),
|
||||
(sources["sandboxer"], "profiles", "sandboxer/data/profiles"),
|
||||
(sources["sandboxer"], "extensions", "sandboxer/data/extensions"),
|
||||
])
|
||||
metadata["owner_runtime"] = True
|
||||
metadata["runtime_contract"] = lock_report
|
||||
metadata["uv_lock_sha256"] = hashlib.sha256(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue