potiuk opened a new pull request, #198: URL: https://github.com/apache/airflow-steward/pull/198
## Summary Fixes [#197](https://github.com/apache/airflow-steward/issues/197) — the harness pre-resolves `sandbox.filesystem.allowRead: ["."]` at session start and silently drops the literal, so reads under CWD fall through to the broad `denyRead: ["~/"]` and fail under the sandbox. The defensive measure: add the project root as an explicit absolute path to both `allowRead` and `allowWrite` in the adopter's **project-local** `<repo>/.claude/settings.local.json` (gitignored, per-machine, per-project). The `.` entry stays in the committed project-scope `settings.json`. The fix is also wired so that **worktrees inherit access automatically** — each worktree carries its own `<worktree>/.claude/settings.local.json` entry, both for worktrees that already exist when the fix runs and for worktrees added later via `git worktree add`. ### Scope choice — project-local, not user-scope | Scope | File | Suitable? | |---|---|---| | User | `~/.claude/settings.json` | No — pollutes user-scope with every adopter project's abs path. | | Project (committed) | `<repo>/.claude/settings.json` | No — machine-specific abs paths would leak into the repo. | | Project (local, gitignored) | `<repo>/.claude/settings.local.json` | Yes — per-machine, per-project, never committed. | The helper writes only to the project-local file. User-scope and committed project-scope are never touched. ### What landed - **New helper** `tools/agent-isolation/sandbox-add-project-root.sh` (executable, Apache 2.0). With `--all-worktrees`, enumerates `git worktree list --porcelain` and writes each worktree's path into **that worktree's own** `.claude/settings.local.json`. Without the flag (post-checkout hook mode), writes only the current worktree's path. Creates the target file if missing; updates atomically (`jq` → tmp → `mv`); idempotent. - **`setup-isolated-setup-install`** — new Step P that installs the script under `~/.claude/scripts/` (the *file* lives user-scope; what it *writes* is project-local) and runs it once with `--all-worktrees` against the adopter repo. - **`setup-isolated-setup-verify`** — new Check 8: live read+write probe of the current worktree's project root, plus a static cross-check that the abs path is in the current worktree's `.claude/settings.local.json`. - **`/setup-steward adopt`** Step 12 pass 3 — runs the helper with `--all-worktrees` after the worktree-init propagation. Step 10 post-checkout hook content extends to chain into the helper. Step 7 gitignore gains `/.claude/settings.local.json` (most adopters already gitignore it by Claude Code convention; the adopt flow checks and adds the line if missing). - **`/setup-steward upgrade`** Step 6c — after the per-worktree `worktree-init` loop, the helper runs with `--all-worktrees`. - **`/setup-steward worktree-init`** new Step 1c — invokes the helper for just this worktree's root. - **`/setup-steward verify`** new Check 8b — static cross-check that the current worktree's abs path is in its own `.claude/settings.local.json`. Scopes to the current worktree only, since each worktree carries its own per-machine settings file. - **`docs/setup/secure-agent-setup.md`** — new section *Project-root coverage in the sandbox allowlists* (harness behaviour, scope rationale, helper surface, four invocation points). - **`tools/agent-isolation/README.md`** — table row for the new helper. ### Testing Dry-run on this repo: 4 worktrees, each one gets its own absolute path written to its own `<worktree>/.claude/settings.local.json` (one worktree had no existing file — helper creates it from scratch with only the sandbox.filesystem block). Idempotent — second run produces no diff. ## Test plan - [ ] On a fresh adopter clone with the secure setup already installed, run `/setup-steward` and confirm the project root lands in `<repo>/.claude/settings.local.json`'s `sandbox.filesystem.allowRead`/`allowWrite`. - [ ] On an adopted repo, `git worktree add ../foo feature-x`; confirm the post-checkout hook fires in the new worktree and the path lands in `<new-worktree>/.claude/settings.local.json` (not in the main's). - [ ] On a multi-worktree adopted repo, run `/setup-steward upgrade` and confirm each worktree's `settings.local.json` carries its own path. - [ ] Run `setup-isolated-setup-verify` on a stale session whose project root is not yet in the local settings; confirm Check 8's live probe surfaces ✗ and remediation pointer fires. - [ ] Run the helper with `--dry-run --all-worktrees` and verify the diff matches expectations without writing. - [ ] Run the helper twice in a row — second run should be a no-op (no diff output, exit 0). - [ ] Run the helper from a directory that has no `.claude/` yet — confirm it creates `.claude/settings.local.json` from scratch with only the `sandbox.filesystem` block. - [ ] Confirm user-scope `~/.claude/settings.json` is **never** touched by the helper, even when running with `--all-worktrees`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
