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
3 changes: 3 additions & 0 deletions .agents/skills/helm-dev-environment/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ mise run helm:skaffold:run
mise run helm:skaffold:run:sidecar
```

Combined topology selects RFC 0012's in-pod backend and supplies its descriptor;
sidecar topology remains on its separate lifecycle.

**Supervisor sidecar topology with TLS/mTLS enabled** (build once and leave running):
```bash
mise run helm:skaffold:run:sidecar-mtls
Expand Down
55 changes: 55 additions & 0 deletions .github/workflows/branch-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,61 @@ jobs:
fi
exit 0

isolation-conformance:
name: Isolation conformance (privileged Linux)
needs: pr_metadata
if: needs.pr_metadata.outputs.should_run == 'true'
runs-on: linux-amd64-cpu8
timeout-minutes: 20
container:
image: ghcr.io/nvidia/openshell/ci:latest
options: --privileged
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install tools and network helpers
run: |
apt-get update
apt-get install -y --no-install-recommends iproute2 nftables iptables util-linux
mise install --locked

- name: Materialize the Alpine trusted helper runtime fixture
run: |
alpine_root="${RUNNER_TEMP}/openshell-alpine-root"
runtime="${RUNNER_TEMP}/openshell-runtime"
archive="${RUNNER_TEMP}/alpine-minirootfs.tar.gz"
curl -fsSL \
https://dl-cdn.alpinelinux.org/alpine/v3.22/releases/x86_64/alpine-minirootfs-3.22.5-x86_64.tar.gz \
-o "$archive"
echo "4b4daa9fe2fc696c4919c4412a4c3d3e770d8fb70292a004a2c72f5096175282 $archive" \
| sha256sum -c -
mkdir -p "$alpine_root" "$runtime"
tar -xzf "$archive" -C "$alpine_root"
cp /etc/resolv.conf "$alpine_root/etc/resolv.conf"
chroot "$alpine_root" /sbin/apk add --no-cache \
iproute2 nftables iptables iptables-legacy
for path in /bin /sbin /lib /lib64 /usr/bin /usr/sbin /usr/lib /usr/lib64 /etc/iproute2 /usr/share/nftables; do
if [ -e "$alpine_root$path" ]; then
(cd "$alpine_root" && cp -aL --parents ".$path" "$runtime")
fi
done
chmod -R go-w "$runtime"

- name: Exercise the live default-deny ceiling
run: |
cargo test -p openshell-isolation -p openshell-supervisor-process \
-p openshell-supervisor-network -p openshell-sandbox
OPENSHELL_TEST_TRUSTED_RUNTIME_ROOT="${RUNNER_TEMP}/openshell-runtime" \
cargo test -p openshell-supervisor-process \
installed_egress_ceiling_ -- \
--ignored --nocapture --test-threads=1
cargo test -p openshell-sandbox \
pid_one_exit_kills_unregistered_setsid_descendant_within_bound -- \
--ignored --nocapture --test-threads=1

rust-macos:
name: Rust lint (macOS)
needs: pr_metadata
Expand Down
14 changes: 10 additions & 4 deletions .github/workflows/driver-vm-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
options: --privileged
volumes:
- /var/run/docker.sock:/var/run/docker.sock
env:
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENSHELL_IMAGE_TAG: ${{ inputs['image-tag'] }}
Expand All @@ -141,8 +143,12 @@ jobs:
cache-directories: .cache/sccache
cache-targets: "true"

- name: Install zstd
run: apt-get update && apt-get install -y --no-install-recommends zstd && rm -rf /var/lib/apt/lists/*
- name: Install zstd and verify Docker
run: |
apt-get update
apt-get install -y --no-install-recommends zstd
rm -rf /var/lib/apt/lists/*
docker info

- name: Download kernel runtime tarball
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
Expand All @@ -168,14 +174,14 @@ jobs:
- name: Verify embedded driver inputs
run: |
set -euo pipefail
for file in libkrun.so.zst libkrunfw.so.5.zst gvproxy.zst umoci.zst openshell-sandbox.zst; do
for file in libkrun.so.zst libkrunfw.so.5.zst gvproxy.zst umoci.zst openshell-sandbox.zst openshell-runtime.tar.zst; do
test -s "target/vm-runtime-compressed/${file}"
done

- name: Scope workspace to driver-vm crates
run: |
set -euo pipefail
sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-driver-vm", "crates/openshell-core"]|' Cargo.toml
sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-driver-vm", "crates/openshell-core", "crates/openshell-isolation"]|' Cargo.toml

- name: Patch workspace version
if: ${{ inputs['cargo-version'] != '' }}
Expand Down
19 changes: 14 additions & 5 deletions .github/workflows/driver-vm-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ jobs:
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
env:
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENSHELL_IMAGE_TAG: ${{ inputs['image-tag'] }}
Expand All @@ -100,8 +102,12 @@ jobs:
cache-directories: .cache/sccache
cache-targets: "true"

- name: Install zstd
run: apt-get update && apt-get install -y --no-install-recommends zstd && rm -rf /var/lib/apt/lists/*
- name: Install zstd and verify Docker
run: |
apt-get update
apt-get install -y --no-install-recommends zstd
rm -rf /var/lib/apt/lists/*
docker info

- name: Build bundled supervisor
run: |
Expand All @@ -116,7 +122,9 @@ jobs:
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: driver-vm-supervisor-arm64
path: target/vm-runtime-compressed/openshell-sandbox.zst
path: |
target/vm-runtime-compressed/openshell-sandbox.zst
target/vm-runtime-compressed/openshell-runtime.tar.zst
retention-days: 1

build-driver-vm-macos:
Expand Down Expand Up @@ -180,12 +188,13 @@ jobs:
run: |
set -euo pipefail
test -f target/vm-runtime-compressed-macos/openshell-sandbox.zst
ls -lh target/vm-runtime-compressed-macos/openshell-sandbox.zst
test -f target/vm-runtime-compressed-macos/openshell-runtime.tar.zst
ls -lh target/vm-runtime-compressed-macos/openshell-{sandbox,runtime.tar}.zst

- name: Verify embedded driver inputs
run: |
set -euo pipefail
for file in libkrun.dylib.zst libkrunfw.5.dylib.zst gvproxy.zst umoci.zst openshell-sandbox.zst; do
for file in libkrun.dylib.zst libkrunfw.5.dylib.zst gvproxy.zst umoci.zst openshell-sandbox.zst openshell-runtime.tar.zst; do
test -s "target/vm-runtime-compressed-macos/${file}"
done

Expand Down
17 changes: 17 additions & 0 deletions Cargo.lock

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

28 changes: 28 additions & 0 deletions architecture/sandbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,34 @@ OpenShell uses overlapping controls rather than a single sandbox primitive:
The supervisor may enrich baseline filesystem allowances for runtime-required
paths, such as proxy support files or GPU device paths when a GPU is present.

## Isolation Backend

[RFC 0012](../rfc/0012-isolation-backend/README.md) defines the Isolation
Backend contract for topology-specific boundary construction and process
operations. The contract uses consuming
lifecycle states (`attach` → `Bound` → `confirm` → `Ready` → `start_agent` →
`Running`) so untrusted workload execution cannot begin before standing
enforcement is confirmed.

The logical supervisor remains the trusted bridge between the gateway and the
workload. It drives the backend and applies approved network policy through
supervisor-owned mediation; the backend routes workload egress to that
mediation. The trusted Kubernetes driver selects the co-located backend for
combined topology and supplies its topology descriptor to the supervisor.
Sidecar topology remains on its pre-RFC lifecycle; a conforming backend for
that placement requires separate design and implementation. Docker, Podman,
and VM drivers provision the same co-located topology and supply its descriptor
by default. The co-located backend requires the
supervisor to own the execution environment's PID namespace so boundary
teardown can terminate every remaining workload process.

For proxy-mode boundaries, the co-located backend verifies its default-deny
kernel egress ceiling before exposing any workload execution surface and then
rechecks it every 250 milliseconds. Each check has a two-second deadline.
Verification failure or timeout ends the boundary and triggers process cleanup;
the PID-1 supervisor exits so the kernel terminates the complete workload PID
namespace. The topology's detection-and-termination bound is five seconds.

## Network and Inference

See [Sandbox Limits](sandbox-limits.md) for the current numeric safety ceilings,
Expand Down
18 changes: 18 additions & 0 deletions crates/openshell-core/src/driver_mounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,24 @@ mod tests {
assert!(err.contains("/etc/openshell"));
}

#[test]
fn container_target_rejects_parents_that_shadow_reserved_trees() {
for target in ["/opt", "/etc", "/run"] {
let err = validate_container_mount_target(target).unwrap_err();
assert!(
err.contains("reserved OpenShell path"),
"expected {target} to be rejected: {err}"
);
}
}

#[test]
fn container_target_rejects_proc_shadowing() {
for target in ["/proc", "/proc/self", "/"] {
assert!(validate_container_mount_target(target).is_err());
}
}

#[test]
fn container_target_does_not_prefix_match_unrelated_paths() {
validate_container_mount_target("/etc/openshell-tools").unwrap();
Expand Down
5 changes: 3 additions & 2 deletions crates/openshell-driver-docker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ path = "src/main.rs"

[dependencies]
openshell-core = { path = "../openshell-core", default-features = false, features = ["driver-extraction"] }
openshell-isolation = { path = "../openshell-isolation" }
openshell-otel = { path = "../openshell-otel" }

opentelemetry = { workspace = true }
Expand All @@ -35,15 +36,15 @@ url = { workspace = true }
clap = { workspace = true }
miette = { workspace = true }
toml = { workspace = true }
tar = "0.4"
tempfile = "3"

[dev-dependencies]
openshell-otel-test-support = { path = "../openshell-otel-test-support" }
opentelemetry = { workspace = true }
opentelemetry_sdk = { workspace = true, features = ["testing"] }
prost-types = { workspace = true }
tar = "0.4"
temp-env = "0.3"
tempfile = "3"
tracing-subscriber = { workspace = true }

[lints]
Expand Down
Loading
Loading