Skip to content

feat(zed): add a zed permissions override for sandbox_permissions and profiles - #2643

Merged
dyoshikawa merged 3 commits into
mainfrom
resolve-issue-2415-zed-permissions-override
Aug 8, 2026
Merged

feat(zed): add a zed permissions override for sandbox_permissions and profiles#2643
dyoshikawa merged 3 commits into
mainfrom
resolve-issue-2415-zed-permissions-override

Conversation

@dyoshikawa

Copy link
Copy Markdown
Owner

Part of #2415 (gap 5 sandbox_permissions + profiles passthrough per the 2026-08-06 comment).

Background

Zed 1.14.2 (2026-08-05) turned OS-level agent sandboxing on by default for the terminal and fetch tools. The defaults forbid network access, writing outside the project directories, and writing to .git, so a realistic setup now has to relax at least one of network_hosts, allow_all_hosts, write_paths, allow_fs_write_all or allow_unsandboxed under agent.sandbox_permissions. None of that was expressible from .rulesync/permissions.jsonc: zed was still bound to the generic CanonicalPermissionsOverrideSchema.

agent.profiles had the same problem from the other direction. Profiles decide which tools exist in a thread — a separate enforcement stage from tool_permissions, since a tool absent from the active profile cannot be used no matter what the permission rules say. #2033 looked at profiles as a subagents surface and was closed; the permissions angle was never covered.

What changed

A new ZedPermissionsOverrideSchema in src/types/permissions.ts carries the generic tool-scoped permission surface plus two verbatim passthrough blocks, and zed moves off the generic schema onto it:

  • sandbox_permissions — a bare looseObject, written straight into agent.sandbox_permissions, mirroring the Kilo / Claude Code / Codex CLI sandbox passthrough precedent. The keys are documented rather than enumerated, since upstream adds to them release over release.
  • profiles — keyed by profile id, with name / tools / enable_all_context_servers / context_servers / default_model typed but loose, like Kimi Code's tools.enabled/disabled block. No canonicalization is attempted.

zed-permissions.ts writes both through the existing shared-config gateway path (the permissions feature already owns the whole agent key at all three Zed settings paths) and lifts both back into the zed override on import, so a hand-written sandbox policy or profile set round-trips instead of being lost on the next generate.

Fail-closed guard

The override cannot reach past its own surface: buildZedOverridePatch reads the two keys by name rather than spreading the override object, so an unlisted key is inert. agent.tool_permissions is called out explicitly and ignored with a warning rather than silently, since it is the canonical permission block's surface end to end — the analogue of Kiro's read/write/grep/glob rejection. A test asserts a canonical deny survives an override that tries to set tool_permissions.default = "allow".

A key the override supplies replaces the existing block wholesale (Zed reads each as one policy unit, so a deep merge would leave half of a rewritten sandbox policy behind); a key it omits leaves whatever is in settings.json alone rather than deleting it.

Tests

zed-permissions.test.ts covers the verbatim write, round-trips in both project and global scope (the global dir is platform-branched), the omitted-override import, wholesale-replace vs. preserve, and the tool_permissions rejection. src/e2e/e2e-permissions.spec.ts gains an end-to-end generate case. Docs note added to the Zed permissions section of docs/reference/file-formats.md, with docs-content regenerated.

pnpm cicheck green; npx vitest run --config vitest.e2e.config.ts src/e2e/e2e-permissions.spec.ts green (81 tests).

The issue stays open — the remaining Zed gaps are untouched here.

🤖 Generated with Claude Code

… profiles

Zed 1.14.2 turns OS-level agent sandboxing on by default for the terminal
and fetch tools, so most setups now need to relax agent.sandbox_permissions
- none of which was authorable from .rulesync/permissions.jsonc, since zed
was bound to the generic override schema. agent.profiles, the separate
tool-availability layer, was equally out of reach.

Both are now verbatim passthrough blocks on a new ZedPermissionsOverride
schema, written into agent and lifted back out on import. The translator
reads only those two keys by name, and warns on a tool_permissions key, so
an override can never weaken a canonical deny.
The allowlist made an unsupported or misspelled key inert, but silently -
so `zed.sandboxPermissions` looked like it worked. Report every key the
patch does not consume, and document why the block is an allowlist rather
than a verbatim agent merge: `agent.always_allow_tool_actions` would
disarm every permission rule at once if the override could reach it.

Also record the scope rationale in the docs. Zed layers user settings
under project settings and applies a project's .zed/settings.json once the
worktree is trusted, so both scopes are written - and a project-scoped
allow_unsandboxed is a real grant, which is worth saying out loud.
agent.sandbox_permissions is not only hand-written: Zed saves an
always-allow clicked in the sandbox prompt there. So an import can pick up
an ad-hoc grant from one machine and a later generate ships it to the
whole team via the project file. Say so, along with the mirror case where
regenerating discards approvals Zed recorded after the override was
authored.
@dyoshikawa
dyoshikawa merged commit 5caa9cd into main Aug 8, 2026
9 checks passed
@dyoshikawa
dyoshikawa deleted the resolve-issue-2415-zed-permissions-override branch August 8, 2026 22:31
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.

2 participants