fix(827): bind D4 launcher bytes to fixture
This commit is contained in:
@@ -26,14 +26,14 @@ from pathlib import Path
|
|||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
|
|
||||||
HERE = Path(__file__).resolve().parent
|
HERE = Path(__file__).resolve().parent
|
||||||
# WI-3 is deliberately kept in its reviewed worktree until the release package
|
# WI-3 remains in a reviewed worktree until the release package contains the
|
||||||
# contains the gated launcher. This harness pins the source it will execute;
|
# gated launcher. The probe resolves that worktree portably and never falls
|
||||||
# falling back to the released `mosaic` binary is forbidden.
|
# back to the released `mosaic` binary.
|
||||||
GATED_WI_ROOT = HERE.parents[3].parent / "stack-cr-wi3-revoke"
|
GATED_WI_ROOT_OVERRIDE = os.environ.get("GATED_WI_ROOT")
|
||||||
|
GATED_WI_BRANCH = "refs/heads/feat/830-compaction-revoke"
|
||||||
GATED_WI_HEAD = "f400830738998db105107a2a4c69c7f2a2a6fd5d"
|
GATED_WI_HEAD = "f400830738998db105107a2a4c69c7f2a2a6fd5d"
|
||||||
GATED_LAUNCHER = GATED_WI_ROOT / "packages/mosaic/framework/tools/lease-broker/launch-runtime.py"
|
LEASE_BROKER_DIRECTORY = "packages/mosaic/framework/tools/lease-broker"
|
||||||
GATED_LAUNCHER_SHA256 = "e950e4224e280f16979d90cabb89aa1896c5ee28bed2df957e14d018d43cda82"
|
GATED_LAUNCHER_SHA256 = "e950e4224e280f16979d90cabb89aa1896c5ee28bed2df957e14d018d43cda82"
|
||||||
GATED_GENERATION_MODULE = GATED_LAUNCHER.with_name("lease_generation.py")
|
|
||||||
|
|
||||||
|
|
||||||
class PiRpc:
|
class PiRpc:
|
||||||
@@ -247,8 +247,74 @@ export default function register(pi: ExtensionAPI): void {
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def gated_launcher_precondition(root: Path, socket_path: Path, environment: dict[str, str]) -> None:
|
def repository_root() -> Path:
|
||||||
"""Refuse to launch unless the exact WI-3 launcher binds this run's fixture."""
|
for candidate in HERE.parents:
|
||||||
|
if (candidate / ".git").exists():
|
||||||
|
return candidate
|
||||||
|
raise RuntimeError("D4 precondition: probe repository root is unavailable")
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_gated_wi_root() -> Path:
|
||||||
|
"""Resolve an explicit override or the unique checked-out WI-3 branch."""
|
||||||
|
|
||||||
|
if GATED_WI_ROOT_OVERRIDE:
|
||||||
|
candidate = Path(GATED_WI_ROOT_OVERRIDE).expanduser()
|
||||||
|
candidates = [candidate]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
listing = subprocess.check_output(
|
||||||
|
["git", "-C", str(repository_root()), "worktree", "list", "--porcelain"],
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
except (OSError, subprocess.CalledProcessError) as error:
|
||||||
|
raise RuntimeError("D4 precondition: cannot enumerate WI-3 worktrees") from error
|
||||||
|
candidates = []
|
||||||
|
worktree: Path | None = None
|
||||||
|
head: str | None = None
|
||||||
|
branch: str | None = None
|
||||||
|
for line in [*listing.splitlines(), ""]:
|
||||||
|
if line.startswith("worktree "):
|
||||||
|
worktree = Path(line.removeprefix("worktree "))
|
||||||
|
head = None
|
||||||
|
branch = None
|
||||||
|
elif line.startswith("HEAD "):
|
||||||
|
head = line.removeprefix("HEAD ")
|
||||||
|
elif line.startswith("branch "):
|
||||||
|
branch = line.removeprefix("branch ")
|
||||||
|
elif not line and worktree is not None:
|
||||||
|
if head == GATED_WI_HEAD and branch == GATED_WI_BRANCH:
|
||||||
|
candidates.append(worktree)
|
||||||
|
worktree = None
|
||||||
|
if len(candidates) != 1:
|
||||||
|
raise RuntimeError("D4 precondition: WI-3 worktree is ambiguous or unavailable")
|
||||||
|
|
||||||
|
gated_root = candidates[0]
|
||||||
|
try:
|
||||||
|
if not gated_root.is_dir():
|
||||||
|
raise RuntimeError("D4 precondition: GATED_WI_ROOT is not a directory")
|
||||||
|
head = subprocess.check_output(
|
||||||
|
["git", "-C", str(gated_root), "rev-parse", "HEAD"], text=True
|
||||||
|
).strip()
|
||||||
|
except (OSError, subprocess.CalledProcessError) as error:
|
||||||
|
raise RuntimeError("D4 precondition: GATED_WI_ROOT is not a git worktree") from error
|
||||||
|
if head != GATED_WI_HEAD:
|
||||||
|
raise RuntimeError(f"D4 precondition: gated WI head mismatch: {head}")
|
||||||
|
return gated_root
|
||||||
|
|
||||||
|
|
||||||
|
def git_object_bytes(gated_root: Path, relative_path: str) -> bytes:
|
||||||
|
try:
|
||||||
|
return subprocess.check_output(
|
||||||
|
["git", "-C", str(gated_root), "show", f"{GATED_WI_HEAD}:{relative_path}"]
|
||||||
|
)
|
||||||
|
except (OSError, subprocess.CalledProcessError) as error:
|
||||||
|
raise RuntimeError(f"D4 precondition: missing pinned source {relative_path}") from error
|
||||||
|
|
||||||
|
|
||||||
|
def gated_launcher_precondition(
|
||||||
|
root: Path, socket_path: Path, environment: dict[str, str]
|
||||||
|
) -> tuple[Path, Path]:
|
||||||
|
"""Materialize verified WI-3 launcher bytes inside this fixture before exec."""
|
||||||
|
|
||||||
if environment.get("MOSAIC_LEASE_BROKER_SOCKET") != str(socket_path):
|
if environment.get("MOSAIC_LEASE_BROKER_SOCKET") != str(socket_path):
|
||||||
raise RuntimeError("D4 precondition: lease broker socket is not this fixture")
|
raise RuntimeError("D4 precondition: lease broker socket is not this fixture")
|
||||||
@@ -273,19 +339,19 @@ def gated_launcher_precondition(root: Path, socket_path: Path, environment: dict
|
|||||||
raise RuntimeError("D4 precondition: child write path escapes fixture root")
|
raise RuntimeError("D4 precondition: child write path escapes fixture root")
|
||||||
if socket_path.parent != root or root.parent != Path(tempfile.gettempdir()):
|
if socket_path.parent != root or root.parent != Path(tempfile.gettempdir()):
|
||||||
raise RuntimeError("D4 precondition: fixture socket is outside this run's temporary root")
|
raise RuntimeError("D4 precondition: fixture socket is outside this run's temporary root")
|
||||||
try:
|
|
||||||
head = subprocess.check_output(
|
gated_root = resolve_gated_wi_root()
|
||||||
["git", "-C", str(GATED_WI_ROOT), "rev-parse", "HEAD"], text=True
|
launcher_relative = f"{LEASE_BROKER_DIRECTORY}/launch-runtime.py"
|
||||||
).strip()
|
generation_relative = f"{LEASE_BROKER_DIRECTORY}/lease_generation.py"
|
||||||
launcher_bytes = GATED_LAUNCHER.read_bytes()
|
launcher_bytes = git_object_bytes(gated_root, launcher_relative)
|
||||||
launcher_source = launcher_bytes.decode("utf-8")
|
generation_bytes = git_object_bytes(gated_root, generation_relative)
|
||||||
generation_source = GATED_GENERATION_MODULE.read_text(encoding="utf-8")
|
|
||||||
except (OSError, subprocess.CalledProcessError, UnicodeDecodeError) as error:
|
|
||||||
raise RuntimeError("D4 precondition: gated WI launcher is unavailable") from error
|
|
||||||
if head != GATED_WI_HEAD:
|
|
||||||
raise RuntimeError(f"D4 precondition: gated WI head mismatch: {head}")
|
|
||||||
if hashlib.sha256(launcher_bytes).hexdigest() != GATED_LAUNCHER_SHA256:
|
if hashlib.sha256(launcher_bytes).hexdigest() != GATED_LAUNCHER_SHA256:
|
||||||
raise RuntimeError("D4 precondition: gated WI launcher hash mismatch")
|
raise RuntimeError("D4 precondition: gated WI launcher hash mismatch")
|
||||||
|
try:
|
||||||
|
launcher_source = launcher_bytes.decode("utf-8")
|
||||||
|
generation_source = generation_bytes.decode("utf-8")
|
||||||
|
except UnicodeDecodeError as error:
|
||||||
|
raise RuntimeError("D4 precondition: pinned launcher is not UTF-8") from error
|
||||||
|
|
||||||
register = launcher_source.find('"action": "register_anchor"')
|
register = launcher_source.find('"action": "register_anchor"')
|
||||||
initialize = launcher_source.find("initialize_runtime_generation(generation_file, generation)")
|
initialize = launcher_source.find("initialize_runtime_generation(generation_file, generation)")
|
||||||
@@ -305,6 +371,19 @@ def gated_launcher_precondition(root: Path, socket_path: Path, environment: dict
|
|||||||
):
|
):
|
||||||
raise RuntimeError("D4 precondition: launcher is not file-generation fixture-bound")
|
raise RuntimeError("D4 precondition: launcher is not file-generation fixture-bound")
|
||||||
|
|
||||||
|
fixture_launcher_dir = root / "pinned-lease-broker"
|
||||||
|
fixture_launcher_dir.mkdir(mode=0o700)
|
||||||
|
fixture_launcher = fixture_launcher_dir / "launch-runtime.py"
|
||||||
|
fixture_generation = fixture_launcher_dir / "lease_generation.py"
|
||||||
|
fixture_launcher.write_bytes(launcher_bytes)
|
||||||
|
fixture_generation.write_bytes(generation_bytes)
|
||||||
|
os.chmod(fixture_launcher, 0o600)
|
||||||
|
os.chmod(fixture_generation, 0o600)
|
||||||
|
if hashlib.sha256(fixture_launcher.read_bytes()).hexdigest() != GATED_LAUNCHER_SHA256:
|
||||||
|
raise RuntimeError("D4 precondition: fixture launcher hash mismatch")
|
||||||
|
environment["PYTHONPATH"] = str(fixture_launcher_dir)
|
||||||
|
return fixture_launcher, fixture_generation
|
||||||
|
|
||||||
|
|
||||||
def assert_d4(records: list[dict[str, Any]]) -> dict[str, object]:
|
def assert_d4(records: list[dict[str, Any]]) -> dict[str, object]:
|
||||||
def record_where(description: str, candidates: list[dict[str, Any]]) -> dict[str, Any]:
|
def record_where(description: str, candidates: list[dict[str, Any]]) -> dict[str, Any]:
|
||||||
@@ -492,7 +571,9 @@ def run_once(index: int) -> Path:
|
|||||||
environment = isolated_environment(root, index, workspace, socket_path, pi_log)
|
environment = isolated_environment(root, index, workspace, socket_path, pi_log)
|
||||||
# Must run before the fixture broker or Pi process is launched. It proves
|
# Must run before the fixture broker or Pi process is launched. It proves
|
||||||
# the launcher registers before exec and can only read this fixture socket.
|
# the launcher registers before exec and can only read this fixture socket.
|
||||||
gated_launcher_precondition(root, socket_path, environment)
|
fixture_launcher, fixture_generation = gated_launcher_precondition(
|
||||||
|
root, socket_path, environment
|
||||||
|
)
|
||||||
broker = subprocess.Popen(
|
broker = subprocess.Popen(
|
||||||
[
|
[
|
||||||
sys.executable,
|
sys.executable,
|
||||||
@@ -502,7 +583,7 @@ def run_once(index: int) -> Path:
|
|||||||
"--log",
|
"--log",
|
||||||
str(generation_log),
|
str(generation_log),
|
||||||
"--generation-module",
|
"--generation-module",
|
||||||
str(GATED_GENERATION_MODULE),
|
str(fixture_generation),
|
||||||
],
|
],
|
||||||
text=True,
|
text=True,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
@@ -512,7 +593,7 @@ def run_once(index: int) -> Path:
|
|||||||
pi = PiRpc(
|
pi = PiRpc(
|
||||||
[
|
[
|
||||||
sys.executable,
|
sys.executable,
|
||||||
str(GATED_LAUNCHER),
|
str(fixture_launcher),
|
||||||
"--runtime",
|
"--runtime",
|
||||||
"pi",
|
"pi",
|
||||||
"--",
|
"--",
|
||||||
|
|||||||
Reference in New Issue
Block a user