swactor/crates/bindings/python/tests/test_bootstrap.py
Zachery Aaron Shores-Chmielewski 77f3cdc660 feat(data-plane): add exec bootstrap ABI for job processes
Define the spawn-time handoff a job process consumes before any
application code runs: two inherited descriptors named by
SWACTOR_ARENA_FD and SWACTOR_WAKE_FD, and a fixed 48-byte little-endian
header at arena offset 0 naming one control-ring region.

- Canonical header layout, shared parser, and a host writer that leases
  the header region and control ring disjointly under the arena's own
  placement law, zeroes the ring, stamps its generation, and returns the
  handoff (env map, inheritable arena and wake descriptors, host wake
  eventfd) only after every write completes.
- Python binding gains swactor.run(main): map the arena read-only, take
  ground truth from fstat, validate through the shared parser, arm
  FD_CLOEXEC on the wake descriptor, close the arena descriptor after
  mapping, and drive main on asyncio with Context.data carrying the
  resolved state. Fail-fast BootstrapError before main on any defect.
- Rewrite jobs/tiny_linear_inference.py against the approved path API and
  record the slice, invariants, and remaining bridge work in the handoff
  doc.

Verified with 12 new data-plane bootstrap guarantee tests (parser defect
table, fuzzed pages, writer round-trip), 29 binding tests across
in-process and exec boundaries, and full data-plane and iroh-driver
suites with no regressions.
2026-08-20 20:43:44 +04:00

460 lines
14 KiB
Python

"""Bootstrap-slice behavior guarantees for the ``swactor`` Python binding.
Defends the agreed invariants:
- B1 deterministic handoff: a valid exec-time bootstrap reaches ``main``
- B2 fail-fast purity: every bootstrap defect raises ``BootstrapError``
before ``main`` is invoked
- B3 version gate rejects, never guesses
- B4 arbitrary header bytes never crash the process
- B5 grandchild isolation: post-bootstrap children inherit no bootstrap fds
- B6 wake opacity: bootstrap does not consume the wake descriptor
- B7 exit-code contract across a real process boundary
- B8 the two environment names are the whole handoff ABI
- B9 no identity leakage on the Python-visible surface
"""
from __future__ import annotations
import os
import random
import select
import struct
import subprocess
import sys
import tempfile
from pathlib import Path
import pytest
import swactor
MAGIC = int.from_bytes(b"SWBS", "little")
ENV_ARENA = "SWACTOR_ARENA_FD"
ENV_WAKE = "SWACTOR_WAKE_FD"
VERSION = 1
ARENA_SIZE = 1 << 20
MAIN_RAN = []
# ─── fixtures ────────────────────────────────────────────────────────────────
def pack_header(
arena_size=ARENA_SIZE,
ring_offset=4096,
ring_capacity=8192,
ring_generation=1,
*,
magic=MAGIC,
version=VERSION,
reserved0=0,
reserved1=0,
):
return struct.pack(
"<IHHQQQQ",
magic,
version,
reserved0,
arena_size,
ring_offset,
ring_capacity,
ring_generation,
) + struct.pack("<Q", reserved1)
def _create_backing() -> int:
if hasattr(os, "memfd_create"):
return os.memfd_create("test-arena", 0)
# Not every interpreter exposes memfd_create; an unlinked temp file is an
# equally anonymous regular-file inode for ftruncate/pwrite/mmap.
fd, path = tempfile.mkstemp(prefix="swactor-test-arena-")
os.unlink(path)
return fd
def make_arena(header: bytes, size: int = ARENA_SIZE) -> int:
fd = _create_backing()
os.ftruncate(fd, size)
os.pwrite(fd, header, 0)
return fd
def make_wake(signaled: bool) -> tuple[int, int]:
read_fd, write_fd = os.pipe()
if signaled:
os.write(write_fd, b"x")
# Keep the write end open: closing it would signal EOF and make the read
# end "readable" without a wake ever being delivered.
return read_fd, write_fd
@pytest.fixture
def valid_env(monkeypatch):
"""A complete, valid bootstrap in the current process."""
keep_open = []
def install(*, header=None, arena_size=ARENA_SIZE, signaled=True):
arena_fd = make_arena(
header if header is not None else pack_header(arena_size=arena_size),
arena_size,
)
wake_fd, write_fd = make_wake(signaled)
keep_open.append(write_fd)
# Make the wake fd inheritable so only run()'s CLOEXEC can hide it
# from children (B5 evidence).
os.set_inheritable(wake_fd, True)
monkeypatch.setenv(ENV_ARENA, str(arena_fd))
monkeypatch.setenv(ENV_WAKE, str(wake_fd))
return arena_fd, wake_fd
yield install
for write_fd in keep_open:
os.close(write_fd)
# ─── B1 / B9: valid bootstrap reaches main with a clean surface ─────────────
def test_run_constructs_context_and_data(valid_env):
valid_env()
seen = {}
async def main(ctx):
seen["ctx"] = ctx
swactor.run(main)
assert isinstance(seen["ctx"], swactor.Context)
assert isinstance(seen["ctx"].data, swactor.DataPlane)
# B9: no identities leak onto the surface.
assert {a for a in dir(seen["ctx"]) if not a.startswith("_")} == {"data"}
leaked = {"arena", "resolved", "control_ring", "offset", "generation"}
assert not leaked & {a for a in dir(seen["ctx"].data) if not a.startswith("_")}
def test_run_passes_the_same_context_instance(valid_env):
valid_env()
seen = {}
async def main(ctx):
seen["one"] = ctx
seen["data"] = ctx.data
swactor.run(main)
assert seen["one"].data is seen["data"]
# ─── B5: fd hygiene ──────────────────────────────────────────────────────────
def test_arena_fd_closed_after_run(valid_env):
arena_fd, _ = valid_env()
async def main(ctx):
pass
swactor.run(main)
with pytest.raises(OSError):
os.fstat(arena_fd)
# ─── B6: wake opacity ────────────────────────────────────────────────────────
@pytest.mark.parametrize("signaled,expected", [(True, 1), (False, 0)])
def test_bootstrap_does_not_consume_wake(valid_env, signaled, expected):
valid_env(signaled=signaled)
readable = {}
async def main(ctx):
wake = int(os.environ[ENV_WAKE])
readable["value"] = int(bool(select.select([wake], [], [], 0)[0]))
swactor.run(main)
assert readable["value"] == expected
def test_wake_fd_cloexec_armed_by_run(valid_env):
_, wake_fd = valid_env()
async def main(ctx):
child = subprocess.Popen(
[
sys.executable,
"-c",
"import os, sys; "
"sys.exit(0 if sys.argv[1] not in os.listdir('/proc/self/fd') else 3)",
str(wake_fd),
],
close_fds=False,
)
child.wait()
assert child.returncode != 3, "close_fds=False child saw the wake fd"
swactor.run(main)
# ─── B2 / B3 / B4: defect table, in process ─────────────────────────────────
def _expect_bootstrap_failure(monkeypatch, header=None, *, env=None, arena_size=ARENA_SIZE, match=""):
calls = []
async def main(ctx): # pragma: no cover - must never run
calls.append(ctx)
if env is not None:
monkeypatch.setenv(ENV_ARENA, str(env[0]))
monkeypatch.setenv(ENV_WAKE, str(env[1]))
else:
arena_fd = make_arena(header if header is not None else pack_header(arena_size=arena_size), arena_size)
wake_fd, _keep_wake = make_wake(True)
monkeypatch.setenv(ENV_ARENA, str(arena_fd))
monkeypatch.setenv(ENV_WAKE, str(wake_fd))
with pytest.raises(swactor.BootstrapError, match=match) as excinfo:
swactor.run(main)
assert isinstance(excinfo.value, swactor.SwactorError)
assert calls == [], "main must never run on a bootstrap defect"
def test_missing_env_rejected(monkeypatch):
monkeypatch.delenv(ENV_ARENA, raising=False)
monkeypatch.delenv(ENV_WAKE, raising=False)
calls = []
async def main(ctx): # pragma: no cover - must never run
calls.append(ctx)
with pytest.raises(swactor.BootstrapError, match="is not set"):
swactor.run(main)
assert calls == []
def test_non_numeric_fd_rejected(monkeypatch):
_expect_bootstrap_failure(
monkeypatch, env=("not-a-number", "also-not"), match="not a descriptor number"
)
def test_negative_fd_rejected(monkeypatch):
_expect_bootstrap_failure(monkeypatch, env=("-1", "-1"), match="non-negative")
def test_closed_fd_rejected(monkeypatch):
closed = os.pipe()[0]
os.close(closed)
_expect_bootstrap_failure(monkeypatch, env=(closed, 1), match="stat arena descriptor")
def test_short_backing_rejected(monkeypatch):
_expect_bootstrap_failure(
monkeypatch,
header=b"\0" * 16,
arena_size=16,
match="shorter than the 48-byte bootstrap header",
)
@pytest.mark.parametrize(
"header,match",
[
(pack_header(magic=MAGIC ^ 0xFF), "magic mismatch"),
(pack_header(version=0), "unsupported bootstrap version 0"),
(pack_header(version=2), "unsupported bootstrap version 2"),
(pack_header(reserved0=1), "reserved bytes at offset 6"),
(pack_header(reserved1=1), "reserved bytes at offset 40"),
(
pack_header(arena_size=ARENA_SIZE, ring_offset=16),
"overlaps the bootstrap header",
),
(
pack_header(ring_offset=ARENA_SIZE, ring_capacity=1),
"exceeds arena size",
),
(
pack_header(ring_offset=2**64 - 8, ring_capacity=16),
"exceeds arena size",
),
(pack_header(ring_capacity=0), "capacity is zero"),
(pack_header(ring_generation=0), "generation is zero"),
],
)
def test_header_defects_rejected(monkeypatch, header, match):
_expect_bootstrap_failure(monkeypatch, header, match=match)
def test_lying_arena_size_rejected(monkeypatch):
_expect_bootstrap_failure(
monkeypatch,
pack_header(arena_size=ARENA_SIZE),
arena_size=ARENA_SIZE + 1,
match="disagrees with backing length",
)
def test_arbitrary_header_bytes_never_crash(monkeypatch):
rng = random.Random(0x53574253)
for _ in range(128):
fields = {
"arena_size": rng.choice([rng.getrandbits(64), ARENA_SIZE, 0, 1]),
"ring_offset": rng.choice(
[rng.getrandbits(64), 16, 4096, ARENA_SIZE, 2**64 - 8]
),
"ring_capacity": rng.choice([rng.getrandbits(64), 0, 1, 8192, 2**64 - 1]),
"ring_generation": rng.choice([rng.getrandbits(64), 0, 1, 7]),
}
header = pack_header(**fields)
ran = []
async def main(ctx): # pragma: no cover - only on accidental success
ran.append(ctx)
arena_fd = make_arena(header)
wake_fd, _keep_wake = make_wake(False)
monkeypatch.setenv(ENV_ARENA, str(arena_fd))
monkeypatch.setenv(ENV_WAKE, str(wake_fd))
end = fields["ring_offset"] + fields["ring_capacity"]
should_parse = (
fields["arena_size"] == ARENA_SIZE
and fields["ring_capacity"] > 0
and fields["ring_generation"] > 0
and fields["ring_offset"] >= 48
and end <= ARENA_SIZE
)
if should_parse:
swactor.run(main)
assert ran, "parser accepted fields that satisfy no invariant"
else:
with pytest.raises(swactor.BootstrapError):
swactor.run(main)
assert not ran
# ─── B7 / B1 / B8: real process boundary ────────────────────────────────────
PROBE = Path(__file__).parent / "probe.py"
def _spawn(argv, *, arena_fd, wake_fd, env_extra=None):
env = {k: v for k, v in os.environ.items() if k not in (ENV_ARENA, ENV_WAKE)}
env[ENV_ARENA] = str(arena_fd)
env[ENV_WAKE] = str(wake_fd)
if env_extra:
env.update(env_extra)
for fd in (arena_fd, wake_fd):
os.set_inheritable(fd, True)
return subprocess.run(
argv,
env=env,
pass_fds=(arena_fd, wake_fd),
capture_output=True,
text=True,
timeout=60,
)
def _parse_facts(stdout):
facts = dict(
part.split("=", 1) for part in stdout.strip().split() if "=" in part
)
return facts
def test_probe_succeeds_across_exec_boundary():
arena_fd = make_arena(pack_header())
wake_fd, _keep_wake = make_wake(signaled=True)
result = _spawn([sys.executable, str(PROBE)], arena_fd=arena_fd, wake_fd=wake_fd)
assert result.returncode == 0, result.stderr
facts = _parse_facts(result.stdout)
assert facts["HAS_DATA"] == "1"
assert facts["WAKE_READABLE"] == "1", "B6: presignaled wake must survive exec"
assert facts["WAKE_LEAKED"] == "0", "B5: grandchild must not see the wake fd"
def test_probe_reports_unsignaled_wake_across_exec_boundary():
arena_fd = make_arena(pack_header())
wake_fd, _keep_wake = make_wake(signaled=False)
result = _spawn([sys.executable, str(PROBE)], arena_fd=arena_fd, wake_fd=wake_fd)
assert result.returncode == 0, result.stderr
assert _parse_facts(result.stdout)["WAKE_READABLE"] == "0"
_MAIN_RETURN_SCRIPT = (
"import swactor\n"
"async def main(ctx):\n"
" print('MAIN_OK')\n"
"swactor.run(main)\n"
)
_MAIN_RAISE_SCRIPT = (
"import swactor\n"
"async def main(ctx):\n"
" raise RuntimeError('boom')\n"
"swactor.run(main)\n"
)
_NEVER_RUN_SCRIPT = (
"import swactor\n"
"async def main(ctx):\n"
" raise AssertionError('must not run')\n"
"swactor.run(main)\n"
)
def test_exit_zero_when_main_returns():
arena_fd = make_arena(pack_header())
wake_fd, _keep_wake = make_wake(True)
result = _spawn(
[sys.executable, "-c", _MAIN_RETURN_SCRIPT],
arena_fd=arena_fd,
wake_fd=wake_fd,
)
assert result.returncode == 0, result.stderr
assert "MAIN_OK" in result.stdout
def test_exit_nonzero_when_main_raises_with_traceback():
arena_fd = make_arena(pack_header())
wake_fd, _keep_wake = make_wake(True)
result = _spawn(
[sys.executable, "-c", _MAIN_RAISE_SCRIPT],
arena_fd=arena_fd,
wake_fd=wake_fd,
)
assert result.returncode != 0
assert "boom" in result.stderr
def test_exit_nonzero_on_bootstrap_defect_without_entering_main():
arena_fd = make_arena(pack_header(magic=MAGIC ^ 0xFF))
wake_fd, _keep_wake = make_wake(True)
result = _spawn(
[sys.executable, "-c", _NEVER_RUN_SCRIPT],
arena_fd=arena_fd,
wake_fd=wake_fd,
)
assert result.returncode != 0
assert "BootstrapError" in result.stderr
assert "must not run" not in result.stderr
def test_handoff_uses_only_the_two_env_names():
arena_fd = make_arena(pack_header())
wake_fd, _keep_wake = make_wake(True)
result = _spawn(
[sys.executable, "-c", _MAIN_RETURN_SCRIPT],
arena_fd=arena_fd,
wake_fd=wake_fd,
)
assert result.returncode == 0
# B8 is structural: the binding reads exactly ENV_ARENA and ENV_WAKE.
# Prove it by renaming one and observing failure.
env = {k: v for k, v in os.environ.items() if k not in (ENV_ARENA, ENV_WAKE)}
env["SWACTOR_DATA_PLANE_INPUT"] = "ignored-legacy-name"
env[ENV_WAKE] = str(wake_fd)
for fd in (arena_fd, wake_fd):
os.set_inheritable(fd, True)
missing = subprocess.run(
[sys.executable, "-c", _NEVER_RUN_SCRIPT],
env=env,
pass_fds=(arena_fd, wake_fd),
capture_output=True,
text=True,
timeout=60,
)
assert missing.returncode != 0
assert ENV_ARENA in missing.stderr