Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a7393e6
fix: close device, stream, and preview lifecycle gaps
CMGS Aug 13, 2026
47d55e8
fix: watch overflow signals by dropping the sender, not a flag
CMGS Aug 13, 2026
082a3c1
perf(preview): pooled guest conns with per-request touch authorization
CMGS Aug 13, 2026
718242a
review: tighten comments, converge relay close paths
CMGS Aug 13, 2026
0f7cc33
fix(pool): scope promoted-template claims to the owning tenant
CMGS Aug 13, 2026
90929bc
fix(mesh): a departed node stays gone until it restarts
CMGS Aug 13, 2026
8d9283d
docs: correct the preview audit op, bound verbs, and volume scope
CMGS Aug 13, 2026
b098091
test(peer): bound the in-flight wait and give the fan-out test teeth
CMGS Aug 13, 2026
cb6b293
fix(egress): a missing policy on either side denies, never inherits
CMGS Aug 13, 2026
7a85601
docs: correct the claim engine axis, metrics inventory, and config table
CMGS Aug 13, 2026
a951bf8
fix: close preview and idle hibernate gaps
CMGS Aug 13, 2026
57e88c9
fix(mesh): let SWIM membership decide who is in the view
CMGS Aug 13, 2026
05dda54
build: pin the toolchains that produce guest binaries, and gate shell
CMGS Aug 13, 2026
0ca6c80
feat(sdk): expose the reply status, and close the parity gaps
CMGS Aug 13, 2026
5c7a855
docs: document the node-operation verbs, and stop restating delete se…
CMGS Aug 13, 2026
a5c3082
feat(sdk): finish the Go/Python surface parity
CMGS Aug 13, 2026
84cc8e7
docs: record the Python exit, pty and watch contracts
CMGS Aug 13, 2026
bc7e7b3
review: cut the restating half of the admit godoc
CMGS Aug 13, 2026
895aeef
fix: carry the engine axis through the SDK and metrics, and true up t…
CMGS Aug 13, 2026
0c85e99
fix(scripts): spell the daemon teardown as an if, not A && B || true
CMGS Aug 13, 2026
1198869
test(e2e): pin claim_ref and the engine axis on the wire
CMGS Aug 13, 2026
a4f3ab9
fix(pool): routing must answer what a claim would about a template
CMGS Aug 13, 2026
5d8b083
fix(mcp): fork children and checkpoint branches get the session lease
CMGS Aug 14, 2026
4931efc
review: compress the tenant-cache comments to their WHY
CMGS Aug 14, 2026
855c678
sandboxd: drop the Firecracker engine axis (#86)
CMGS Aug 14, 2026
89304e5
fix(mesh): tenant-scope the template gossip hashes
CMGS Aug 14, 2026
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
39 changes: 39 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# The guest binaries (sandbox-init, silkd) and every os-image are built from
# these bases, so their tags are pinned by digest for reproducibility and
# dependabot is what keeps the pins current — without it a pinned digest is a
# frozen, unpatched toolchain.
version: 2
updates:
- package-ecosystem: docker
directories:
- /silkd
- /boot
- /os-image/base/24.04
schedule:
interval: weekly
commit-message:
prefix: "build"
- package-ecosystem: cargo
directories:
- /silkd
- /boot/init
schedule:
interval: weekly
commit-message:
prefix: "build"
- package-ecosystem: gomod
directories:
- /sandboxd
- /sdk/go
- /e2e
- /mcp
schedule:
interval: weekly
commit-message:
prefix: "build"
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
commit-message:
prefix: "build"
28 changes: 28 additions & 0 deletions .github/workflows/shell.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# The e2e and bench drivers are shell, and they are what hardware rounds run;
# a broken quoting or trap change there costs a whole round.
name: shell

on:
push:
branches: [main]
paths:
- "**.sh"
- ".github/workflows/shell.yml"
pull_request:
paths:
- "**.sh"
- ".github/workflows/shell.yml"
workflow_dispatch:

permissions:
contents: read

jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: shellcheck
run: make sh-lint
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ GOLANGCILINT_VERSION ?= v2.12.2
GOLANGCILINT_ROOT := $(LOCALBIN)/golangci-lint-$(GOLANGCILINT_VERSION)
GOLANGCILINT := $(GOLANGCILINT_ROOT)/golangci-lint

.PHONY: help test lint boot boot-debug extract extract-debug silkd-image base python images \
.PHONY: help test lint sh-lint boot boot-debug extract extract-debug silkd-image base python images \
sandboxd go-test go-lint bench cloc

## Tool download targets
Expand All @@ -49,6 +49,9 @@ lint: ## Rust fmt --check + clippy -D warnings: boot/init + silkd
cd boot/init && cargo fmt --check && cargo clippy --all-targets -- -D warnings
cd silkd && cargo fmt --check && cargo clippy --all-targets -- -D warnings

sh-lint: ## shellcheck every tracked shell script
git ls-files '*.sh' | xargs shellcheck

sandboxd: ## build dist/sandboxd
mkdir -p dist
cd sandboxd && GOWORK=off go build -ldflags "-X main.version=$(SANDBOXD_VERSION)" -o ../dist/sandboxd .
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ performance) — source in
`/boot/vmlinuz-sandbox` + `/boot/initrd.img-sandbox`
- `os-image/` — VM images consuming the boot artifact: `base` (layered,
for builds), `rt` (base squashed to one layer — the default template in
examples), `python`, `python-rt`, and `android`
- `scripts/` — `boot-bench.sh` (boot phase timing) and `sandboxd-e2e.sh`
(bare-metal e2e, below)
examples), `python`, `python-rt`, `browser`, and `android`
- `scripts/` — `boot-bench.sh` (boot phase timing), `bench.sh` (the published
benchmark procedure), `sandboxd-e2e.sh` (bare-metal e2e, below), plus the
`archive`/`egress`/`intercept` e2e drivers

## Build & test

Expand Down Expand Up @@ -118,6 +119,7 @@ TEMPLATE=rt:24.04 scripts/sandboxd-e2e.sh
changed carriers (via `build-boot.yml` / `build-silkd.yml`,
`workflow_call`) then os-images, in order, so the chain is deterministic
- `build-os-images.yml` — bakes base + flavors FROM the sha-pinned carriers
- `release.yml` — on a version tag, builds the release binaries and archives
- `publish-pypi.yml` — on an `sdk-*-v*` tag, builds and publishes the
matching package via PyPI Trusted Publishing (OIDC, per-package
environment)
Expand Down
6 changes: 3 additions & 3 deletions boot/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# under /boot/ for os-image builds to COPY --from. Built per-platform on
# native runners (a kernel build under QEMU emulation takes hours).

FROM debian:bookworm-slim AS kbuild
FROM debian:bookworm-slim@sha256:abd67ffcfa541b485a3dff59865ab629aa048a6c613e639d36e7456b0b229241 AS kbuild
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential bc bison flex libelf-dev libssl-dev \
xz-utils curl ca-certificates python3 \
Expand Down Expand Up @@ -75,14 +75,14 @@ RUN set -e; \
fi; \
gcc usr/gen_init_cpio.c -o /usr/local/bin/gen_init_cpio

FROM rust:1-alpine AS initbuild
FROM rust:1-alpine@sha256:3c38f3f82c2f3d73da3b38e18d279393a04cb43ddded0e35088a8c3324d40900 AS initbuild
RUN apk add --no-cache musl-dev
WORKDIR /build
COPY init/Cargo.toml init/Cargo.lock ./
COPY init/src ./src
RUN cargo build --release --locked && cp target/release/sandbox-init /sandbox-init

FROM busybox:musl AS bb
FROM busybox:musl@sha256:32b5cdad7cce41dfd53d0ae06baebcf8357a147ee7694dc706911c373bc30c37 AS bb

FROM kbuild AS pack
ARG INITRD_DEBUG=0
Expand Down
2 changes: 1 addition & 1 deletion boot/init/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[toolchain]
channel = "stable"
channel = "1.97.1"
components = ["rustfmt", "clippy"]
profile = "minimal"
38 changes: 32 additions & 6 deletions boot/init/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! switch_root → exec.

use std::fs;
use std::path::Path;
use std::time::{Duration, Instant};

use crate::cfg::{self, BootCfg};
Expand Down Expand Up @@ -235,12 +236,15 @@ fn scan_serials(ids: &[&str], found: &mut [Option<String>]) {
let Ok(serial) = fs::read_to_string(&path) else {
continue;
};
let serial = serial.trim_end();
for (i, id) in ids.iter().enumerate() {
if found[i].is_none() && *id == serial {
found[i] = Some(format!("/dev/{name}"));
}
}
record_serial(ids, found, serial.trim_end(), &format!("/dev/{name}"));
}
}
}

fn record_serial(ids: &[&str], found: &mut [Option<String>], serial: &str, device: &str) {
for (i, id) in ids.iter().enumerate() {
if found[i].is_none() && *id == serial && Path::new(device).exists() {
found[i] = Some(device.into());
}
}
}
Expand All @@ -251,3 +255,25 @@ fn uptime() -> String {
.and_then(|s| s.split_ascii_whitespace().next().map(String::from))
.unwrap_or_else(|| "?".into())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn record_serial_skips_a_missing_device_node() {
let ids = ["layer"];
let mut found = [None];

record_serial(
&ids,
&mut found,
"layer",
"/dev/sandbox-init-missing-device",
);
assert!(found[0].is_none());

record_serial(&ids, &mut found, "layer", "/dev/null");
assert_eq!(found[0].as_deref(), Some("/dev/null"));
}
}
Loading