From cb2a739c8ba857fcc825e276ba185f07ce20c482 Mon Sep 17 00:00:00 2001 From: Dmitry Labintcev Date: Mon, 28 Sep 2026 13:18:17 +1000 Subject: [PATCH] Guard the released loader protocol against in-place changes Every release shares PLUGIN_DATA/runtime-v1/bootstrap.py, and the loader's publish() raises when those bytes differ. A release that edits sol_bootstrap.py and regenerates the pinned hook commands therefore passes the existing pin tests, then fails every installed task with "runtime collision or corruption" and disables all hooks. Freeze the bootstrap digest for the released runtime directory, and show that the same change loads once it moves to a new runtime directory. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + .../sol-codex/scripts/test_hook_commands.py | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbef234..690186d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ All notable changes to this project are documented here. - Recorded a same-fixture bounded-search development pair with equal verification and lower observed provider tokens/time, while keeping it separate from held-out evidence. - Recorded a separate cache-boundary repair pair with equal verification, fewer observed provider tokens, and longer elapsed time; expanded the research review with prompt-cache economics. - Recorded a historical CRLF loader pair whose apparent ON success failed a broader behavior matrix; added regression tests for source-line-ending invariance and bootstrap pin integrity. +- Added a loader-protocol guard: `sol_bootstrap.py` bytes are frozen for the released `runtime-v1` directory, because changed bytes there would make every installed task fail with `runtime collision or corruption`. A companion test shows that the same change under a new runtime directory loads. - Probed macOS filesystem isolation for historical-task agents and documented the remaining protection work before a confirmatory campaign. - Added a cost-frontier research protocol based on provider-billed coding-agent studies and independent Astra review. - Extended the opt-in artifact search with bounded line-range retrieval and explicit reporting when long matched lines are omitted. diff --git a/plugins/sol-codex/scripts/test_hook_commands.py b/plugins/sol-codex/scripts/test_hook_commands.py index eadacd0..3b40a2b 100644 --- a/plugins/sol-codex/scripts/test_hook_commands.py +++ b/plugins/sol-codex/scripts/test_hook_commands.py @@ -2,8 +2,11 @@ from __future__ import annotations +import base64 +import hashlib import json import os +import re import shutil import subprocess import sys @@ -14,6 +17,13 @@ PLUGIN_ROOT = Path(__file__).resolve().parents[1] +# Every release shares PLUGIN_DATA//bootstrap.py. Loader +# bytes that change under a released directory make publish() raise in every +# task, so all hooks degrade. A loader change needs a new runtime directory +# and regenerated hook commands. +RELEASED_BOOTSTRAP_DIGESTS = { + "runtime-v1": "84e04d0b3dcffad4aa060ec30194f5b8168c8c381b1210e0f5192e6f583d9e1f", +} class HookCommandTests(unittest.TestCase): @@ -190,6 +200,61 @@ def test_ambiguous_unbound_root_is_rejected(self) -> None: self.assertEqual(result.stdout, "") self.assertIn("runtime unavailable or ambiguous", result.stderr) + def launcher_source(self) -> str: + encoded = re.search(r"b64decode\(\W*([A-Za-z0-9+/=]{40,})", self.commands[0]) + self.assertIsNotNone(encoded) + return base64.b64decode(encoded.group(1)).decode("utf-8") + + def test_released_runtime_directory_keeps_its_bootstrap_bytes(self) -> None: + source = (PLUGIN_ROOT / "scripts" / "sol_bootstrap.py").read_bytes().replace(b"\r\n", b"\n") + digest = hashlib.sha256(source).hexdigest() + directories = set(re.findall(r'"(runtime-v[0-9]+)"', source.decode("utf-8"))) + self.assertEqual(len(directories), 1, directories) + directory = directories.pop() + launcher = self.launcher_source() + self.assertIn(f'"{directory}"', launcher) + self.assertIn(digest, launcher) + if directory in RELEASED_BOOTSTRAP_DIGESTS: + self.assertEqual( + digest, RELEASED_BOOTSTRAP_DIGESTS[directory], + f"sol_bootstrap.py changed under released {directory}; installed tasks would fail " + "with 'runtime collision or corruption'. Move the loader to a new runtime directory " + "and regenerate the hook commands.", + ) + + @unittest.skipIf(os.name == "nt", "builds a POSIX launcher command") + def test_changed_loader_needs_a_new_runtime_directory(self) -> None: + with tempfile.TemporaryDirectory() as directory: + base = Path(directory) + data = base / "data" + released = base / "released" + self.fixture(released, "released") + self.assertEqual(self.invoke(released, data).returncode, 0) + original = (released / "scripts" / "sol_bootstrap.py").read_bytes().replace(b"\r\n", b"\n") + launcher = self.launcher_source() + for runtime, expected in (("runtime-v1", None), ("runtime-v2", "upgraded")): + with self.subTest(runtime=runtime): + root = base / runtime + self.fixture(root, "upgraded") + changed = original.replace(b'"runtime-v1"', f'"{runtime}"'.encode()) + b"# changed loader\n" + (root / "scripts" / "sol_bootstrap.py").write_bytes(changed) + code = launcher.replace('"runtime-v1"', f'"{runtime}"').replace( + hashlib.sha256(original).hexdigest(), hashlib.sha256(changed).hexdigest(), + ) + environment = os.environ.copy() + environment.update({"PLUGIN_ROOT": str(root), "PLUGIN_DATA": str(data), "PYTHONDONTWRITEBYTECODE": "1"}) + result = subprocess.run( + [sys.executable, "-c", code], + input=json.dumps({"session_id": "next-release", "hook_event_name": "SessionStart"}), + text=True, capture_output=True, env=environment, check=False, + ) + self.assertEqual(result.returncode, 0, result.stderr) + if expected is None: + self.assertEqual(result.stdout, "") + self.assertIn("runtime collision or corruption", result.stderr) + else: + self.assertEqual(json.loads(result.stdout)["runtime"], expected, result.stderr) + if __name__ == "__main__": unittest.main()