nono includes comprehensive integration tests that verify the sandbox enforcement works correctly across different scenarios and platforms.
Running Tests
Full Test Suite
Run all integration tests with:
./tests/run_integration_tests.sh
This script:
- Builds nono in release mode
- Runs all 7 test suites
- Reports results with pass/fail/skip counts
- Exits with non-zero status if any tests fail
Individual Test Suites
Run a specific test suite:
# Build first
cargo build --release
# Export binary location
export NONO_BIN="$(pwd)/target/release/nono"
# Run a specific suite
./tests/integration/test_fs_access.sh
Test Suites
The integration tests are organized into 7 focused suites:
1. Filesystem Access (test_fs_access.sh)
Tests that nono correctly enforces read/write permissions on directories and files.
| Test Category | What It Verifies |
|---|
| Directory Read | Files can be read in granted directories |
| Directory Write | Files can be written in granted directories |
| Nested Access | Permissions apply to subdirectories |
| Read-only Mode | --read flag allows reads but not writes |
| Write-only Mode | --write flag allows writes but not reads |
| Single File Access | --read-file and --write-file grant file-level permissions |
| Multiple Grants | Multiple --allow, --read, --write flags work together |
2. Sensitive Paths (test_sensitive_paths.sh)
Verifies that credential and configuration files are protected by default.
Protected paths include:
~/.ssh/ - SSH keys
~/.aws/ - AWS credentials
~/.gnupg/ - GPG keys
~/.kube/ - Kubernetes config
~/.docker/ - Docker credentials
~/.npmrc - npm auth tokens
~/.netrc - Network credentials
~/.bash_history, ~/.zsh_history - Command history
~/.bashrc, ~/.zshrc - Shell configs
These paths are blocked even if a parent directory is explicitly allowed.
3. System Paths (test_system_paths.sh)
Tests protection of system directories.
| Test Category | What It Verifies |
|---|
| System Reads | Can read from /usr/bin, /etc (needed for executables) |
| System Writes | Cannot write to system directories |
| Root Protection | Cannot write to /, /tmp/.. escapes |
| macOS Specifics | /System/Library is readable but not writable |
4. Binary Execution (test_binary_exec.sh)
Verifies that various binaries execute correctly under the sandbox.
| Category | Commands Tested |
|---|
| Basic | echo, true, false, exit codes |
| File Operations | ls, cat, head, tail, wc, grep, find, touch, mkdir |
| Shells | sh, bash, zsh, env, printenv |
| Text Processing | sort, uniq, cut, sed, awk |
| Language Runtimes | python3, node, ruby, perl, gofmt |
| Output Verification | Correct output from commands |
Language runtime tests (Python, Node, Ruby) may be skipped if the runtime is installed via Homebrew, as /opt/homebrew isn’t in the sandbox allowlist by default.
5. Network (test_network.sh)
Tests network blocking functionality.
| Test | What It Verifies |
|---|
--net-block | curl, wget, nc, ping are blocked |
| Default (allowed) | Network access works without --net-block |
| DNS Resolution | host, nslookup, dig work when network is allowed |
6. Dangerous Commands (test_commands.sh)
Verifies that potentially destructive commands are blocked by default.
| Category | Commands Blocked |
|---|
| Destructive | rm, rmdir, mv |
| Permissions | chmod, chown, chgrp |
| Privilege | sudo, su, doas |
| Package Managers | pip, npm, gem, cargo install |
| System | shutdown, reboot, kill, killall |
Also tests:
--allow-command flag to permit specific blocked commands
--block-command flag to block additional commands
7. Edge Cases (test_edge_cases.sh)
Tests unusual scenarios and boundary conditions.
| Test Category | What It Verifies |
|---|
| Symlinks | Symlink traversal within allowed paths |
| Symlink Escapes | Symlinks to sensitive paths are blocked |
| Path Variations | Relative paths, .. references, spaces, special characters |
| Capability Queries | nono why --self for sandbox introspection, NONO_CAP_FILE env var |
| Non-existent Paths | Proper error handling for missing paths |
| Dry Run Mode | --dry-run shows sandbox info without executing |
| Mixed Permissions | Combining --read and --write directories |
Test Framework
Tests use a shared helper library (tests/lib/test_helpers.sh) providing:
# Run a test expecting success (exit 0)
expect_success "test name" command args...
# Run a test expecting failure (non-zero exit)
expect_failure "test name" command args...
# Check command output contains a string
expect_output_contains "test name" "expected string" command args...
# Skip a test with a reason
skip_test "test name" "reason"
# Platform checks
is_macos # Returns true on macOS
is_linux # Returns true on Linux
# Check if a command is available
command_exists curl
CI Pipeline
Integration tests run automatically in GitHub Actions on:
- Pull requests to
main
- Pushes to
main
The CI runs tests on both Ubuntu and macOS:
integration:
name: Integration Tests
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Build release binary
run: cargo build --release
- name: Run integration tests
run: ./tests/run_integration_tests.sh
macOS Notes
-
TMPDIR: On macOS,
/var/folders (where TMPDIR points) is a system-writable path. Tests that expect write denial within TMPDIR won’t work. Write denial is instead verified via system paths (/usr/bin, /etc).
-
Homebrew runtimes: Language runtimes installed via Homebrew at
/opt/homebrew/ aren’t in the sandbox allowlist. Tests for Python, Node, Ruby gracefully skip if the runtime isn’t accessible.
Linux Notes
- Landlock ABI: Tests should work on any Landlock-enabled kernel (5.13+). Network filtering requires ABI v4+ (kernel 6.7+).
Adding New Tests
-
Create a new test file in
tests/integration/:
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/../lib/test_helpers.sh"
echo ""
echo -e "${BLUE}=== My New Tests ===${NC}"
verify_nono_binary
TMPDIR=$(setup_test_dir)
trap 'cleanup_test_dir "$TMPDIR"' EXIT
# Your tests here
expect_success "my test" "$NONO_BIN" run --allow "$TMPDIR" -- echo "hello"
print_summary
-
Add the suite to
tests/run_integration_tests.sh:
run_suite "$SCRIPT_DIR/integration/test_my_new.sh" "My New Tests"
-
Make the script executable:
chmod +x tests/integration/test_my_new.sh