Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ workspace/
*.sublime-project
*.sublime-workspace
Thumbs.db
node_modules/
14 changes: 14 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Owners must have write access. Enforce CODEOWNER review in Protect main.
/.github/CODEOWNERS @BrettKinny @TheBobFella
/.github/workflows/ @BrettKinny @TheBobFella
/Dockerfile @BrettKinny @TheBobFella
/install.sh @BrettKinny @TheBobFella
/install.ps1 @BrettKinny @TheBobFella
/uninstall.sh @BrettKinny @TheBobFella
/uninstall.ps1 @BrettKinny @TheBobFella
/scripts/squarebox-entrypoint.sh @BrettKinny @TheBobFella
/scripts/release-* @BrettKinny @TheBobFella
/scripts/lib/tool-lib.sh @BrettKinny @TheBobFella
/scripts/agent/ @BrettKinny @TheBobFella
/scripts/sqrbx-agent @BrettKinny @TheBobFella
/SECURITY.md @BrettKinny @TheBobFella
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ workspace/
# OS files
Thumbs.db
.claude/settings.local.json
node_modules/
15 changes: 15 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Agent guidance

- Read `CLAUDE.md` for repository conventions and test commands.
- Read `CONTEXT.md` before changing architecture or behavior; consult `docs/adr/`.
- Keep changes scoped and run relevant deterministic tests. Before delivery,
run the executable `tests/test-*.sh` suite described in `CLAUDE.md`.
- Do not weaken fail-closed artifact verification or lifecycle ownership checks.
- Do not push, release, tag, publish, change GitHub settings, or modify secrets
unless explicitly instructed.
- Inside `sqrbx-agent`, project access is confined to `/workspace`; do not seek
host credentials or paths outside it. Use only the supplied execution tools.

These are behavioral instructions, not a security boundary. Normal Squarebox
is a trusted development environment. See `SECURITY.md` and `docs/agent.md` for
the separate hardened agent profile.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ One-line install, interactive first-run setup, sensible defaults (thanks
Preparing an existing installation for v1.2? Read the
[migration guide](docs/releases/v1.2.1.md) and [changelog](CHANGELOG.md).

For host-side Pi with isolated tool execution, see
[`sqrbx-agent`](docs/agent.md). This separate Linux profile uses an independent
session repository, disposable home, and explicit rootless Podman backend with
networking disabled by default. The normal Box remains a trusted development
environment.

![squarebox first-run setup](demo/squarebox-setup.gif)
*(Actual setup may involve more staring at the screen.)*

Expand Down
67 changes: 67 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ GitHub's digest is an integrity snapshot, not an independent publisher signature

## Container authority and isolation

### Normal Squarebox: trusted development environment

The Box is a development environment, not a hostile-code security sandbox.
The `dev` user can invoke passwordless package-management/install commands.
`dpkg` maintainer scripts and `install` can provide effective root authority
Expand Down Expand Up @@ -300,6 +302,71 @@ PUID="$(id -u)" PGID="$(id -g)" "$SQUAREBOX_DIR/install.sh"
Do not replace these resolved paths with the home directory, the install root,
or another broad recursive target.

### sqrbx-agent: hardened agent execution profile

[`sqrbx-agent`](docs/agent.md) is a separate Linux host command. Its initial
backend is explicitly selected rootless Podman, which shares the host kernel.
Gondolin would provide a micro-VM boundary; it is not implemented or claimed as
tested in this milestone. Requesting it fails instead of selecting Podman.

The host Pi runtime, pinned SDK dependencies, adapter, host OS, runtime, and
selected immutable image are trusted. The model's tool requests, project code,
instruction files, and dependencies are untrusted. A compromised host Pi
process is not contained by this architecture. No `AGENTS.md` rule substitutes
for enforcement. The adapter exposes only tools routed through the backend,
without automatic project or ordinary Pi extension discovery.

The guest receives an independent repository at `/workspace`, not the original
checkout or its common Git directory. Only committed source is copied; the
original working files and refs are not modified. Session identity and trusted
reporting metadata remain outside the guest mount. Treat retained workspace
files, including `.git` and package scripts, as hostile after execution; use
the host-controlled inspection command and review before importing or running
anything in your normal environment.

The profile runs unprivileged, drops all capabilities, enables
no-new-privileges, keeps the root filesystem read-only, and uses temporary
home/scratch mounts. The normal entrypoint and Selection reconciliation do not
run. No Managed home, host home, SSH files/agent, GitHub credentials, real Git
config, model credentials, or runtime sockets are mounted or forwarded. Private
SELinux labeling applies only to the independent workspace; agent mode does
not disable label separation. Tracked secrets already in the selected commit
remain visible to the agent, as do any files the user explicitly places there.

`--network none` is the default. `development` fails because this Podman
implementation has no enforceable destination policy. `open` is an explicit
opt-in and permits exfiltration and access to reachable services, including
potentially local-network services. Host-side Pi can still contact the selected
model provider with guest networking disabled: that provider is an authorized
recipient of source and tool output. This is not a guarantee that source stays
on the machine, nor does a hostname allowlist alone prevent data leakage.

Guest homes and execution state are discarded when execution stops. Repository
files persist until explicitly discarded, so files written into `/workspace`
can persist across resumed sessions. Resource limits bound CPU, memory, and
process counts; workspace disk usage is not quota-limited. Host kernel/runtime
vulnerabilities, malicious output presented for review, exhausted host storage,
and malicious changes subsequently run by a human are residual risks. This is
defense in depth, not absolute sandboxing. See the
[architecture decision](docs/adr/0010-isolate-agent-execution-from-the-box.md).

### GitHub review controls

The repository's `Protect main` ruleset was inspected on 2026-09-07. It requires
pull requests, resolved review threads, and the existing status checks, with no
bypass actors. It currently requires zero approving reviews and does not
require CODEOWNER review or approval of the latest push.

An administrator should require one approving review, approval of the latest
push, and CODEOWNER review for sensitive paths. Retain resolved-thread
enforcement, existing status checks, and no bypass actors. `.github/CODEOWNERS`
assigns sensitive paths to `@BrettKinny` and `@TheBobFella`, whose repository
write access was verified. An owner cannot approve their own PR; the other
owner must review sensitive changes. These
settings are recommendations; this change does not modify them. Keep existing
release-tag protection, immutable releases, and stable release environment
approval intact; the release automation does not need a main-branch bypass.

## Safe lifecycle deletion

Install and uninstall operations consume the persisted Install identity.
Expand Down
70 changes: 70 additions & 0 deletions docs/adr/0010-isolate-agent-execution-from-the-box.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Isolate agent execution from the trusted Box

## Decision

`sqrbx-agent` is a Linux host workflow, independent of the normal Box lifecycle,
Managed home, Selection, and runtime options. Pi and the small host execution
adapter belong to the trusted computing base. Model-generated tool requests,
project instructions, dependencies, and all guest processes are untrusted.
A compromised host harness is outside this boundary. The chosen model provider
is an authorized destination for source code and tool results.

Each session starts from committed `HEAD` in an independent Git repository.
It does not share writable Git objects, refs, configuration, or worktree
administration with the source. This replaces the initial linked-worktree
proposal: a linked worktree requires access to common repository metadata,
which is incompatible with protecting that metadata from hostile commands.
Uncommitted and ignored source files are not copied. Session files remain until
explicit discard; the execution environment and guest home are disposable.

Host-owned session identity and reporting state live outside the writable guest
workspace. Paths used for cleanup are derived from validated identity, never
from guest-written paths or Git configuration. Host reports compare against a
trusted baseline and must not execute guest Git hooks, filters, or diff helpers.
Review and import into the original checkout remain explicit human operations.

The first backend is local rootless Podman, explicitly selected with
`--backend podman`. It uses an unprivileged user, all capabilities dropped,
no-new-privileges, a read-only root filesystem, disposable home, and private
SELinux workspace labeling. It bypasses the normal entrypoint because that
entrypoint refreshes and reconciles trusted Box configuration. Normal Box
behavior is unchanged.

Images must already be acquired by immutable digest or local image ID. The
launcher can reuse the recorded Install identity's image, but does not discover
mutable tags or download tools automatically. Optional host Pi SDK dependencies
are installed explicitly from a committed npm lock with lifecycle scripts off.

Networking defaults to `none`. `open` requires an explicit launch option;
`development` is rejected until a backend can enforce a documented policy.
No restricted mode falls back to open networking, and no backend falls back to
a weaker boundary silently.

## Gondolin investigation

Gondolin's current SDK has host-controlled execution, VFS mounts, and HTTP
policy hooks. Its [OCI image builder](https://earendil-works.github.io/gondolin/custom-images/)
can export a digest-pinned Squarebox userspace, but still creates separate
Alpine-derived kernel/initramfs and downloads versioned guest helpers. A
Squarebox OCI digest therefore does not identify the complete guest boot chain.

Gondolin is reserved and fails with an actionable error in this milestone.
Shipping it requires verification and versioning of all boot assets, auditing
the host filesystem provider against escaping links and concurrent mutation,
and live VM/network escape tests. The neutral `exec` backend interface is the
integration point. A nominal wrapper around an upstream example would not be
sufficient evidence of the promised boundary.

## Consequences

Agent mode requires its own host prerequisites and tests; normal installation
does not install host packages or change existing release verification. Linux
is the initial supported host; native Windows, Git Bash, macOS, remote Podman,
and nested invocation from a Box are not supported execution targets.

Disposable homes do not inherit toolchains installed in the Managed home.
Offline projects need dependencies already in the selected image or a separate,
explicit preparation step. CPU/memory/process limits reduce resource abuse;
the writable session directory is not a storage quota. Kernel/runtime flaws,
resource exhaustion, malicious generated changes, and execution after manually
importing those changes remain risks requiring review.
58 changes: 58 additions & 0 deletions docs/agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# `sqrbx-agent`

`sqrbx-agent` launches Pi against a disposable, hardened execution environment
for one repository. Linux rootless Podman is the first supported backend and
must be selected explicitly:

```bash
sqrbx-agent --backend podman .
sqrbx-agent --backend podman --network open ~/src/project
sqrbx-agent list
sqrbx-agent diff SESSION_ID
sqrbx-agent discard SESSION_ID
```

The default network is `none`. `development` is rejected because this backend
cannot enforce a destination allowlist. `open` is an explicit opt-in that can
expose project data to the network. Pi runs on the host and may send source and
tool output to the selected model provider; guest networking is not required
for that model connection.

The provider and model are explicit host-side choices. For example:

```bash
sqrbx-agent --backend podman --provider openai --model gpt-5 .
```

With no `--prompt`, the command reads prompts from the terminal until EOF. A
single noninteractive turn can use `--prompt 'inspect and test the change'`.

Sessions start from committed `HEAD` in an independent repository. Dirty and
ignored files from the input checkout are not copied, and the original checkout
is never mounted or changed. Session repositories remain under the agent state
directory until `discard`; the guest container and its home are disposable.

The agent image must already be available locally under an immutable
`repository@sha256:...` reference or full local `sha256:` image ID. Without
`--image`, the command reads and validates the POSIX Squarebox Install identity.
It never pulls a mutable tag. Gondolin is reserved for a later milestone and
fails clearly rather than falling back to Podman.

The host Pi adapter disables ordinary Pi resource discovery and exposes one
backend-backed bash tool. It does not load project or global extensions,
settings, skills, prompts, credentials, or instruction files as host resources.
Use a dedicated Pi auth directory configured for this workflow; never mount
the normal Managed home, SSH files, GitHub CLI state, runtime sockets, or host
Git configuration. The root repository `AGENTS.md` is behavioral guidance only.

Install the exact host SDK into the private adapter directory before first use:

```bash
cd /path/to/squarebox/scripts/agent
npm ci --ignore-scripts --no-audit --no-fund
```

`diff` uses host-controlled Git state and disables hooks, filters, external diff,
text conversion, and fsmonitor. Review changes before importing them into a
normal checkout. Resource limits are defense in depth, not a storage quota or
absolute protection against host kernel/runtime flaws.
3 changes: 2 additions & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,7 @@ _shell_init_tmp="$(mktemp "${SHELL_INIT}.sqrbx.XXXXXX")"
printf '# squarebox-install-id=%s\n# Managed by squarebox from %q.\n' "$INSTALL_ID" "$STATE_FILE"
printf '_sq_install=%s\n_sq_runtime=%s\n_sq_container=%s\n_sq_install_id=%s\n' "$_q_install" "$_q_runtime" "$_q_container" "$_q_install_id"
cat <<'EOF'
unalias sqrbx squarebox sqrbx-rebuild squarebox-rebuild sqrbx-uninstall squarebox-uninstall 2>/dev/null || true
unalias sqrbx squarebox sqrbx-agent sqrbx-rebuild squarebox-rebuild sqrbx-uninstall squarebox-uninstall 2>/dev/null || true
_sq_rt() {
if [ -n "${MSYSTEM:-}" ]; then MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' "${_sq_runtime}" "$@"
else "${_sq_runtime}" "$@"
Expand All @@ -1045,6 +1045,7 @@ sqrbx() {
_sq_rt_interactive start -ai "${_sq_container}"
}
squarebox() { sqrbx "$@"; }
sqrbx-agent() { "${_sq_install}/scripts/sqrbx-agent" "$@"; }
sqrbx-rebuild() { "${_sq_install}/install.sh" "$@"; }
squarebox-rebuild() { sqrbx-rebuild "$@"; }
sqrbx-uninstall() { "${_sq_install}/uninstall.sh" "$@"; }
Expand Down
Loading