Skip to content

isb 3.1.0: isbx runs any CLI in a sandbox; egress waits for DNS and gains presets - #68

Merged
knowsuchagency merged 12 commits into
mainfrom
isbx
Oct 24, 2026
Merged

knowsuchagency merged 12 commits into
mainfrom
isbx

Conversation

@knowsuchagency

@knowsuchagency knowsuchagency commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

isb x (and isbx, the same binary under another name) runs any CLI in an isb sandbox instead of on the host.

  • One-off runs: isbx npm install runs in a kept sandbox for the project. The project is mounted at its own path, .git is read-only, the command runs as uid 1000, and only display variables pass through (-e KEY names another). The network starts closed. A package manager's first run opens its registry preset, and a refused host is named after the failure.

  • Installed tools: isb x install NAME --from npm:|pypi:|cargo:|go:|script:URL|sh:LINE puts the CLI in a sandbox of its own and adds host shims in ~/.local/share/isb/x/bin. Also update (blue/green), rm, shim, allow/deny, ls, stop, gc and doctor. --learn installs with public hosts open and keeps only the hosts the install used.

  • Egress, for every sandbox: a new egress sandbox's first command no longer fails DNS. Adds presets (@npm, @pypi, @crates, @go, @github, @mise, @public), * and dns: all. The proxy records the hosts it allowed and refused.

  • isb exec -e KEY takes the value from the host environment, so it never appears in host argv.

  • isb serve stops isbx sandboxes that have been idle for 30 minutes.

  • Dependencies: MSRV is now 1.87. Updates rustls 0.23.46, rustls-webpki 0.103.16, webpki-roots 1.0.11, ruzstd 0.9.1 and ctutils 0.4.5 for this week's RustSec advisories. crypto-bigint 0.5 is ignored, with a reason: it only reaches isb through age's P-256 recipients, which isb doesn't use.

Docs: docs/guides/isbx.md, plus updates to the CLI reference, the egress guide, the security concepts page and SKILL.md.

Tests: scripts/check.sh passes. tests/x.rs (ISB_INTEGRATION) passes in a preview VM running its own isb serve.

https://claude.ai/code/session_0193FJYdMzGpzZb8q3KQMDgJ

…c -e KEY

- A fresh or restarted egress sandbox waits until its guest resolves an
  allowed name: the first command used to run before /etc/resolv.conf
  existed and failed DNS.
- `@npm`, `@pypi`, `@crates`, `@go`, `@github`, `@mise`, `@public` in an
  allow list stand for those hosts.
- `*` / `*:PORT` allows any public name on that port; `dns: all` makes the
  bridge DNS answer every name with the proxy address, so unlisted names
  reach the proxy and are refused there.
- The proxy records each host:port it allowed or denied per sandbox under
  <state>/egress/names/<network>.
- `isb exec -e KEY` passes the caller's $KEY, keeping a value out of argv.
- prune_missing_path moves to sandbox/prune.rs.

Claude-Session: https://claude.ai/code/session_0193FJYdMzGpzZb8q3KQMDgJ
`isbx CMD` (the isb binary under that name) is `isb x run CMD`: the
project (the git repository you are in, else the directory) is mounted at
its own path in a kept dev-base sandbox, .git read-only, as uid 1000, with
a shared package cache volume. `$HOME`, its ancestors and credential and
host directories are refused as roots.

The project sandbox's egress list only grows: it starts closed (DNS
answers, the proxy refuses and records), and a package manager's first
run adds its registry, GitHub releases and mise's hosts once. --net none
and --net public are sandboxes of their own. After a failed run isbx
names the hosts the proxy refused.

The proxy marks the policy it applied, so isbx waits for a widened list
to reach it before the command's first connection.

Also: `isb x ls`, `isb x stop`, `isb x gc --idle/--missing`; output
helpers move to src/bin/isb/output.rs.

Claude-Session: https://claude.ai/code/session_0193FJYdMzGpzZb8q3KQMDgJ
`isb x install NAME --from npm:|pypi:|cargo:|go:|script:URL|sh:LINE`
installs into a new sandbox generation (x-NAME-N) as dev, finds the
programs the install added, and writes a shim for each in
$XDG_DATA_HOME/isb/x/bin. `isb x update` builds the next generation and
switches only once it works. A tool mounts the project it runs in (hot
plugged, earlier projects detached unless a live run uses them), a fixed
directory, or nothing. Secrets go on the wire as placeholders, or with
--secret-env are read with `op read` per run and sent in the exec request.
--learn installs with any public host open and keeps the hosts used.

Also `isb x tool`, `rm`, `shim` (plain host commands through isbx),
`allow`, `deny`, `doctor`; `isbx NAME` finds an installed tool. A VM
defaults to images:ubuntu/24.04/cloud.

Docs: docs/guides/isbx.md, the CLI and compose references, the egress
guide (presets, `*`, `dns: all`, readiness, the name record), the security
model, SKILL.md and the daemon's cli guide topic.

Claude-Session: https://claude.ai/code/session_0193FJYdMzGpzZb8q3KQMDgJ
… tests

- isb serve stops (never deletes) isbx sandboxes outside orgs that no run
  has used for 30 minutes (`isbx.idle` sets another time), skipping one a
  run is going in.
- Every isbx sandbox waits until uid 1000 exists (a cloud image makes it
  with cloud-init after starting).
- `isb x doctor` checks net.ipv4.ip_unprivileged_port_start, which the
  proxy needs at 80 or lower to listen on 443 and 80.
- tests/x.rs (ISB_INTEGRATION=1): a one-off run's paths, exit codes,
  stdin, ownership, read-only .git, env filtering, refused roots, the
  first command's DNS; a tool's install, shim, update, failed update and
  removal.

Claude-Session: https://claude.ai/code/session_0193FJYdMzGpzZb8q3KQMDgJ
…crypto-bigint 0.5 ignored

ruzstd 0.9.1 bounds a block's decoded size, so a crafted .zst can no longer
exhaust memory in a backup restore; ctutils 0.4.5 makes argon2's comparisons
branch-free. Both need Rust 1.87. crypto-bigint 0.5 comes only through age's
P-256 recipients, which isb never uses, and no age release takes the fix.
is_multiple_of replaces the modulo checks clippy flags at the new MSRV.

Claude-Session: https://claude.ai/code/session_0193FJYdMzGpzZb8q3KQMDgJ
@knowsuchagency
knowsuchagency merged commit 19c8702 into main Oct 24, 2026
26 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant