Add granular per-path write permissions for the agent terminal sandbox - #57972
Merged
Conversation
MartinYe1234
marked this pull request as ready for review
May 28, 2026 18:38
Co-authored-by: Anant Goel <anantdgoel@gmail.com>
…-granular-permissions-for-sandbox Co-authored-by: Anant Goel <anantdgoel@gmail.com>
anantdgoel
self-requested a review
June 1, 2026 22:28
anantdgoel
approved these changes
Jun 1, 2026
…ons-for-sandbox # Conflicts: # crates/agent/src/thread.rs
rtfeldman
approved these changes
Jun 2, 2026
TomPlanche
pushed a commit
to TomPlanche/zed
that referenced
this pull request
Jun 2, 2026
zed-industries#57972) Adds granular, per-path write permissions to the agent's sandboxed `terminal` tool. Previously a command could only request unrestricted filesystem writes (`allow_fs_write: true`) as an all-or-nothing escape hatch. Now the model can request write access to specific paths via `fs_write_paths`, and each granted directory covers its whole subtree. The broad escape hatch is still available as `allow_fs_write_all: true` for cases where the paths can't be enumerated up front. Approval prompts now let the user grant a write request either just for that command or for the rest of the conversation. Conversation grants are tracked in memory (never persisted) using pure subtree containment, so later commands writing under an already-granted path run without prompting again. Closes AI-335 Release Notes: - Improved the agent's terminal sandbox so commands can request write access to specific paths instead of all-or-nothing filesystem access, with the option to grant access for a single command or the rest of the conversation. --------- Co-authored-by: Anant Goel <anantdgoel@gmail.com> Co-authored-by: Richard Feldman <oss@rtfeldman.com>
MasoudAlali
pushed a commit
to MasoudAlali/zed
that referenced
this pull request
Jun 2, 2026
Follow-up hardening on top of zed-industries#57972 (granular sandbox write permissions), based on a review of that branch. The most important fix is that model-requested `fs_write_paths` were joined but never normalized, so a path containing `..` could pass the lexical subtree-containment checks while seatbelt canonicalized it to somewhere else entirely — causing skipped approval prompts and silent runtime write denials. Write paths are now lexically normalized (via `util::paths::normalize_lexically`) at the point they enter the system, both for model requests and for hand-edited persistent grants, so the containment check, the approval prompt, and the enforced sandbox policy all operate on the same path. The subtree insert/prune and containment logic had drifted into roughly five near-identical copies across `agent`, `agent_settings`, and `settings_content`; these now share `util::paths::insert_subtree` and `path_within_subtree`. The dead `SandboxPermissions::covers` (only ever exercised by its own tests, duplicating the production `covers_with_persistent`) is removed, and its tests rewritten to cover the real settings-compilation path including `..` normalization. The remaining changes reduce brittleness: the sandbox permission option ids (`allow`, `allow_thread`, `allow_always`, `deny`) are now shared constants in `acp_thread` instead of bare string literals scattered across the agent and UI, `persist_sandbox_always_permission` logs instead of silently doing nothing when no filesystem is available, and a comment documents why replay always resolves the terminal tool to the non-sandboxed variant. Release Notes: - N/A --------- Co-authored-by: Martin Ye <martin@zed.dev> Co-authored-by: MartinYe1234 <52641447+MartinYe1234@users.noreply.github.com>
dandv
pushed a commit
to dandv/zed
that referenced
this pull request
Jun 3, 2026
Follow-up hardening on top of zed-industries#57972 (granular sandbox write permissions), based on a review of that branch. The most important fix is that model-requested `fs_write_paths` were joined but never normalized, so a path containing `..` could pass the lexical subtree-containment checks while seatbelt canonicalized it to somewhere else entirely — causing skipped approval prompts and silent runtime write denials. Write paths are now lexically normalized (via `util::paths::normalize_lexically`) at the point they enter the system, both for model requests and for hand-edited persistent grants, so the containment check, the approval prompt, and the enforced sandbox policy all operate on the same path. The subtree insert/prune and containment logic had drifted into roughly five near-identical copies across `agent`, `agent_settings`, and `settings_content`; these now share `util::paths::insert_subtree` and `path_within_subtree`. The dead `SandboxPermissions::covers` (only ever exercised by its own tests, duplicating the production `covers_with_persistent`) is removed, and its tests rewritten to cover the real settings-compilation path including `..` normalization. The remaining changes reduce brittleness: the sandbox permission option ids (`allow`, `allow_thread`, `allow_always`, `deny`) are now shared constants in `acp_thread` instead of bare string literals scattered across the agent and UI, `persist_sandbox_always_permission` logs instead of silently doing nothing when no filesystem is available, and a comment documents why replay always resolves the terminal tool to the non-sandboxed variant. Release Notes: - N/A --------- Co-authored-by: Martin Ye <martin@zed.dev> Co-authored-by: MartinYe1234 <52641447+MartinYe1234@users.noreply.github.com>
TomPlanche
pushed a commit
to TomPlanche/zed
that referenced
this pull request
Jun 8, 2026
Follow-up hardening on top of zed-industries#57972 (granular sandbox write permissions), based on a review of that branch. The most important fix is that model-requested `fs_write_paths` were joined but never normalized, so a path containing `..` could pass the lexical subtree-containment checks while seatbelt canonicalized it to somewhere else entirely — causing skipped approval prompts and silent runtime write denials. Write paths are now lexically normalized (via `util::paths::normalize_lexically`) at the point they enter the system, both for model requests and for hand-edited persistent grants, so the containment check, the approval prompt, and the enforced sandbox policy all operate on the same path. The subtree insert/prune and containment logic had drifted into roughly five near-identical copies across `agent`, `agent_settings`, and `settings_content`; these now share `util::paths::insert_subtree` and `path_within_subtree`. The dead `SandboxPermissions::covers` (only ever exercised by its own tests, duplicating the production `covers_with_persistent`) is removed, and its tests rewritten to cover the real settings-compilation path including `..` normalization. The remaining changes reduce brittleness: the sandbox permission option ids (`allow`, `allow_thread`, `allow_always`, `deny`) are now shared constants in `acp_thread` instead of bare string literals scattered across the agent and UI, `persist_sandbox_always_permission` logs instead of silently doing nothing when no filesystem is available, and a comment documents why replay always resolves the terminal tool to the non-sandboxed variant. Release Notes: - N/A --------- Co-authored-by: Martin Ye <martin@zed.dev> Co-authored-by: MartinYe1234 <52641447+MartinYe1234@users.noreply.github.com>
This was referenced Jun 10, 2026
This was referenced Jun 18, 2026
Closed
This was referenced Jul 1, 2026
This was referenced Jul 10, 2026
jonx
pushed a commit
to jonx/zed-aros
that referenced
this pull request
Jul 17, 2026
zed-industries#57972) Adds granular, per-path write permissions to the agent's sandboxed `terminal` tool. Previously a command could only request unrestricted filesystem writes (`allow_fs_write: true`) as an all-or-nothing escape hatch. Now the model can request write access to specific paths via `fs_write_paths`, and each granted directory covers its whole subtree. The broad escape hatch is still available as `allow_fs_write_all: true` for cases where the paths can't be enumerated up front. Approval prompts now let the user grant a write request either just for that command or for the rest of the conversation. Conversation grants are tracked in memory (never persisted) using pure subtree containment, so later commands writing under an already-granted path run without prompting again. Closes AI-335 Release Notes: - Improved the agent's terminal sandbox so commands can request write access to specific paths instead of all-or-nothing filesystem access, with the option to grant access for a single command or the rest of the conversation. --------- Co-authored-by: Anant Goel <anantdgoel@gmail.com> Co-authored-by: Richard Feldman <oss@rtfeldman.com>
jonx
pushed a commit
to jonx/zed-aros
that referenced
this pull request
Jul 17, 2026
Follow-up hardening on top of zed-industries#57972 (granular sandbox write permissions), based on a review of that branch. The most important fix is that model-requested `fs_write_paths` were joined but never normalized, so a path containing `..` could pass the lexical subtree-containment checks while seatbelt canonicalized it to somewhere else entirely — causing skipped approval prompts and silent runtime write denials. Write paths are now lexically normalized (via `util::paths::normalize_lexically`) at the point they enter the system, both for model requests and for hand-edited persistent grants, so the containment check, the approval prompt, and the enforced sandbox policy all operate on the same path. The subtree insert/prune and containment logic had drifted into roughly five near-identical copies across `agent`, `agent_settings`, and `settings_content`; these now share `util::paths::insert_subtree` and `path_within_subtree`. The dead `SandboxPermissions::covers` (only ever exercised by its own tests, duplicating the production `covers_with_persistent`) is removed, and its tests rewritten to cover the real settings-compilation path including `..` normalization. The remaining changes reduce brittleness: the sandbox permission option ids (`allow`, `allow_thread`, `allow_always`, `deny`) are now shared constants in `acp_thread` instead of bare string literals scattered across the agent and UI, `persist_sandbox_always_permission` logs instead of silently doing nothing when no filesystem is available, and a comment documents why replay always resolves the terminal tool to the non-sandboxed variant. Release Notes: - N/A --------- Co-authored-by: Martin Ye <martin@zed.dev> Co-authored-by: MartinYe1234 <52641447+MartinYe1234@users.noreply.github.com>
jolutz
pushed a commit
to jolutz/zed
that referenced
this pull request
Aug 8, 2026
zed-industries#57972) Adds granular, per-path write permissions to the agent's sandboxed `terminal` tool. Previously a command could only request unrestricted filesystem writes (`allow_fs_write: true`) as an all-or-nothing escape hatch. Now the model can request write access to specific paths via `fs_write_paths`, and each granted directory covers its whole subtree. The broad escape hatch is still available as `allow_fs_write_all: true` for cases where the paths can't be enumerated up front. Approval prompts now let the user grant a write request either just for that command or for the rest of the conversation. Conversation grants are tracked in memory (never persisted) using pure subtree containment, so later commands writing under an already-granted path run without prompting again. Closes AI-335 Release Notes: - Improved the agent's terminal sandbox so commands can request write access to specific paths instead of all-or-nothing filesystem access, with the option to grant access for a single command or the rest of the conversation. --------- Co-authored-by: Anant Goel <anantdgoel@gmail.com> Co-authored-by: Richard Feldman <oss@rtfeldman.com>
jolutz
pushed a commit
to jolutz/zed
that referenced
this pull request
Aug 8, 2026
Follow-up hardening on top of zed-industries#57972 (granular sandbox write permissions), based on a review of that branch. The most important fix is that model-requested `fs_write_paths` were joined but never normalized, so a path containing `..` could pass the lexical subtree-containment checks while seatbelt canonicalized it to somewhere else entirely — causing skipped approval prompts and silent runtime write denials. Write paths are now lexically normalized (via `util::paths::normalize_lexically`) at the point they enter the system, both for model requests and for hand-edited persistent grants, so the containment check, the approval prompt, and the enforced sandbox policy all operate on the same path. The subtree insert/prune and containment logic had drifted into roughly five near-identical copies across `agent`, `agent_settings`, and `settings_content`; these now share `util::paths::insert_subtree` and `path_within_subtree`. The dead `SandboxPermissions::covers` (only ever exercised by its own tests, duplicating the production `covers_with_persistent`) is removed, and its tests rewritten to cover the real settings-compilation path including `..` normalization. The remaining changes reduce brittleness: the sandbox permission option ids (`allow`, `allow_thread`, `allow_always`, `deny`) are now shared constants in `acp_thread` instead of bare string literals scattered across the agent and UI, `persist_sandbox_always_permission` logs instead of silently doing nothing when no filesystem is available, and a comment documents why replay always resolves the terminal tool to the non-sandboxed variant. Release Notes: - N/A --------- Co-authored-by: Martin Ye <martin@zed.dev> Co-authored-by: MartinYe1234 <52641447+MartinYe1234@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds granular, per-path write permissions to the agent's sandboxed
terminaltool.Previously a command could only request unrestricted filesystem writes (
allow_fs_write: true) as an all-or-nothing escape hatch. Now the model can request write access to specific paths viafs_write_paths, and each granted directory covers its whole subtree. The broad escape hatch is still available asallow_fs_write_all: truefor cases where the paths can't be enumerated up front.Approval prompts now let the user grant a write request either just for that command or for the rest of the conversation. Conversation grants are tracked in memory (never persisted) using pure subtree containment, so later commands writing under an already-granted path run without prompting again.
Closes AI-335
Release Notes: