Skip to content

worktree: close ambient CARGO_TARGET_DIR gap for agent builds and CI - #217

Merged
getappz merged 5 commits into
masterfrom
task/139
Jul 17, 2026
Merged

worktree: close ambient CARGO_TARGET_DIR gap for agent builds and CI#217
getappz merged 5 commits into
masterfrom
task/139

Conversation

@getappz

@getappz getappz commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Summary

Test plan

  • cargo fmt --check
  • cargo build --workspace --verbose
  • cargo test --workspace --verbose (26/26 relevant tests pass locally on Windows; new Unix-gated regression test run_launch_env_strips_ambient_cargo_target_dir will run on CI's ubuntu/macos legs)
  • cargo clippy --locked --workspace --all-targets --all-features -- -D warnings -A unsafe_code -A clippy::pedantic
  • Validated .github/workflows/ci.yml YAML syntax

Summary by CodeRabbit

  • Bug Fixes

    • Prevented launched agents and headless runs from inheriting ambient CARGO_TARGET_DIR, ensuring per-worktree isolated build artifacts are used consistently.
  • Documentation

    • Documented how build artifact isolation works, the precedence rules for CARGO_TARGET_DIR, and the remaining bypass case when running cargo directly.
  • Tests

    • Added Unix-only checks that ambient CARGO_TARGET_DIR can’t leak to child processes, including when explicitly overridden.
  • Chores

    • Updated CI/tooling workflow pinning and added a CI guard that fails when CARGO_TARGET_DIR is set.

Per-worktree .cargo/config.toml isolation (item #133) never covered an
ambient CARGO_TARGET_DIR env var, since Cargo's precedence always lets the
env var override the config file. Strip CARGO_TARGET_DIR from the child env
of every agent launched via run_launch_env/run_headless (agent_launch.rs),
and add a CI job that fails the build if the var is ever set project-wide.
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e7ca1477-0e4b-4758-a352-8fa109802560

📥 Commits

Reviewing files that changed from the base of the PR and between 2b055f2 and bb19fcd.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • .github/workflows/ppa-publish.yml
  • src/agent_launch.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/ci.yml
  • src/agent_launch.rs

📝 Walkthrough

Walkthrough

The change prevents launched agents from inheriting CARGO_TARGET_DIR, adds Unix regression tests for ambient and override values, documents Cargo target isolation, adds a required CI guard, and updates pinned Rust toolchain action commits.

Changes

Cargo target directory isolation

Layer / File(s) Summary
Strip ambient target directory from agent launches
src/agent_launch.rs
Launch and headless execution paths remove CARGO_TARGET_DIR; Unix tests verify ambient values and explicit overrides are not inherited.
Document and enforce the isolation invariant
src/worktree.rs, AGENTS.md, .github/workflows/ci.yml
Documentation explains Cargo precedence and bypass behavior, while CI adds target-dir-guard to the required ci-green gate.
Update stable Rust action pins
.github/workflows/ci.yml, .github/workflows/ppa-publish.yml
Clippy, format, and publishing workflows use updated pinned commits for the stable Rust toolchain action.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AgentCommand
  participant run_launch_env
  participant ChildProcess
  AgentCommand->>run_launch_env: provide launch environment
  run_launch_env->>run_launch_env: remove CARGO_TARGET_DIR
  run_launch_env->>ChildProcess: start without CARGO_TARGET_DIR
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing ambient CARGO_TARGET_DIR leakage for worktree builds and CI.
Description check ✅ Passed The Summary and Test plan sections are complete and aligned with the template, with only Notes for reviewers omitted.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task/139

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 133-152: Update the target-dir-guard job’s “Fail if
CARGO_TARGET_DIR is set” step to also evaluate the GitHub Actions configuration
variable vars.CARGO_TARGET_DIR, mapping it into the step environment or
otherwise checking it explicitly. Preserve the existing failure behavior and
diagnostic for either the runner environment or vars.CARGO_TARGET_DIR being
non-empty.

In `@src/agent_launch.rs`:
- Around line 389-431: Protect the process-wide CARGO_TARGET_DIR mutation in
run_launch_env_strips_ambient_cargo_target_dir with the existing global
environment lock. Acquire the lock before set_var, keep it held through the
launch and assertion, and remove_var before releasing it so parallel tests
cannot observe or modify the temporary environment.
- Around line 81-90: The environment override loop in the agent launch command
can reintroduce CARGO_TARGET_DIR after it is removed. Update the command setup
around cmd.env_remove and the env loop so CARGO_TARGET_DIR remains unset after
applying overrides, then add a regression test covering an explicit
CARGO_TARGET_DIR override.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b0672984-8c69-4527-a6f6-29b833898a7a

📥 Commits

Reviewing files that changed from the base of the PR and between 2b58ffd and 2b055f2.

📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • AGENTS.md
  • src/agent_launch.rs
  • src/worktree.rs

Comment thread .github/workflows/ci.yml
Comment thread src/agent_launch.rs
Comment thread src/agent_launch.rs
Comment on lines +389 to +431
// Item #139: an ambient CARGO_TARGET_DIR must never reach the launched
// agent — Cargo's env var always outranks the worktree's isolated
// `.cargo/config.toml` (see `isolate_worktree_target_dir` in
// worktree.rs), so leaking it here would silently defeat that isolation
// for every build the agent runs. `env_remove` clones the current env
// and drops the key at that point, so this holds regardless of what any
// other test concurrently does to the ambient var.
#[cfg(unix)]
#[test]
fn run_launch_env_strips_ambient_cargo_target_dir() {
let marker = tempfile::NamedTempFile::new().unwrap();
let marker_path = marker.path().to_path_buf();
unsafe {
std::env::set_var("CARGO_TARGET_DIR", "/tmp/shared-target");
}
let reg = vec![AgentSpec {
id: Agent::Aider,
display_name: "aider",
tier: Tier::Cli,
binary_names: &["sh"],
version_args: &[],
package_manager: None,
package_name: None,
}];
let script = format!("echo -n \"$CARGO_TARGET_DIR\" > {}", marker_path.display());
run_launch_env(
&reg,
"aider",
None,
None,
&["-c".to_string(), script],
&[],
false,
);
unsafe {
std::env::remove_var("CARGO_TARGET_DIR");
}
let content = std::fs::read_to_string(&marker_path).unwrap();
assert_eq!(
content, "",
"child must not inherit ambient CARGO_TARGET_DIR"
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant region and nearby tests in src/agent_launch.rs
awk 'NR>=330 && NR<=470 { printf "%4d  %s\n", NR, $0 }' src/agent_launch.rs

echo
echo "---- env-related occurrences ----"
grep -nE 'set_var|remove_var|env_remove|env::var|CARGO_TARGET_DIR|serial|test.*env' -n src/agent_launch.rs || true

echo
echo "---- repo-wide serialization/env strategy hints ----"
grep -RInE 'serial_test|#[[:space:]]*serial|std::env::set_var|std::env::remove_var|CARGO_TARGET_DIR' . --exclude-dir=.git --exclude-dir=target | head -n 200

Repository: getappz/agentflare

Length of output: 13718


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- locks / serialization in tests ----"
grep -RInE 'GLOBAL_STATE_LOCK|Mutex<|lazy_static!.*Mutex|once_cell::sync::Lazy.*Mutex|serial_test|#[[:space:]]*serial' src crates --exclude-dir=target || true

echo
echo "---- nearby test helpers around env mutation ----"
awk 'NR>=1 && NR<=220 { printf "%4d  %s\n", NR, $0 }' src/paths.rs

echo
echo "---- AGENTS.md section mentioning CARGO_TARGET_DIR ----"
awk 'NR>=78 && NR<=110 { printf "%4d  %s\n", NR, $0 }' AGENTS.md

Repository: getappz/agentflare

Length of output: 8101


Serialize this env mutation in the test

This mutates process-wide CARGO_TARGET_DIR without the shared lock used elsewhere, so parallel cargo test runs can race. Guard the set_var/remove_var pair with the existing global env lock, or move the inheritance check into a subprocess.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/agent_launch.rs` around lines 389 - 431, Protect the process-wide
CARGO_TARGET_DIR mutation in run_launch_env_strips_ambient_cargo_target_dir with
the existing global environment lock. Acquire the lock before set_var, keep it
held through the launch and assertion, and remove_var before releasing it so
parallel tests cannot observe or modify the temporary environment.

getappz added 4 commits July 17, 2026 03:54
macOS's /bin/sh doesn't treat -n as a flag (that's a bash builtin
behavior), so echo -n printed the literal "-n" into the marker file
and failed the new CARGO_TARGET_DIR-stripping regression test on CI's
macos-latest runner.
dtolnay/rust-toolchain force-pushes its stable branch on every Rust
release rather than tagging, so a SHA pinned to it eventually falls
off the branch's history. zizmor's impostor-commit audit was flagging
the stale pin (pre-existing on master since 2026-07-07, unrelated to
this PR) as a supply-chain risk. Re-pinned all three occurrences
(ci.yml clippy/fmt jobs, ppa-publish.yml) to stable's current HEAD.
…reintroducing it, serialize env-mutating test
@getappz
getappz merged commit d79a7eb into master Jul 17, 2026
17 checks passed
@getappz
getappz deleted the task/139 branch July 17, 2026 12:41
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