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 others

Sections

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.

SectionKeyTypeFlag
topname, versionText, a whole number--spec-name, --spec-version
fileswriteFolders--write
filesreadFolders--read
fileswrite_dot_filesFolders--write-dot-files
fileshideFolders--hide
internethostsHosts, or ["*"]--internet-host
internettcphost:port endpoints--tcp
internetper_minuteA whole number, at least 1--per-minute
lanhostsNames, addresses, ranges, or ["*"]--lan-host
localhostportsPort numbers--port
localhostmodelsPort numbers--model
toolsnamesTool names--tool
browserhostsHosts, or ["*"]--browser-host
commandsallowPrograms, 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.com for the names under a name but not the name itself, or an IP address.
  • [internet] tcp: each endpoint names its port; *.abc.mongodb.net holds the names under it, not abc.mongodb.net, and hosts must 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 in ports and in models. models needs ports beside it.
  • [tools] names: letters, digits, - and _.
  • [commands] allow: a name is found on PATH when 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/ beside write = ["~/tools/out"]). lnk-sandbox and, on Linux, the program loader are always allowed. lnk sandbox learn lists 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 your PATH or 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/etc and /private/var. Homebrew's, /opt/homebrew and /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, .vscode or .idea: write the project's folder, and name it in write_dot_files.
  • A read or write in, or holding, a folder where programs keep their sockets: /tmp, /run, /var/run, /var/folders, $XDG_RUNTIME_DIR and 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.