Skip to content

fix(jail): expose the opencode install root inside the fs-jail - #164

Merged
drewstone merged 1 commit into
mainfrom
fix/jail-expose-cli-binary
Aug 14, 2026
Merged

fix(jail): expose the opencode install root inside the fs-jail#164
drewstone merged 1 commit into
mainfrom
fix/jail-expose-cli-binary

Conversation

@drewstone

Copy link
Copy Markdown
Owner

What was wrong

opencode installs itself under $HOME (~/.opencode/bin/opencode). An fs-jail deliberately excludes /home. A jailed opencode run therefore exits 127 on a binary that exists:

opencode exited 127: timeout: failed to run command
'/home/<user>/.opencode/bin/opencode': No such file or directory

toolchainReadPaths already tries to expose the CLI's install root, but it only reaches it when the on-PATH entry realpaths into it. An operator whose opencode is a symlink to a wrapper script elsewhere realpaths to the wrapper's directory, so the install root stays hidden.

BRIDGE_JAIL_RO_PATHS can paper over this, but only after the operator has diagnosed a 127 that names a file which is plainly present.

Why the backend should declare it

The install root is a fixed property of this harness, exactly like the MCP config dir the claude backend registers. Leaving it to per-operator config makes every new machine rediscover the same 127.

Impact measured here

12 consecutive opencode runs failed this way. The seat was recorded as an unusable harness with a "capability gap" — two conclusions that were both wrong. With the path exposed, the same AgentProfile completes normally (finish_reason: stop).

Verification

New test tests/opencode-jail-binary.test.ts, three cases: install root exposed under readConfine; OPENCODE_INSTALL_DIR honoured when the install moved; nothing registered when reads are not confined.

Fails without the fix, passes with it:

without: AssertionError: expected [ '/tmp/cli-bridge-opencode-q87kDN' ]
         to include '/home/drew/.opencode'
with:    Tests  3 passed (3)

Full suite:

Step Result
typecheck clean
test 823 passed / 8 skipped, 0 failed (47 files)

One thing worth knowing

A fresh pnpm install --frozen-lockfile in a worktree leaves better-sqlite3 unbuilt, and the suite then reports 119 failures across 15 files that are pure environment. pnpm rebuild better-sqlite3 clears all of them. Anyone baselining this repo should run that first or they will chase phantom regressions.

🤖 Generated with Claude Code

opencode installs itself under $HOME, and an fs-jail deliberately hides /home. A
jailed opencode run therefore exits 127 on a binary that exists:

  opencode exited 127: timeout: failed to run command
  '/home/<user>/.opencode/bin/opencode': No such file or directory

`toolchainReadPaths` reaches the install root only when the on-PATH entry
realpaths into it. An operator whose `opencode` is a wrapper script elsewhere
realpaths to the wrapper's own directory, so the install root stays hidden.

The install root is a fixed property of this harness, so the backend declares it.
`OPENCODE_INSTALL_DIR` is honoured for a moved install. `registerJailReadable`
stays a no-op when reads are not confined.

Measured: 12 consecutive opencode runs failed this way and the seat was recorded
as an unusable harness. With the path exposed the same profile completes.
@drewstone
drewstone merged commit 0076bfe into main Aug 14, 2026
1 check passed
@drewstone
drewstone deleted the fix/jail-expose-cli-binary branch August 14, 2026 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant