gridland
Guides

Sandboxing

Run CLI apps in isolated Docker containers with zero trust

Run any CLI or TUI app inside a hardened Docker container. This is ideal for running untrusted demos, third-party packages, or student submissions with full isolation from your host system.

Terminal
bunx @gridland/container @gridland/demo -- landing

Source Types

@gridland/container accepts four kinds of sources:

SourceExampleWhat happens
npm package@gridland/demoInstalls and runs the package bin
GitHub shorthandcjroth/my-tuiClones the repo and runs it
Git URLhttps://github.com/user/repoClones the repo and runs it
Local directory./my-appMounts the directory read-only

Getting Started

Install Docker

@gridland/container requires Docker to be installed and running.

Install Docker Desktop and make sure it's running.

Terminal
curl -fsSL https://get.docker.com | sh

Run a Package

Run any npm package that exposes a CLI binary. Use -- to forward arguments to the package:

Terminal
bunx @gridland/container @gridland/demo -- landing

This runs the Gridland landing page demo inside a sandboxed container.

Arguments after -- are passed to the container entry point. Without --, the package runs with no arguments (which may just print its help text).

The first run pulls or builds the sandbox image. Subsequent runs use the cached image.

Run a GitHub Repo

Use owner/repo shorthand or a full URL:

Terminal
bunx @gridland/container cjroth/my-tui-demo

The repo is cloned with --depth 1, dependencies are installed, and the entry point from package.json is executed.

Run a Local Project

Mount a local directory into the container read-only:

Terminal
bunx @gridland/container ./my-app

The local directory is mounted read-only and copied to a tmpfs inside the container. Your source files are never modified.

Options

bunx @gridland/container <source> [options] [-- <args...>]
OptionDefaultDescription
--no-networknetwork onDisable network access inside the container
--memory <limit>512mSet the container memory limit
--buildpull firstForce a local Docker image build
-- <args...>Forward arguments to the container entry point

Examples

Terminal
# Run the Gridland landing page demo
bunx @gridland/container @gridland/demo -- landing

# Run any other Gridland demo (table, gradient, chat, etc.)
bunx @gridland/container @gridland/demo -- gradient

# Run a third-party npm package
bunx @gridland/container cowsay -- "Hello from a container"

# Run with no network access
bunx @gridland/container @gridland/demo --no-network -- landing

# Set a 1GB memory limit
bunx @gridland/container heavy-app --memory 1g

# Force rebuild the sandbox image
bunx @gridland/container my-app --build

Security

Every container runs with hardened defaults:

  • --cap-drop=ALL -all Linux capabilities dropped
  • --security-opt=no-new-privileges -prevents privilege escalation
  • --read-only -root filesystem is read-only
  • --pids-limit=256 -limits process count
  • --memory=512m -default memory cap
  • Non-root user -runs as an unprivileged runner user
  • tmpfs /tmp -writable scratch space limited to 256MB

Network access is enabled by default. Use --no-network when running untrusted code that should not make outbound connections.

How It Works

  1. The CLI detects the source type (npm, git, or local)
  2. Docker pulls the pre-built sandbox image from ghcr.io (or builds locally)
  3. A container runs with the security flags above
  4. Inside the container, the entrypoint installs dependencies and runs the app
  5. TTY is forwarded so interactive TUI apps work normally
  6. The container is removed on exit (--rm)