Skip to content

feat(runtime): judge a command's risk by where it will run - #59

Merged
mangit955 merged 1 commit into
mainfrom
feat/sandbox-aware-approval
Aug 12, 2026
Merged

feat(runtime): judge a command's risk by where it will run#59
mangit955 merged 1 commit into
mainfrom
feat/sandbox-aware-approval

Conversation

@mangit955

Copy link
Copy Markdown
Owner

The payoff for phases 1–5: with the sandbox on, machine-level work stops asking. Deleting, the network, and anything unrecognised still ask.

This is a permission widening, so it is a draft PR rather than a push to main.

What this newly permits

chmod/chown/chgrp, systemctl/launchctl/service, mount/umount, apt/brew/dnf/pacman/snap, ifconfig/route/iptables, reboot/shutdown, crontab/at — plus any declared write or redirect outside the workspace (mkdir /opt/thing, echo hi > /etc/hosts).

Each is safe for one reason: its whole effect lands on a VM that is discarded, and the only thing that crosses back is a file sync confined to the workspace that refuses to overwrite a local change.

What it deliberately does not permit

  • Deleting. The sync carries deletions home — applyChanges removes every local file whose sandbox copy went away and whose contents still match the snapshot — so a sandboxed rm -rf src costs uncommitted work. DESTRUCTIVE is also where every unrecognised command lives.
  • The network. Egress is on by default and the workspace source is in the sandbox, so curl, wget, ssh, scp, rsync and git's remote subcommands are how it leaves.
  • Remote control planes. kubectl, terraform, docker, helm talk to things that are not in the VM.

The list is an allowlist, so anything added to SYSTEM_COMMANDS later is contained-unsafe by default.

Two things worth reviewing closely

sudo. It is not a transparent prefix, so sudo rm -rf / grades as plain SYSTEM elsewhere in the classifier. Listing it as contained-safe would have made it a workspace write and run it unattended. Contained, it is the max of a write and whatever it wraps: sudo apt-get install runs, sudo rm -rf / still asks.

Why the classifier and not the policy. requiresApproval is risk > ceiling over a linear enum, so no ceiling can permit SYSTEM without also permitting DESTRUCTIVE — the one combination to avoid. policy.ts and approval-mode.ts are untouched; no new mode.

Verification

  • bun run verify --all and --staged: 4 gates. Reverse-order sweep: 1870 pass, 0 fail across 114 files.
  • Every rule proved by mutation — including reverting to the original plan's "DESTRUCTIVE auto-approves when contained", which fails 6 tests.
  • Fixtures are pairs throughout: what newly runs, and the nearby thing that must still ask, with the uncontained column alongside so the change is provably conditional.
  • Live, against a real sandbox with AUTO_WORKSPACE: chmod ran with no prompt, rm -rf src still prompted, host file modes and working tree unchanged.

Not covered

The approval picker's mode descriptions still describe uncontained behaviour — a copy change, deferred. Network egress remains the boundary's weak edge; WOOPCODE_SANDBOX_NETWORK=none is the brake and nothing here changes it.

With the sandbox on, a command runs in a micro-VM that is discarded. A
whole class of it is no longer dangerous because of where it lands, and
prompting anyway is how a user learns to click through the dialog that
mattered.

What this newly permits, named rather than implied:

  chmod / chown / chgrp, systemctl / launchctl / service, mount / umount,
  apt / brew / dnf / pacman / snap, ifconfig / route / iptables,
  reboot / shutdown, crontab / at — and any declared write or redirect
  outside the workspace, such as `mkdir /opt/thing` or
  `echo hi > /etc/hosts`.

Each is safe for one reason: its entire effect lands on a machine that is
thrown away, and the only thing that crosses back is a file sync confined
to the workspace which refuses to overwrite a local change.

What it deliberately does not permit:

  - Deleting. The sync carries deletions home — applyChanges removes every
    local file whose sandbox copy went away and whose contents still match
    the snapshot — so a sandboxed `rm -rf src` costs the user's
    uncommitted work. DESTRUCTIVE is also where every unrecognised command
    lives, and auto-approving the level would auto-approve all of them.
  - The network. Egress is on by default and the workspace source is
    pushed into the sandbox, so curl, wget, ssh, scp, rsync and git's
    remote subcommands are how it leaves.
  - Remote control planes. kubectl, terraform, docker and helm talk to
    clusters and daemons that are not in the VM.

sudo is neither listed nor ignored. It is not a transparent prefix, so
`sudo rm -rf /` grades as plain SYSTEM elsewhere in the classifier —
listing it as contained-safe would have made it a workspace write and run
it unattended. Contained, it is the maximum of a write and whatever it
wraps: `sudo apt-get install` runs, `sudo rm -rf /` still asks.

Containment enters the classifier, not the policy. requiresApproval is
`risk > ceiling` over a linear enum, so no ceiling can permit SYSTEM
without also permitting DESTRUCTIVE — the one combination to avoid.
policy.ts and approval-mode.ts are untouched and there is no new mode.

Every rule has fixtures in both directions, and the approval dialog now
says when a command it is asking about will run in the sandbox.

Verified live: with AUTO_WORKSPACE and a real sandbox, chmod ran without
a prompt, `rm -rf src` still prompted, and the host's file modes and
working tree were unchanged.
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
woop-code Ready Ready Preview Aug 12, 2026 1:41am

@mangit955
mangit955 marked this pull request as ready for review August 12, 2026 02:29
@mangit955
mangit955 merged commit 050210a into main Aug 12, 2026
6 checks passed
@mangit955
mangit955 deleted the feat/sandbox-aware-approval branch August 12, 2026 02:29
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