scooter  ·  2026-05-03

jail.sh

  1#!/usr/bin/env bash
  2
  3# opencode-sandbox - Run OpenCode in a sandboxed firejail environment
  4# This script runs in firejail with filesystem isolation
  5# while maintaining access to current directory and configuration
  6#
  7# NOTE: This script requires system-installed firejail and opencode.
  8# Install them via your package manager (e.g., pacman, apt, dnf).
  9
 10set -euo pipefail
 11
 12# Parse --allow flags to add extra whitelisted directories
 13ALLOWED_DIRS=()
 14while [[ $# -gt 0 ]]; do
 15    case "$1" in
 16        --allow)
 17            if [[ $# -lt 2 ]]; then
 18                echo "Error: --allow requires a directory argument" >&2
 19                exit 1
 20            fi
 21            ALLOWED_DIRS+=("$2")
 22            shift 2
 23            ;;
 24        --)
 25            shift
 26            break
 27            ;;
 28        -*)
 29            echo "Error: Unknown flag: $1" >&2
 30            echo "Usage: jail [--allow <dir>]... <command> [args...]" >&2
 31            exit 1
 32            ;;
 33        *)
 34            break
 35            ;;
 36    esac
 37done
 38
 39# Check that a command was provided
 40if [[ $# -eq 0 ]]; then
 41    echo "Error: No command specified" >&2
 42    echo "Usage: jail [--allow <dir>]... <command> [args...]" >&2
 43    exit 1
 44fi
 45
 46# Check for required system dependencies
 47if ! command -v firejail &> /dev/null; then
 48    echo "Error: firejail is not installed or not in PATH" >&2
 49    echo "Please install firejail using your system package manager:" >&2
 50    echo "  Arch Linux: sudo pacman -S firejail" >&2
 51    echo "  Ubuntu/Debian: sudo apt install firejail" >&2
 52    echo "  Fedora: sudo dnf install firejail" >&2
 53    exit 1
 54fi
 55
 56if ! command -v opencode &> /dev/null; then
 57    echo "Error: opencode is not installed or not in PATH" >&2
 58    echo "Please install opencode using your system package manager" >&2
 59    exit 1
 60fi
 61
 62# Enable OpenCode experimental support for oxfmt when listed as a package dependency
 63export OPENCODE_EXPERIMENTAL_OXFMT="true"
 64export EDITOR="echo"
 65
 66# Capture current environment
 67CURRENT_DIR="$(pwd)"
 68ROOT="$(git rev-parse --show-toplevel)"
 69
 70# For NixOS: resolve to actual Nix store paths (not symlinks)
 71OPENCODE_PATH="$(readlink -f "$(which opencode)")"
 72echo "Using $OPENCODE_PATH"
 73
 74# Build firejail command arguments
 75FIREJAIL_ARGS=(
 76    # Use noprofile to avoid default restrictions that might block large directories
 77    --noprofile
 78
 79    # Security restrictions
 80    # NOTE: --private-tmp removed to allow opencode access to system /tmp
 81    # for test scratch space and shared temporary files
 82    --noroot                   # Disable su/sudo inside sandbox
 83    --caps.drop=all           # Drop all capabilities
 84    --nonewprivs              # Prevent privilege escalation
 85    --nogroups                # Don't inherit supplementary groups
 86
 87    # Filesystem access - whitelist specific paths only
 88    --whitelist="$ROOT"
 89    --read-only="$ROOT"
 90    --whitelist="$ROOT/.git"  # if started in a subdirectory of a git project
 91    --read-write="$ROOT/.git" # => needs access to .git and .jj for bug and commits
 92    --whitelist="$ROOT/.jj"
 93    --read-write="$ROOT/.jj"
 94    --whitelist="$CURRENT_DIR"        # Allow access to current directory
 95    --read-write="$CURRENT_DIR"       # Make current directory writable
 96    --whitelist="/nix/store"       # Make Nix tools available in dev shell
 97    --read-only="/nix/store"
 98    --whitelist="$HOME/.bashrc"
 99    --read-write="$HOME/.bashrc" # tool call aliases
100    --whitelist="$HOME/.agents"
101    --read-write="$HOME/.agents" # skills
102    --whitelist="$HOME/.ssh" # to troubleshoot Nix depoyment
103    --read-only="$HOME/.ssh"
104
105    # Terminal access - required for interactive TUI applications
106    --whitelist=/dev/tty        # Allow access to controlling terminal
107    --read-write=/dev/tty
108
109    # Device access required for Bun/JavaScriptCore
110    --whitelist=/dev/shm        # Shared memory required by JSC
111    --read-write=/dev/shm
112    --whitelist=/dev/urandom    # Randomness required for crypto/timing
113    --read-only=/dev/urandom
114    --whitelist=/dev/random     # Randomness fallback
115    --read-only=/dev/random
116    --whitelist=/dev/null       # Standard I/O
117    --whitelist=/dev/zero       # Memory allocation helpers
118    --whitelist=/dev/full
119    --whitelist=/dev/pts        # Psuedo TTY
120)
121
122# Blacklist specific tools resident in /usr/bin environment that you absolutely don't want
123# OpenCode using. This augments any restrictions you put in your OpenCode permissions.
124BLACKLIST=(
125    npm
126    /usr/bin/npm
127    yarn
128    java
129    perl
130)
131for bl in "${BLACKLIST[@]}"; do
132    FIREJAIL_ARGS+=(--blacklist="$(which "$bl")")
133done
134
135# Add configuration access if files/directories exist
136if [ -d "$HOME/.config/opencode" ]; then
137    FIREJAIL_ARGS+=(--whitelist="$HOME/.config/opencode")
138    FIREJAIL_ARGS+=(--read-write="$HOME/.config/opencode")
139
140    # auth creds and logs
141    FIREJAIL_ARGS+=(--whitelist="$HOME/.local/share/opencode")
142    FIREJAIL_ARGS+=(--read-write="$HOME/.local/share/opencode")
143fi
144if [ -d "$HOME/.config/jj" ]; then
145    FIREJAIL_ARGS+=(--whitelist="$HOME/.config/jj")
146    FIREJAIL_ARGS+=(--read-only="$HOME/.config/jj")
147fi
148
149# Add PNPM store
150if [ -d "$HOME/.local/share/pnpm" ]; then
151    FIREJAIL_ARGS+=(--whitelist="$HOME/.config/pnpm")
152    FIREJAIL_ARGS+=(--read-only="$HOME/.config/pnpm")
153    FIREJAIL_ARGS+=(--whitelist="$HOME/.local/share/pnpm")
154    FIREJAIL_ARGS+=(--read-write="$HOME/.local/share/pnpm")
155    FIREJAIL_ARGS+=(--whitelist="$HOME/.cache/node") # corepack installs
156    FIREJAIL_ARGS+=(--read-only="$HOME/.cache/node")
157
158fi
159
160# add playwright browsers
161if [ -d "$HOME/.cache/ms-playwright" ]; then
162    FIREJAIL_ARGS+=(--whitelist="$HOME/.cache/ms-playwright")
163    FIREJAIL_ARGS+=(--read-write="$HOME/.cache/ms-playwright")
164fi
165
166# Add user-specified allowed directories
167for dir in "${ALLOWED_DIRS[@]}"; do
168    FIREJAIL_ARGS+=(--whitelist="$dir")
169    FIREJAIL_ARGS+=(--read-write="$dir")
170done
171
172# Network access (allow by default, can be restricted with --net=none)
173# FIREJAIL_ARGS+=(--net=none)  # Uncomment to disable network access
174
175echo "Starting in firejail sandbox..."
176exec firejail "${FIREJAIL_ARGS[@]}" "$@"
177