Sandbox Spec
A sandbox spec is a file saying what a program may write, read and
reach, and nothing else is open. lnk sandbox run --spec and lnk sandbox guest add --spec read it.
Every option
# Yours: a name to tell specs apart, and a number to bump when you change one.
name = "app"
version = 1
# Your folders. A section needs write or read.
[files]
write = ["~/code/app"] # read and written; relative paths are from this file's folder
read = ["~/Documents/reports"] # read only; "~" alone reads your whole home
# Of write, the folders whose .git, .envrc, .vscode and .idea it writes too, for a sandbox that commits.
write_dot_files = ["~/code/app"]
hide = ["~/code/app/secrets"] # closed whatever else is open
# Public hosts, through Link's proxy. A section needs hosts.
[internet]
hosts = ["api.openai.com", "github.com", "*.githubusercontent.com"]
# hosts = ["*"] # instead: any public host
tcp = ["github.com:22"] # raw host:port beyond HTTPS and HTTP; hosts must allow each
per_minute = 600 # the most calls a minute, at least 1
# Other machines of your network, through Link's proxy. A section needs hosts.
[lan]
hosts = ["nas.local", "192.168.1.0/24"] # names, addresses and ranges; "*" is the private ranges
# Servers on this machine. A section needs ports.
[localhost]
ports = [8080] # ports it may call
models = [11434] # a model runtime's port, for inference only
# Your tools from `lnk sandbox tool add`, which run outside with your logins. A section needs names.
[tools]
names = ["gh"]
# Pages it may ask you to open in your browser, each time. A section needs hosts.
[browser]
hosts = ["github.com"] # or ["*"] for any host
# The programs it may run. A section needs allow; one left out runs nothing.
[commands]
allow = ["sh", "node", "git", "/usr/lib/git-core/"] # names, paths, folders ending in /, or ["*"]
# On macOS, these keys replace the section's. Every section has these tables, for macos and linux.
[commands.macos]
allow = ["sh", "node", "git", "/Library/Developer/CommandLineTools/usr/libexec/git-core/"]
# [files.linux]
# hide = ["~/.local/share/keyrings"] # hide adds to the section's instead of replacing it
# [localhost.macos]
# ports = [5432] # only on macOS, these ports and no othersSections
A section is a grant, and one left out stays closed. A spec with no sections reads none of your files, reaches no network and runs no program.
| Section | Key | Type | Flag |
|---|---|---|---|
| top | name, version | Text, a whole number | --spec-name, --spec-version |
files | write | Folders | --write |
files | read | Folders | --read |
files | write_dot_files | Folders | --write-dot-files |
files | hide | Folders | --hide |
internet | hosts | Hosts, or ["*"] | --internet-host |
internet | tcp | host:port endpoints | --tcp |
internet | per_minute | A whole number, at least 1 | --per-minute |
lan | hosts | Names, addresses, ranges, or ["*"] | --lan-host |
localhost | ports | Port numbers | --port |
localhost | models | Port numbers | --model |
tools | names | Tool names | --tool |
browser | hosts | Hosts, or ["*"] | --browser-host |
commands | allow | Programs, folders ending /, or ["*"] | --command |
A section needs its first key: [files] needs write or read, the
others the key above. An empty section, an unknown key and "*" beside
other entries are refused, naming the line. A spec file is at most
64 KiB.
Values
- Paths:
~/is your home folder; anything else relative is from the spec's own folder...is refused. "*": in[internet] hosts, any public host; in[lan] hosts, the private ranges; in[browser] hosts, any host; in[commands] allow, any program. It's refused in[files],[tools]and[localhost].- Hosts: a name with a dot (
api.openai.com),*.github.comfor the names under a name but not the name itself, or an IP address. [internet] tcp: each endpoint names its port;*.abc.mongodb.netholds the names under it, notabc.mongodb.net, andhostsmust allow each. A*.endpoint's port can't be a[localhost]port or 40781. On Linux, a spec with endpoints gets DNS from its proxy (how).[lan] hosts: names, addresses and ranges of your network. Which addresses each reaches, and what is refused whatever is listed: Security. On a cloud's machine,"*"and a range holding a whole private block are refused too, since the network there is the cloud's.[localhost]: a port is 1 to 65535, and 40781, the port of Link's proxy, is refused inportsand inmodels.modelsneedsportsbeside it.[tools] names: letters, digits,-and_.[commands] allow: a name is found onPATHwhen the run starts. A path is from the spec's folder, and one ending in/allows every program in that folder. An entry in a folder it may write, or in/tmp, is refused, and so is a folder holding one of those ("/", or~/tools/besidewrite = ["~/tools/out"]).lnk-sandboxand, on Linux, the program loader are always allowed.lnk sandbox learnlists the entries a command needs.
Dot files that run outside
At the top of each folder in write, a project's dot files that run
outside the sandbox are read only (each, and how).
write_dot_files lists the folders of write where they're written
too, for a sandbox that commits (Let it commit).
A folder in it that isn't in write is refused. Left out, none is.
One OS's table
[<section>.macos] and [<section>.linux] hold the section's keys for
one OS. Each key given replaces the section's there, but hide, which
adds up. A section with only another OS's table is closed here.
Flags and a file
A flag giving a key replaces the file's key, but --hide, which adds
to it. Without --spec, the flags are the whole spec, and any program
runs unless --command names them.
Refused in a file
A spec from a file may be anyone's, so these are refused in it, with the flags given beside it:
- A folder in Link's settings or agents' folders, or a write of one holding them.
- A write of your home folder itself, a dot folder in it (
~/.ssh,~/.config),~/bin,~/Library, a folder on yourPATHor one holding it, or in the system's folders:/bin,/sbin,/usr,/etc,/lib,/lib32,/lib64,/boot,/dev,/proc,/sys,/opt,/nix,/snap,/var,/home/linuxbrew, and macOS's/System,/Library,/Applications,/private/etcand/private/var. Homebrew's,/opt/homebrewand/usr/local, are among them. - A write of the folder holding the spec, which would let the program change its next run.
- A write in a project's
.git,.envrc,.vscodeor.idea: write the project's folder, and name it inwrite_dot_files. - A read or write in, or holding, a folder where programs keep their
sockets:
/tmp,/run,/var/run,/var/folders,$XDG_RUNTIME_DIRand the temp folder, so/too. What answers on a socket there, a session's bus or Docker's, runs what it's asked outside the sandbox, and on Linux a socket connects read only. ..in a path.
Flags alone are yours, or Link's own, and aren't checked this way.
How to use a spec: Describe a sandbox in a file. Why it is what it is: Decisions. Every spec Link reads, side by side: Specs.
