From b4e3b3b735b4b686793f25d0b814a847b0d34035 Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Fri, 24 Jul 2026 18:29:52 +0300 Subject: [PATCH] fix(simulation): inspect namespace through netlink --- simulation/s1/stock_rover_lifecycle.py | 37 ++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/simulation/s1/stock_rover_lifecycle.py b/simulation/s1/stock_rover_lifecycle.py index ae5d18c..d5bff80 100644 --- a/simulation/s1/stock_rover_lifecycle.py +++ b/simulation/s1/stock_rover_lifecycle.py @@ -5,6 +5,7 @@ import hashlib import os import re import shutil +import socket import sys import time from datetime import UTC, datetime @@ -79,18 +80,38 @@ def main() -> int: parser.error(f"the lifecycle harness requires WSL distribution {EXPECTED_DISTRO}") paths = StockRoverTargetPaths.from_d_root(args.d_root) + evidence_root = paths.d_root / "artifacts/s1/lifecycle" / args.run_id + evidence_root.mkdir(mode=0o700, parents=True, exist_ok=False) lifecycle_profile_path = args.lifecycle_profile.expanduser().resolve() s0_profile_path = args.s0_profile.expanduser().resolve() - lifecycle_profile = load_stock_rover_lifecycle_profile(lifecycle_profile_path) - guard = S0WorkerGuard(s0_profile_path) - _preflight(paths, guard.profile) + try: + lifecycle_profile = load_stock_rover_lifecycle_profile(lifecycle_profile_path) + guard = S0WorkerGuard(s0_profile_path) + _preflight(paths, guard.profile) + interface_names = _loopback_only_interfaces() + except Exception as exc: + write_json_atomic( + evidence_root / "result.json", + { + "schema_version": "missioncore.s1b-stock-rover-result/v1", + "verdict": "fail", + "phase": "preflight", + "detail": f"{type(exc).__name__}: {exc}", + "run_id": args.run_id, + "mission_core_commit": args.mission_core_commit, + "network_scope": "loopback-only-netns-required", + "actuator_authority": False, + "direct_actuator_setpoints_allowed": False, + "finished_at_utc": _utc_now(), + }, + ) + _write_digest_index(evidence_root) + print("verdict=fail") + print(f"evidence_root={evidence_root}") + return 1 artifact_runs_root = paths.d_root / "artifacts/s1/runs" runtime_runs_root = paths.d_root / "runtime/s1/runs" - evidence_root = paths.d_root / "artifacts/s1/lifecycle" / args.run_id - evidence_root.mkdir(mode=0o700, parents=True, exist_ok=False) - - interface_names = _loopback_only_interfaces() write_json_atomic( evidence_root / "network.json", { @@ -239,7 +260,7 @@ def _preflight(paths: StockRoverTargetPaths, profile: S0Profile) -> None: def _loopback_only_interfaces() -> tuple[str, ...]: - interfaces = tuple(sorted(path.name for path in Path("/sys/class/net").iterdir())) + interfaces = tuple(sorted(name for _, name in socket.if_nameindex())) if interfaces != ("lo",): raise RuntimeError(f"S1B must run in a loopback-only namespace; observed {interfaces}") return interfaces