Skip to main content
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:
  1. Builds nono in release mode
  2. Runs all 7 test suites
  3. Reports results with pass/fail/skip counts
  4. 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 CategoryWhat It Verifies
Directory ReadFiles can be read in granted directories
Directory WriteFiles can be written in granted directories
Nested AccessPermissions 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 GrantsMultiple --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 CategoryWhat It Verifies
System ReadsCan read from /usr/bin, /etc (needed for executables)
System WritesCannot write to system directories
Root ProtectionCannot 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.
CategoryCommands Tested
Basicecho, true, false, exit codes
File Operationsls, cat, head, tail, wc, grep, find, touch, mkdir
Shellssh, bash, zsh, env, printenv
Text Processingsort, uniq, cut, sed, awk
Language Runtimespython3, node, ruby, perl, gofmt
Output VerificationCorrect 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.
TestWhat It Verifies
--net-blockcurl, wget, nc, ping are blocked
Default (allowed)Network access works without --net-block
DNS Resolutionhost, nslookup, dig work when network is allowed

6. Dangerous Commands (test_commands.sh)

Verifies that potentially destructive commands are blocked by default.
CategoryCommands Blocked
Destructiverm, rmdir, mv
Permissionschmod, chown, chgrp
Privilegesudo, su, doas
Package Managerspip, npm, gem, cargo install
Systemshutdown, 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 CategoryWhat It Verifies
SymlinksSymlink traversal within allowed paths
Symlink EscapesSymlinks to sensitive paths are blocked
Path VariationsRelative paths, .. references, spaces, special characters
Capability Queriesnono why --self for sandbox introspection, NONO_CAP_FILE env var
Non-existent PathsProper error handling for missing paths
Dry Run Mode--dry-run shows sandbox info without executing
Mixed PermissionsCombining --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

Platform-Specific Behavior

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

  1. 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
    
  2. Add the suite to tests/run_integration_tests.sh:
    run_suite "$SCRIPT_DIR/integration/test_my_new.sh" "My New Tests"
    
  3. Make the script executable:
    chmod +x tests/integration/test_my_new.sh