Smith::Sandbox
Runs bash where it cannot reach past the project.
The approval gate asks before every mutating call, and asking about
everything is how users end up leaving --yes on — at which point nothing
is gated at all. A sandbox inverts that: a command that cannot write
outside the working directory does not need to be asked about, because the
answer no longer depends on trust.
What is claimed here is deliberately narrow. The filesystem is confined and the network is a switch. There is no per-domain allowlist, because SBPL filters by address and port and not by hostname — a profile naming a host does not compile. Saying so is better than a setting that quietly means something else.
Constants
Directories the toolchain has to write to or it fails — usually not with a
permission error but with something far more confusing. A Crystal compiler
that cannot write ~/.cache/crystal reports "you've found a bug in the
Crystal compiler", which is a sentence that sends an agent hunting through
its own code for an hour.
This list is the reason the feature is more than a profile string.
Character devices a shell needs to be a shell.
Class methods
A path as the kernel will see it.
Two corrections, both of which are silent failures if skipped. ~ is left
alone by File.expand_path unless it is told otherwise, which turns
~/.cache into a path inside the project: an allowance that allows
nothing. And symlinks have to be resolved, because the sandbox matches the
real path — on macOS /tmp is /private/tmp and a temporary directory
lives under /private/var/folders, so a profile naming the unresolved
path confines a directory nobody is writing to.
Tools::Paths.normalize already does the symlink half for permission
rules, where getting it wrong is how a scoped rule gets bypassed. Same
problem, same code.
The strategy for this policy on this machine, and the reason when it is not the one that was asked for.