Skip to content

fix(setup): fix the agent sandbox and give the agent more facts (6/7) - #899

Open
atornsii wants to merge 16 commits into
atorns/agent-5-opencode-handlerfrom
atorns/agent-6-run-fixes
Open

atornsii wants to merge 16 commits into
atorns/agent-5-opencode-handlerfrom
atorns/agent-6-run-fixes

Conversation

@atornsii

@atornsii atornsii commented Oct 20, 2026 •

Copy link
Copy Markdown

This fixes problems that the test runs found.

Sandbox (run 8)

  • Resolving a path reads the metadata of each parent folder. The sandbox denied it, so realpath, uv, and git failed with "Operation not permitted", and the agent fell back to pip. The parents of each open folder now allow metadata reads, but not their contents. This also covers folders under /private/tmp, for a project in a nested folder there.
  • ~/.local/share/uv is now writable, because uv writes there when it inspects a managed Python.
  • The sandbox now closes /private/tmp, where the agent found another program's files. Each run gets its own temporary folder there, which OpenCode gets as TMPDIR. Without the sandbox, OpenCode gets the system temporary folder as TMPDIR if the variable is not set.
  • The loopback proxy no longer writes "http: proxy error" lines into the wizard's screen.

Facts (runs 5, 7, and 8)

  • The facts message now gives the LaunchDarkly project and environment, and the names (never the values) of the model provider keys that are set in the environment or in the project's .env. ldcli reads those names itself, and it skips a key whose value is blank, also inside quotes.
  • The facts tell the agent not to look for keys, print the environment, or ask for a key, and to use $TMPDIR. Before, the agent spent about 25 tool calls finding the project, and it printed the environment or asked the user to paste a key.
  • The built-in prompt, which runs when the config cannot load, now has the same facts and rules.
  • ldcli setup agentcontrol takes --project and --environment for the same facts.

The project's .env files (runs 10 and 11)

In run 10, the agent read .env with OpenCode's read tool, so the values of the user's keys went to the model. The sandbox now denies reading and writing .env and .env.* in the project, in any subfolder. .env.example, .env.sample, and .env.template stay open. OpenCode's read and edit tools refuse the same files, and the facts tell the agent that they are closed. The profile escapes the project path in the rule, so a path with a double quote still gives a valid profile.

The agent therefore cannot run the app with the real keys, so the setup prompt must not ask it to. In run 11, the agent wrote the variable names only to .env.example, and it did not try to read .env.

Testing

  • Real sandbox tests check realpath in the project and in a nested folder under /private/tmp, a closed file in /private/tmp, and a writable run folder.
  • A real sandbox test with a project path that has a double quote checks that .env, .env.local, and a nested services/api/.env are closed, and that .env.example and other files stay open.
  • uv python find, realpath, git status, and OpenCode work in the sandbox in the test app.
  • Unit tests cover the provider key names, blank values, the facts in both prompts, and the OpenCode rules for .env files.

Diagram

flowchart TD
  subgraph facts [Facts for the agent]
    cmds["commands.go<br/>startAgent: project, environment"]:::chg
    cmdag["cmd/setup/agent.go<br/>agentTask with project, environment<br/>--project, --environment"]:::chg
    keys["provider_keys.go<br/>ProviderKeys, dotEnvNames"]:::new
    task["agent.go<br/>Task.ProjectKey, EnvironmentKey<br/>Task.ProviderKeys"]:::chg
    prompt["prompt.go<br/>BuildFacts: project, environment<br/>key names, TMPDIR note"]:::chg
    cmds -->|agentTask| cmdag
    cmdag -->|ProviderKeys| keys
    cmdag -->|fills Task| task
    prompt -->|reads Task| task
  end
  subgraph box [Sandbox and screen]
    srv["server.go<br/>TMPDIR = box.TempDir"]:::chg
    sb["sandbox.go<br/>parentFolders<br/>RunTemp, sharedTemp<br/>.local/share/uv writable"]:::chg
    proc[["opencode serve<br/>own TMPDIR"]]:::ext
    tmp[["/private/tmp<br/>closed, except the run folder"]]:::ext
    proxy["relay_proxy.go<br/>ErrorLog: discard"]:::chg
    srv -->|sandboxCommand| sb
    srv -->|sets TMPDIR| proc
    sb -.->|profile rules| tmp
  end
  classDef new fill:#e6f0fa,stroke:#1d6fb8,stroke-width:2px,color:#19202b
  classDef chg fill:#fbf1e1,stroke:#a86a12,stroke-width:2px,color:#19202b
  classDef earlier fill:#ffffff,stroke:#7a8494,stroke-dasharray:5 4,color:#19202b
  classDef ext fill:#eceefa,stroke:#4e5a9c,stroke-width:2px,color:#19202b
Loading

Blue boxes are new files, orange boxes are changed files, dashed boxes are files from an earlier PR, and purple boxes are outside ldcli. A solid arrow goes from the caller to the code that it calls. A dashed arrow shows data that moves without a direct call.

The facts group starts in the wizard. commands.go passes the selected project and environment to agentTask, which also calls ProviderKeys to get the names of the provider keys that are set. agentTask puts these values in the Task, and BuildFacts writes them into the first message. In the sandbox group, sandboxCommand now creates a run folder in /private/tmp and closes the rest of that folder. It returns the run folder as TempDir, and server.go gives it to OpenCode as TMPDIR. The profile also allows metadata reads on parent folders, so realpath, uv, and git work. relay_proxy.go stops writing proxy errors on the wizard screen.

The two groups do not depend on each other. The facts group changes the wizard from #895 and the prompt from #897. The sandbox group changes files from #896 and #897.

Stack

This is one of seven PRs for the ldcli setup agent. Review and merge them in order, after #877 (Go 1.26):

  1. feat(setup): add an OpenCode adapter for the setup agent (1/7) #894 OpenCode adapter
  2. feat(setup): add the setup agent step to the wizard (2/7) #895 Wizard agent step
  3. feat(setup): run the setup agent in a macOS sandbox (3/7) #896 macOS sandbox
  4. feat(setup): read the setup agent config through the gonfalon relay (4/7) #897 AI SDK and relay
  5. feat(setup): run the setup agent through the Go AI SDK with an OpenCode handler (5/7) #898 OpenCode handler
  6. fix(setup): fix the agent sandbox and give the agent more facts (6/7) #899 Run fixes
  7. feat(setup): send the agent's model calls to a LaunchDarkly Bedrock relay (7/7) #930 Bedrock model routing

The gonfalon side is launchdarkly/gonfalon#75196 to #75199 (the SDK relay) and launchdarkly/gonfalon#75426 (the model relay). This stack replaces #876 and #878, which are closed.

🤖 Generated with Claude Code


Note

Overview
Hardens the setup agent after test-run failures by tightening macOS sandboxing, blocking secret leakage from .env, and feeding the model safer context.

Sandbox: Parent directories of allowed paths now permit metadata-only reads so realpath, uv, and git work; ~/.local/share/uv is writable; shared /private/tmp is denied except a per-run folder passed as TMPDIR to OpenCode. Seatbelt regex rules deny read/write on project .env / .env.* while keeping .env.example (and similar) open. The relay proxy discards HTTP error logs so failures do not clutter the wizard UI.

Secrets & prompts: OpenCode read/edit permissions use ordered rules to deny .env files (same exceptions as the sandbox). New ProviderKeys reports only names of set model-provider env vars (from the process env and .env parsing, never values). Task and prompts/facts now include LaunchDarkly project/environment, provider key names, and shared setupRules (no key hunting, no running with real .env, use $TMPDIR). The wizard and setup agent CLI gain --project / --environment flags.

Tests: Coverage for env-file permissions, sandbox temp isolation, .env blocking, provider keys, and prompt/fact parity.

Reviewed by Cursor Bugbot for commit 42f2421. Bugbot is set up for automated code reviews on this repo. Configure here.

atornsii and others added 2 commits October 19, 2026 23:43
A test run found three problems with the macOS sandbox.

Resolving a path reads the metadata of every parent folder, and the
sandbox denied it. So realpath, uv, and git failed with "Operation not
permitted", and the agent fell back to pip and edited pyproject.toml by
hand. The parents of each open folder now allow metadata reads, but not
their contents.

uv writes to ~/.local/share/uv when it inspects a managed Python, and
the sandbox opened that folder read-only. It is now writable.

The agent searched /private/tmp and found another program's files
there. The sandbox now closes /private/tmp and gives the run its own
temporary folder in it, which OpenCode gets as TMPDIR.

The loopback proxy also wrote "http: proxy error" lines into the
wizard's screen. It now discards its log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In test runs, the agent spent about 25 tool calls finding the project
and environment that setup used, and it printed the environment or
asked the user to paste an API key to learn whether one was set.

The facts message now also gives the LaunchDarkly project and
environment, and the names of the model provider keys that are set in
the environment or in the project's .env. It never gives a value. It
tells the agent not to look for keys, print the environment, or ask for
a key, and to use $TMPDIR instead of /tmp.

`ldcli setup agent` takes --project and --environment for the same
facts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@atornsii
atornsii added this pull request to stack #902 October 20, 2026 15:48
@atornsii
atornsii marked this pull request as ready for review October 20, 2026 18:40
@atornsii
atornsii requested a review from a team as a code owner October 20, 2026 18:40
@atornsii
atornsii requested review from tiffanylphan and removed request for a team October 20, 2026 18:40
devin-ai-integration[bot]

This comment was marked as resolved.

…env keys

BuildPrompt now gives the project, the environment, the provider key names, and the same rules as BuildFacts. The agent gets these facts when the AI Config cannot load.

ProviderKeys now trims the value after it removes the quotes, so a quoted blank value does not count as a set key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

atornsii and others added 5 commits October 20, 2026 11:46
If the sandbox gives no run folder and TMPDIR is not set, ldcli now sets TMPDIR to the system temporary folder. The prompt tells the agent to use $TMPDIR on every platform.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… into atorns/agent-6-run-fixes

# Conflicts:
#	cmd/setup/agent_test.go
… into atorns/agent-6-run-fixes

# Conflicts:
#	internal/setup/agent/sandbox.go
… into atorns/agent-6-run-fixes

# Conflicts:
#	internal/setup/agent/sandbox.go
cursor[bot]

This comment was marked as resolved.

atornsii and others added 2 commits October 20, 2026 12:14
…y folder

parentFolders now also walks the folders between an open folder and /private/tmp. A project in a nested folder under /tmp can then use realpath, uv, and git in the sandbox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… into atorns/agent-6-run-fixes

# Conflicts:
#	internal/setup/agent/sandbox_test.go
The agent read .env in a test run, so the values of the user's keys went to the model. The sandbox now denies reading and writing .env and .env.* in the project, in any subfolder, and keeps .env.example, .env.sample, and .env.template open. OpenCode's read and edit tools refuse the same files, so the agent gets a clear refusal. The facts tell the agent that the files are closed and that it must write variable names in .env.example.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

The .env rule wrote the project path into a raw Seatbelt string, so a double quote in the path ended the string and the profile was invalid. The rule now uses an escaped profile string. The sandbox test now uses a project path with a double quote. The comment now uses active voice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cursor[bot]

This comment was marked as resolved.

@atornsii atornsii changed the title fix(setup): fix the agent sandbox and give the agent more facts (6/6) fix(setup): fix the agent sandbox and give the agent more facts (6/7) Oct 21, 2026
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