Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ jobs:
# /usr/bin/python3 and resolves back to it. Containers use their own image.
linux-containment:
runs-on: ubuntu-24.04
# A normal run takes about 4 minutes. A container engine that wedges
# (seen with gVisor on hosted runners) must fail the job, not hold it
# for GitHub's 6-hour default.
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Install containment dependencies
Expand All @@ -42,8 +46,19 @@ jobs:
# only). Parsers never get a network, and Docker's --network none
# alone is refused by runsc on these runners ("cannot run with
# network enabled in root network namespace").
#
# gVisor's default platform, systrap, hangs on some hosts: the
# sandbox starts, but the container's first process never runs, and
# `docker rm -f` cannot remove it. Which hosted runner a job lands on
# decides it, so probe it and fall back to ptrace (slower, same
# isolation boundary) where it hangs.
run: |
sudo runsc install -- --network=none
PLATFORM=systrap
if ! sudo timeout -s KILL 60 runsc --network=none --platform=systrap do /bin/true; then
echo "::warning::gVisor's systrap platform hangs on this runner; registering runsc with --platform=ptrace"
PLATFORM=ptrace
fi
sudo runsc install -- --network=none --platform="$PLATFORM"
sudo systemctl restart docker
docker info --format '{{json .Runtimes}}' | grep -q runsc
- name: Fetch the pinned parser image (trusted acquisition step)
Expand All @@ -57,7 +72,11 @@ jobs:
# step even though its output is piped through tee.
shell: bash
run: |
.venv/bin/python -m pytest tests -q -rs | tee pytest.log
# --timeout (pytest-timeout): a test stuck longer than this fails
# with its name and every thread's stack, and the run goes on, so a
# hang in the container engine names the test that hit it.
# --durations lists the slowest tests either way.
.venv/bin/python -m pytest tests -q -rs --timeout=120 --durations=15 | tee pytest.log
# Windows-only tests may skip here, and the GPU variant of the OCI
# backend skips because hosted runners have no GPU; nothing else may.
if grep "SKIPPED" pytest.log | grep -v "Windows feature" | grep -qv "no usable GPU"; then
Expand Down
6 changes: 6 additions & 0 deletions docs/containment.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ as the entrypoint of the image, so it must resolve inside the image (e.g.
with that reason — it is never replaced by another runtime. Register gVisor
with `runsc install -- --network=none` so it builds no network stack at all;
CI does this, and some Docker hosts refuse runsc with `--network none` alone.
On some hosts gVisor's default platform, `systrap`, hangs: the sandbox
starts but the container's first process never runs, and `docker rm -f`
cannot remove it (Stele then reports `ContainmentCleanupError`). Check with
`runsc --network=none --platform=systrap do /bin/true`. Where it hangs,
register `runsc install -- --network=none --platform=ptrace`: slower, the
same isolation boundary. CI probes this on every run.
- **GPU.** `OciBackend(gpu=True)` passes NVIDIA GPUs through with CDI
(`--device nvidia.com/gpu=all`) or Docker's `--gpus all`, and is unavailable
("no usable GPU") when the engine exposes none. gVisor supports GPUs only via
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies = []
# Wasm/WASI sandbox backend (stele.containment.wasm). The API used (fuel,
# epoch interruption, read-only preopens via fs_mutable) needs wasmtime 49+.
wasm = ["wasmtime>=49"]
dev = ["pytest>=8", "wasmtime>=49"]
dev = ["pytest>=8", "pytest-timeout>=2.3", "wasmtime>=49"]

[tool.hatch.build.targets.wheel]
packages = ["stele"]
Expand Down
14 changes: 14 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading