Combinators

nono.nix combinators are the building blocks to create Permissions, which grant a program specific permissions at runtime.

These permissions can be passed into the third argument to nono function, as well as basePermissions.

A Permission is a State -> State function where State is an internal type that accumulates Landlock grants, network policy, and other nono flags before building the final profile and invocation. The type of State is not part of the public API and may change.


add-cleanup

add-cleanup :: String -> Permission

Source

Adds arbitrary logic to run when the sandbox exits.

This is designed to be an easy way to register cleanup actions for things created in add-runtime. These scripts run in the same scope as add-runtime so any shell variables defined there will be in scope.

The cleanup actions may run even if the runtime doesn't— for example if a previous runtime exits non-zero the sandbox will exit prematurely, but the cleanup actions will still run.

Example:

compose [
  (add-runtime ''
    TMP_FILE=$(mktemp)
    do-something "$TMP_FILE"
  '')
  (add-cleanup ''
    if [ -e "''${TMP_FILE-}" ]; then
      rm "$TMP_FILE"
    fi
  '')
]

add-path

add-path :: String -> Permission

Source

Prepends the passed string to $PATH.


add-pkg-deps

add-pkg-deps :: [Package] -> Permission

Source

Adds the packages' bin directory to $PATH and grants read access to the packages (so the Landlock policy allows them to be executed).


add-runtime

add-runtime :: String -> Permission

Source

Adds arbitrary logic to run at runtime, before the sandbox starts.

You can push additional nono flags by appending to the bash array $NONO_EXTRA_FLAGS. This lets you make sandbox flags depend on runtime conditions (e.g. paths that contain $XDG_RUNTIME_DIR).

Note that anything added here is not run inside the sandbox. To run arbitrary things at runtime inside the sandbox see wrap-entry.

Example:

add-runtime ''
  # grant read access to /foo only if /bar exists on the host
  if [ -e /bar ]; then
    NONO_EXTRA_FLAGS+=(--read /foo)
  fi
''

If you create any resources in add-runtime that you want to automatically clean up when the sandbox exits use add-cleanup.


allow-command

allow-command :: String -> Permission

Source

Adds cmd to the child-process execution allowlist.

Once any allow-command is set, the sandbox blocks execution of any command not in the list. Use this to lock down which binaries the sandboxed process can spawn as children.

(allow-command "/run/current-system/sw/bin/curl")

To allow multiple commands, apply this combinator once per command or compose them:

(compose [
  (allow-command "/run/current-system/sw/bin/curl")
  (allow-command "/run/current-system/sw/bin/git")
])

allow-cwd

allow-cwd :: Permission

Source

Grants read-write access to the current working directory.

Alias for mount-cwd.


allow-domain

allow-domain :: String -> Permission

Source

Allows outbound connections to a domain.

Supports wildcards like *.example.com. Implies network proxy mode.

Example:

allow-domain "api.openai.com"
allow-domain "*.anthropic.com"

allow-endpoint

allow-endpoint :: String -> Permission

Source

Allows a specific HTTP endpoint in the format SERVICE:METHOD:PATH.

Example:

allow-endpoint "openai:POST:/v1/chat/completions"
allow-endpoint "anthropic:POST:/v1/messages"

allow-gpu

allow-gpu :: Permission

Source

Exposes GPUs to the sandboxed application via nono's --allow-gpu flag.

This is the explicit form of gpu. Both set allowGpu = true in the sandbox state, which causes the nono invocation to include --allow-gpu. nono handles the details automatically — DRM, NVIDIA, AMD, Metal, and WSL2 are all covered by that single flag.


allow-launch-services

allow-launch-services :: Permission

Source

(macOS only) Allows the sandbox to open URLs and files through macOS Launch Services.

Without this, calls to open or NSWorkspace.open inside the sandbox are blocked. Enable it when the sandboxed tool legitimately needs to launch browsers, open documents in other apps, or handle URL schemes.


allow-unix-socket

allow-unix-socket :: String -> Permission

Source

Allows the sandboxed process to connect to the unix socket at path.

If path contains shell variable references (e.g. $XDG_RUNTIME_DIR/bus), wrap it with noescape to prevent shell-escaping:

(allow-unix-socket (noescape "$XDG_RUNTIME_DIR/bus"))

allow-unix-socket-bind

allow-unix-socket-bind :: String -> Permission

Source

Allows the sandboxed process to create (bind) a unix socket at path.

If path contains shell variable references (e.g. $XDG_RUNTIME_DIR/foo.sock), wrap it with noescape to prevent shell-escaping:

(allow-unix-socket-bind (noescape "$XDG_RUNTIME_DIR/foo.sock"))

allow-unix-socket-dir

allow-unix-socket-dir :: String -> Permission

Source

Allows the sandboxed process to connect to any unix socket one level deep inside dir. Sockets in subdirectories are not covered — use allow-unix-socket-subtree for recursive access.

If dir contains shell variable references, wrap it with noescape:

(allow-unix-socket-dir (noescape "$XDG_RUNTIME_DIR"))

allow-unix-socket-dir-bind

allow-unix-socket-dir-bind :: String -> Permission

Source

Allows the sandboxed process to create (bind) unix sockets one level deep inside dir. For recursive permission, use allow-unix-socket-subtree-bind.

If dir contains shell variable references, wrap it with noescape:

(allow-unix-socket-dir-bind (noescape "$XDG_RUNTIME_DIR"))

allow-unix-socket-subtree

allow-unix-socket-subtree :: String -> Permission

Source

Allows the sandboxed process to connect to any unix socket anywhere under dir, recursively. For one-level-only access, use allow-unix-socket-dir.

If dir contains shell variable references, wrap it with noescape:

(allow-unix-socket-subtree (noescape "$XDG_RUNTIME_DIR"))

allow-unix-socket-subtree-bind

allow-unix-socket-subtree-bind :: String -> Permission

Source

Allows the sandboxed process to create (bind) unix sockets anywhere under dir, recursively. For one-level-only permission, use allow-unix-socket-dir-bind.

If dir contains shell variable references, wrap it with noescape:

(allow-unix-socket-subtree-bind (noescape "$XDG_RUNTIME_DIR"))

audit-integrity

audit-integrity :: Permission

Source

Enables integrity verification of the audit chain.

When set, nono verifies that no audit entries have been tampered with before processing them. Any gap or modification in the chain causes the verification to fail loudly rather than silently accepting a potentially altered record.

Pair with audit-sign-key if you also want entries cryptographically signed at write time.


audit-sign-key

audit-sign-key :: String -> Permission

Source

Signs audit entries with the given key reference.

key is a URI pointing at the signing key. Supported schemes:

  • op://vault/item/field — 1Password secret reference
  • env://VAR — read from an environment variable
  • file://path — read from a file on disk

Each audit entry gets a signature nono can verify later. Combine with audit-integrity to also verify the chain hasn't been truncated or reordered.


block-command

block-command :: String -> Permission

Source

Blocks the sandboxed process from executing cmd.

Useful for preventing specific subcommands or tools from running inside the sandbox without building a full allowlist via allow-command.

(block-command "/run/current-system/sw/bin/curl")

block-net

block-net :: Permission

Source

Blocks all network access for the sandboxed application.


bypass-protection

bypass-protection :: String -> Permission

Source

Bypasses nono's built-in protection for path.

Nono protects certain paths by default (e.g. ~/.ssh, ~/.gnupg). If a legitimate app genuinely needs access to one of those paths, use this combinator to carve out an exception. The path still needs to be granted by the profile — this just lifts the extra protection layer on top.

Example:

bypass-protection "~/.ssh/known_hosts"

camera

camera :: Permission

Source

Allows access to webcams and other V4L2 video devices at /dev/video*.


capability-elevation

capability-elevation :: Permission

Source

Enables runtime approval prompts for privileged operations.

When the sandboxed process tries to exceed its declared grants, nono normally denies the operation silently. With this combinator, nono shows an interactive approval dialog instead, letting you approve or deny the escalation in real time.

Requires supervised exec mode (nono run). Useful during profile development to catch missing grants without having to rerun from scratch.


compose

compose :: [Permission] -> Permission

Source

Composes a list of permissions into a single permission.


credential

credential :: String -> Permission

Source

Injects credentials for a service via nono's credential proxy.

The service argument identifies the credential to inject (e.g., openai, anthropic, gemini). Requires exec-mode "run" (nono supervised mode).

Example:

credential "anthropic"

defer

defer :: Permission -> Permission

Source

Defers the specified permission to be applied after all non-deferred permissions.

This is useful if a permission needs to read state set by other permissions.


deny

deny :: String -> Permission

Source

Explicitly denies access to a path, overriding any broader grants.

Useful for blocking sensitive subdirectories when a parent directory has been granted. For example, granting ~/.config but blocking ~/.config/secrets.

Example:

compose [
  (readwrite "~/.config")
  (deny "~/.config/secrets")
]

deny-env

deny-env :: String -> Permission

Source

Prevents an environment variable from reaching the sandbox.

Supports PREFIX_* prefix patterns to deny whole namespaces. Takes precedence over fwd-env and try-fwd-env.

Example:

deny-env "AWS_SECRET_ACCESS_KEY"
deny-env "AWS_*"

env-credential

env-credential :: String -> Permission

Source

Injects a credential from a secret store as an environment variable.

The key is a URI identifying the credential source: * op://vault/item/field — 1Password * env://VAR — from an environment variable on the host * file://path — from a file on the host

Example:

env-credential "op://Personal/OpenAI/credential"
env-credential "env://ANTHROPIC_API_KEY"

env-credential-map

env-credential-map :: String -> String -> Permission

Source

Injects a credential at a URI into a specific environment variable.

Like env-credential, but lets you name the environment variable explicitly rather than using the credential's default name.

Example:

env-credential-map "op://Personal/OpenAI/credential" "OPENAI_API_KEY"

escape

escape :: String -> String

Source

Shell escapes the passed string.

Use noescape to prevent escaping.

escape and noescape don't return Permissions, but they are useful helpers to expose when defining jails and writing custom combinators, so they are exposed with the rest of the combinators for convenience.

Example:

nono-nix.lib.extend {
  inherit pkgs;
  additionalCombinators = combinators: with combinators; {
    # a combinator that grants read access to an escaped path
    my-combinator = path: unsafe-add-raw-args "--read ${escape path}";
  };
}

exec-mode

exec-mode :: String -> Permission

Source

Sets the nono execution mode. Valid values are "run" and "wrap".

"run" (the default) uses supervised mode: nono stays alive alongside the sandboxed process, enabling audit logging, rollback snapshots, credential injection, and capability elevation prompts.

"wrap" uses exec-replace mode: nono execs directly into the target process for lower overhead. You lose the supervised features but get a simpler process tree and slightly faster startup.

Example:

exec-mode "wrap"

extends-profile

extends-profile :: String -> Permission

Source

Extends a named nono profile from the built-in profile registry.

The generated profile inherits all grants from name and then applies whatever additional combinators you stack on top. Built-in profiles include things like "default", "claude-code", and "opencode".

Example:

compose [
  (extends-profile "claude-code")
  (groups-include "network")
]

fwd-env

fwd-env :: String -> Permission

Source

Forwards the specified environment variable to the sandboxed process.

If the variable is not set when the sandboxed application runs, it will exit non-zero (variable unbound error).

If you want to tolerate an unset variable, use try-fwd-env instead.


gpu

gpu :: Permission

Source

Exposes GPUs to the sandboxed application.

Sets allowGpu = true in the sandbox state, which causes the nono invocation to include --allow-gpu. nono handles the details automatically — DRM, NVIDIA, AMD, Metal, and WSL2 are all covered by that single flag.


groups-exclude

groups-exclude :: String -> Permission

Source

Excludes a named permission group from the profile.

Use this to pull a group out of an inherited profile. For example, if you extend "default" but don't want the "clipboard" group it includes, you can exclude it here rather than rewriting the whole profile from scratch.

Example:

compose [
  (extends-profile "default")
  (groups-exclude "clipboard")
]

groups-include

groups-include :: String -> Permission

Source

Includes a named permission group from the profile's group registry.

Groups bundle related grants together under a single name (e.g. "network", "fonts", "clipboard"). This combinator opts the sandbox into one of those bundles without having to spell out every grant individually.

Example:

compose [
  (groups-include "network")
  (groups-include "fonts")
]

gui

gui :: Permission

Source

Exposes everything required to get graphical applications working.

This composes pulse, pipewire, wayland, and forwards/grants read access to a few other paths to get fonts and cursor rendering to work correctly.


include-once

include-once :: String -> Permission -> Permission

Source

Only run the passed permission if include-once hasn't been previously called with the specified key.

This is useful when writing your own combinators.

let
  nono = nono-nix.lib.extend {
    inherit pkgs;
    additionalCombinators = combinators: with combinators; {
      # foo isn't `include-once` so each call to it adds a new echo
      foo = add-runtime "echo foo";
      # bar will only be included once, no matter how many times it is called
      bar = include-once "bar" (add-runtime "echo bar");
    };
  };
in
  # Prints:
  # foo
  # foo
  # foo
  # bar
  # Hello, world!
  nono "test" pkgs.hello (c: with c; [
    foo
    foo
    foo
    bar
    bar
    bar
  ])

ipc-mode

ipc-mode :: String -> Permission

Source

Controls IPC access for the sandboxed process.

Valid values:

  • "shared_memory_only" — restricts IPC to shared memory; message queues and semaphores are blocked
  • "full" — allows all IPC mechanisms

The default when this combinator is not used depends on nono's built-in policy.


jail-to-host-channel

jail-to-host-channel :: String -> String -> Combinator

Source

Allows programs in the sandbox to execute and pass messages to a specific handler that runs outside of the sandbox.

The first parameter specifies a name of a program that is exposed to the sandbox that, when called, sends its first argument to the script passed to the second parameter. The script runs outside of the sandbox. Any stdout generated by the script is relayed back as stdout from the program in the sandbox.

Current limitations:

  • Only a single argument is supported. For more arguments you will need to use an encoding like JSON.
  • Only stdout is relayed back to the sandbox, stderr will be visible in your terminal but the sandbox won't be able to read it.
  • The first parameter must be a valid POSIX variable name.

Example:

jail-to-host-channel "getHostFileSize" ''
  # This runs *outside* of the sandbox
  if [ -f "$1" ]; then
    wc -c < "$1"
  else
    echo "$1 is not a file on the host"
  fi
''

This exposes a program inside the sandbox called getHostFileSize that returns the size of the file passed in without needing to give the sandbox read access to any files.

The channel program inside the sandbox finds the FIFO via the J2H_CHAN_<NAME>_TMP environment variable that is forwarded automatically.


listen-port

listen-port :: Int -> Permission

Source

Allows the sandbox to bind and listen on a port.

Example:

listen-port 3000

mount-cwd

mount-cwd :: Permission

Source

Grants read-write access to the working directory at runtime ($PWD).


network

network :: Permission

Source

Grants network access to the sandbox.

Since nono runs on the real network namespace, no namespace sharing is needed. This combinator grants read access to the files required for DNS resolution, TLS certificate verification, and timezone handling.

Exposed paths:

  • /etc/hosts
  • /etc/nsswitch.conf
  • /etc/resolv.conf
  • /etc/ssl
  • /etc/static/ssl (optional — NixOS symlink chain to CA bundle)
  • /run/systemd/resolve (optional — silently skipped if absent)
  • Timezone via time-zone
  • CA certificate bundle (pkgs.cacert) via SSL_CERT_FILE

network-profile

network-profile :: String -> Permission

Source

Sets the nono network profile for the sandbox.

Available profiles: minimal, developer, claude-code, opencode, enterprise. Implies proxy mode.

Example:

network-profile "developer"

no-audit

no-audit :: Permission

Source

Disables nono's audit chain for this invocation.

By default nono records every access decision to an audit log. This combinator turns that off. Only use it during development — production sandboxes should leave auditing on so you can trace what happened if something goes wrong.


noescape

noescape :: String -> NoEscapedString

Source

Prevent the passed string from being automatically shell escaped.

escape and noescape don't return Permissions, but they are useful helpers to expose when defining sandboxes and writing custom combinators, so they are exposed with the rest of the combinators for convenience.

It is the caller's responsibility to ensure anything passed to this is correctly escaped.

# Probably doesn't do what you intended since "~/foo" is shell escaped:
(readonly "~/foo")

# This properly makes $HOME/foo readonly in the sandbox:
(readonly (noescape "~/foo"))

# Binds the path specified by the runtime $FOO variable as read only.
#
# Note that we must properly quote this to ensure bash correctly keeps it
# as a single argument, even if it contains spaces:
(readonly (noescape "\"$FOO\""))

nono-name

nono-name :: String -> Permission

Source

Sets the nono session name (passed as --name).

The session name identifies this invocation in nono status output and audit logs. If you're running multiple sandboxes at once, giving each one a distinct name makes it much easier to tell them apart.

Example:

nono-name "my-tool"

open-port

open-port :: Int -> Permission

Source

Opens a localhost port for the sandbox to connect out on.

Example:

open-port 8080

open-urls-in-browser

open-urls-in-browser :: Permission

Source

Allows access to open URLs in $BROWSER.

This works by creating a pipe that is mounted into the sandbox that forwards all URLs to the $BROWSER outside of the sandbox. This way the sandboxed program can launch your browser, even if it has a subset of the permissions your browser has.

Only URLs beginning with http(s):// will be forwarded.


pipewire

pipewire :: Permission

Source

Exposes PipeWire to the sandboxed application.

Forwards XDG_RUNTIME_DIR and allows the PipeWire Unix socket at $XDG_RUNTIME_DIR/pipewire-0.


process-info-mode

process-info-mode :: String -> Permission

Source

Controls whether the sandboxed process can read /proc entries for other processes.

Valid values:

  • "isolated" — blocks access to other processes' /proc entries; the process can only see its own
  • "allow_same_sandbox" — allows reading /proc entries for processes in the same sandbox
  • "allow_all" — unrestricted /proc access across all processes

The default when this combinator is not used depends on nono's built-in policy.


pulse

pulse :: Permission

Source

Exposes PulseAudio to the sandboxed application.

Forwards XDG_RUNTIME_DIR and optionally PULSE_SERVER, then allows the PulseAudio Unix sockets in $XDG_RUNTIME_DIR/pulse and /run/pulse.


readonly

readonly :: String -> Permission

Source

Grants read-only access to the specified path.

The path is checked at launch time: if it does not exist the sandbox refuses to start with a clear error. Use try-readonly if a missing path should be silently skipped instead.

Pass a noescape value to reference ~ or $VAR, which are expanded by the shell at launch.


readonly-file

readonly-file :: String -> Permission

Source

Grants read-only access to a single file.

Unlike readonly which grants a directory subtree, this grants access only to the specific file at path.

The file is checked at launch time: if it does not exist the sandbox refuses to start with a clear error. Use try-readonly-file if a missing file should be silently skipped instead.

Example:

readonly-file "/etc/ssl/certs/ca-certificates.crt"

readonly-paths-from-var

readonly-paths-from-var :: String -> String -> Permission

Source

Grants read-only access to multiple paths specified by a single runtime environment variable.

The first argument is the runtime environment variable that contains a list of paths. The second argument is the delimiter used to split the paths (typically " " or ":").

This is useful for variables like XDG_DATA_DIRS, GTK_PATH, XCURSOR_PATH, etc.

Example:

compose [
  (readonly-paths-from-var "XDG_DATA_DIRS" ":")
  (readonly-paths-from-var "XCURSOR_PATH" " ")
]

readonly-runtime-args

readonly-runtime-args :: Permission

Source

Grants read-only access to any valid paths passed as arguments to the sandboxed program at runtime.


readwrite

readwrite :: String -> Permission

Source

Grants read-write access to the specified path.

The path is checked at launch time: if it does not exist the sandbox refuses to start with a clear error. Use try-readwrite if a missing path should be silently skipped instead.

Pass a noescape value to reference ~ or $VAR, which are expanded by the shell at launch.


readwrite-file

readwrite-file :: String -> Permission

Source

Grants read-write access to a single file.

Unlike readwrite which grants a directory subtree, this grants access only to the specific file at path.

The file is checked at launch time: if it does not exist the sandbox refuses to start with a clear error. Use try-readwrite-file if a missing file should be silently skipped instead.

Example:

readwrite-file "~/.config/myapp/state.json"

readwrite-runtime-args

readwrite-runtime-args :: Permission

Source

Grants read-write access to any valid paths passed as arguments to the sandboxed program at runtime.


reset

reset :: Permission

Source

Resets the sandbox state back to the initial empty state.

All permissions before this one (including ones set in basePermissions) are removed.

This is useful if you have some permissions set in basePermissions that you want for most of your sandboxes, but want to remove them for a one-off sandbox.

Example:

  nono "some-package" some-package (combinators: with combinators; [
    # First, use reset to remove the base combinators:
    reset

    # Then, re-apply the base combinators you want:
    base
    bind-nix-store-runtime-closure
    (readwrite "/some/path")
  ])

rollback

rollback :: Permission

Source

Enables atomic rollback snapshots for this sandbox.

When enabled, filesystem changes made by the sandboxed process can be rolled back on exit or failure. Nono captures a snapshot before the process runs and restores it if the process exits non-zero or if rollback is triggered manually.

Requires supervised exec mode (nono run). Use with rollback-all if you want to capture all changes regardless of what the profile grants.


rollback-all

rollback-all :: Permission

Source

Tracks all filesystem changes for rollback, regardless of what the profile grants.

Normally rollback only covers paths within the profile's declared grants. This flag tells nono to snapshot everything the process touches, even paths not explicitly listed in the profile. Useful when you want a complete before/after snapshot and don't want gaps.

Combine with rollback to enable the rollback feature itself.


rollback-exclude

rollback-exclude :: String -> Permission

Source

Excludes a glob pattern from rollback tracking.

Paths matching pattern won't be snapshotted or restored when rollback runs. Useful for excluding things like cache directories or log files that you don't want rewound.

Example:

compose [
  rollback
  (rollback-exclude "~/.cache/**")
  (rollback-exclude "/tmp/**")
]

rollback-exclude-glob

rollback-exclude-glob :: String -> Permission

Source

Excludes files matching a glob from rollback tracking.

Unlike rollback-exclude which matches against path components, this glob is matched against the filename only. For example, "*.log" excludes every file ending in .log anywhere under the snapshot.

Example:

compose [
  rollback
  (rollback-exclude-glob "*.log")
  (rollback-exclude-glob "*.tmp")
]

rollback-include

rollback-include :: String -> Permission

Source

Adds an extra path to rollback tracking coverage.

By default, rollback only tracks paths covered by the active profile's grants. Use this to pull in additional paths that the profile doesn't explicitly grant but that you still want snapshotted.

Example:

compose [
  rollback
  (rollback-include "~/.config/myapp")
]

set-argv

set-argv :: [String] -> Permission

Source

Overrides the current argv that is passed to the sandboxed executable.

By default argv is set to noescape "$@" which will forward whatever arguments are provided to the wrapper script at runtime. Calling this will override the current value.


set-env

set-env :: String -> String -> Permission

Source

Sets the specified environment variable for the sandboxed process.

This will throw if the variable name is not a valid POSIX variable name.


signal-mode

signal-mode :: String -> Permission

Source

Controls which processes can send signals to the sandboxed process.

Valid values:

  • "isolated" — blocks all external signals; only the process itself can signal itself
  • "allow_same_sandbox" — allows signals from processes in the same sandbox
  • "allow_all" — any process on the system can signal the sandboxed process

The default when this combinator is not used depends on nono's built-in policy.


startup-timeout

startup-timeout :: Int -> Permission

Source

Sets the startup timeout in seconds.

If the sandboxed process hasn't signalled readiness within secs seconds of launch, nono terminates it. This guards against hangs during initialisation — particularly useful for services that are expected to start promptly.

Example:

startup-timeout 30

suppress-save-prompt

suppress-save-prompt :: String -> Permission

Source

Suppresses the nono save-prompt dialog for writes to path.

When the sandbox tries to write to a path nono considers sensitive, it normally shows an interactive "save here?" dialog. This combinator pre-approves writes to path so the dialog never appears — useful for automated tools that write to a known location and can't handle interactive prompts.

Example:

suppress-save-prompt "~/.config/myapp/state.json"

time-zone

time-zone :: Permission

Source

Exposes your timezone to the sandbox.

If /etc/localtime is a symlink (the common case on systemd systems), the real target is also granted read access so the timezone data is actually readable inside the sandbox.


trust-override

trust-override :: Permission

Source

Overrides trust checks, allowing the sandbox to run even when trust verification would otherwise block it.

Nono normally refuses to run if the binary or profile fails a trust check (e.g. unsigned profile, unknown binary hash). This combinator bypasses that gate. Use sparingly — it exists for development workflows and controlled environments, not for production sandboxes.


try-fwd-env

try-fwd-env :: String -> Permission

Source

Forwards the specified environment variable to the sandboxed process (if set).


try-readonly

try-readonly :: String -> Permission

Source

Grants read-only access to the path if it exists, silently skips otherwise.

Automatically handles both files and directories. Unlike readonly, a missing path does not fail the sandbox.

Pass a noescape value to reference ~ or $VAR, which are expanded by the shell at launch.


try-readonly-file

try-readonly-file :: String -> Permission

Source

Grants read-only access to a single file if it exists, silently skips otherwise.

Same as readonly-file but doesn't fail when the file is absent at launch.

Example:

try-readonly-file "~/.gitconfig"

try-readwrite

try-readwrite :: String -> Permission

Source

Grants read-write access to the path if it exists, silently skips otherwise.

Automatically handles both files and directories. Unlike readwrite, a missing path does not fail the sandbox.

Pass a noescape value to reference ~ or $VAR, which are expanded by the shell at launch.


try-readwrite-file

try-readwrite-file :: String -> Permission

Source

Grants read-write access to a single file if it exists, silently skips otherwise.

Same as readwrite-file but doesn't fail when the file is absent at launch.

Example:

try-readwrite-file "~/.config/myapp/state.json"

try-write-only

try-write-only :: String -> Permission

Source

Grants write-only access to a path if it exists, silently skips otherwise.

Automatically handles both files and directories. Unlike write-only, a missing path does not fail the sandbox.

Example:

try-write-only "/var/log/myapp"

unsafe-add-raw-args

unsafe-add-raw-args :: String -> Permission

Source

Appends the raw string as flags to the nono invocation.

Nothing is escaped — it is the caller's responsibility to ensure everything is properly escaped. Shell variable references in the string expand at runtime.

A noescape value is accepted and unwrapped to its raw string, so combinators that build flags containing $VAR references can pass noescape without it being coerced into the profile.


unsafe-dbus

unsafe-dbus :: Permission

Source

Exposes the D-Bus session bus to the sandboxed program.

This does no message filtering so it is marked as unsafe. If you want more control over the messages that can be sent/received, consider using the dbus combinator instead.

Forwards DBUS_SESSION_BUS_ADDRESS and XDG_RUNTIME_DIR, then allows the session bus socket at $XDG_RUNTIME_DIR/bus.


unsafe-x11

unsafe-x11 :: Permission

Source

Exposes X11 to the sandboxed application.

Note that applications may be able to break out of the sandbox because X11 is not designed to be a security boundary.

For a safer alternative, consider using the xwayland combinator inside of a Wayland compositor.


upstream-bypass

upstream-bypass :: String -> Permission

Source

Bypasses the upstream proxy for a domain.

Example:

upstream-bypass "internal.corp.example.com"

upstream-proxy

upstream-proxy :: String -> Permission

Source

Routes traffic through an upstream proxy at HOST:PORT.

Example:

upstream-proxy "proxy.corp.example.com:8080"

wayland

wayland :: Permission

Source

Exposes your Wayland compositor to the sandbox.

Forwards WAYLAND_DISPLAY, XDG_RUNTIME_DIR, and XDG_SESSION_TYPE, then allows the compositor's Unix socket at $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY.


workdir

workdir :: String -> Permission

Source

Sets the working directory for the sandboxed process (passed as --workdir).

The sandboxed process starts with its current directory set to path. If unset, nono inherits the caller's working directory.

Example:

workdir "/var/lib/myapp"

wrap-entry

wrap-entry :: (String -> String) -> Permission

Source

Wraps the binary to be sandboxed in a bash script that will be the new entrypoint to the sandbox.

This similar in spirit to the add-runtime combinator, except that this runs inside the sandbox, while add-runtime runs before the sandbox starts.

Example:

wrap-entry (entry: ''
  echo 'Inside the sandbox!'
  ${entry}
  echo 'Cleaning up...'
'')

write-only

write-only :: String -> Permission

Source

Grants write-only access to a path.

The sandboxed process can write files under path but cannot read them back. Use this for append-only log sinks or output directories where read access isn't needed.

The path is checked at launch time: if it does not exist the sandbox refuses to start with a clear error. Use try-write-only if a missing path should be silently skipped instead.

Pass a noescape value to reference ~ or $VAR, which are expanded by the shell at launch.

Example:

write-only "/var/log/myapp"

write-only-file

write-only-file :: String -> Permission

Source

Grants write-only access to a single file.

The sandboxed process can write to the file at path but cannot read it. Unlike write-only which covers a directory, this pins access to one file.

The file is checked at launch time: if it does not exist the sandbox refuses to start with a clear error.

Example:

write-only-file "/var/log/myapp/output.log"

write-text

write-text :: String -> String -> Permission

Source

Creates a read-only text file in the nix store and grants the sandbox access to it.

Note: the file is accessible at its nix store path, not at the path argument — nono cannot remap paths. The path argument is used only for derivation naming.

Example:

# Creates a text file and grants the sandbox read access to it.
# Find it at its nix store path, e.g. /nix/store/...-nono-write-text-hello-txt
write-text "/hello.txt" "Hello, world!"

xwayland

xwayland :: Permission

Source

Safely allow X11 apps to render to a Wayland compositor.

This combinator runs xwayland-satellite inside the sandbox and only exposes wayland combinator.

This has the advantage of not allowing multiple sandboxed X11 applications to see each other since each sandboxed application gets its own xwayland-satellite server.

However, doing it this way does mean that every sandboxed application you run with this combinator will spin up its own personal xwayland-satellite server, which will consume more resources than having a global one.


Default Included Combinators

The following combinators are enabled by default, and do not need to be explicitly added to your sandboxes unless you override basePermissions.

base

base :: Permission

Source

Sets up the minimal environment every sandboxed program needs.

Because nono runs as the real user on the real filesystem (no namespace isolation), there's no need to fake /proc, /dev, or /tmp. This combinator just makes sure coreutils is on $PATH and that the basic environment variables are forwarded in.

This combinator:

  • Adds coreutils to the package deps (add-pkg-deps [ pkgs.coreutils ])
  • Forwards HOME into the sandbox
  • Tries to forward LANG and TERM (silently skipped if unset)

This is included in the base permissions by default so you shouldn't need to include it unless you override base permissions. It is exposed as a combinator (like the other default included combinators) so that you can use it in a custom basePermissions.


bind-nix-store-runtime-closure

bind-nix-store-runtime-closure :: Permission

Source

Grants read access to all /nix/store paths in the runtime closure of the sandboxed application via Landlock.

At Nix build time the full closure is computed with exportReferencesGraph and written to a text file. At runtime that file is read and each path is added to NONO_EXTRA_FLAGS as --read <path>.

If you don't have any sensitive nix store paths, you may consider just granting read access to /nix/store directly instead.

For example, the sandbox defined by

# Note that this combinator is included in base permissions, so it does
# not need to be provided:
let listNixStore = pkgs.writeShellScriptBin "list-nix-store" "ls -l /nix/store";
in nono "list-nix-store" listNixStore [];

will only expose the closure paths for list-nix-store, rather than your entire nix store.


Deprecated Combinators

The following combinators have been deprecated, and may be removed in the future.