Preserve symlink paths in terminal sandbox policies#320172
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the terminal sandbox filesystem policy generation to preserve configured (and generated) symlink paths while also including their canonical realpath targets, addressing macOS Seatbelt’s path-based rule evaluation (Fixes #319866).
Changes:
- Change filesystem path resolution to emit both the expanded/original path and the canonical resolved target (when different), with deduplication.
- Update Linux sandbox config tests to verify both the symlink path and resolved target are written for allow/deny read/write paths (including command-runtime paths).
- Update Windows MXC sandbox config tests to verify both the symlink path and resolved target are emitted in MXC filesystem path lists.
Show a summary per file
| File | Description |
|---|---|
| src/vs/platform/sandbox/common/terminalSandboxEngine.ts | Adjusts filesystem path resolution to preserve symlink paths while also adding canonical targets; dedupes combined results. |
| src/vs/platform/sandbox/test/common/terminalSandboxEngine.test.ts | Updates Linux + Windows MXC tests to assert both symlink paths and resolved targets appear in generated configs. |
Copilot's findings
Comments suppressed due to low confidence (1)
src/vs/platform/sandbox/test/common/terminalSandboxEngine.test.ts:303
- The new symlink-preservation behavior is most critical for the macOS Seatbelt scenario described in the PR/issue, but the updated tests only exercise the Linux and Windows MXC branches. Adding at least one macOS-targeted unit test (host getOS=OperatingSystem.Macintosh + AgentSandboxMacFileSystem setting + realpath mapping) would prevent regressions in the exact codepath this change is meant to fix.
test('preserves filesystem symlink paths and resolves their targets on Linux when writing the config', async () => {
setSandboxSetting(AgentSandboxSettingId.AgentSandboxLinuxFileSystem, {
allowRead: ['~/read-link'],
allowWrite: ['/write-link'],
denyRead: ['~/deny-read-link'],
denyWrite: ['/deny-write-link'],
});
fileService.setRealpath('/workspace-link', '/real/workspace');
- Files reviewed: 2/2 changed files
- Comments generated: 0
TylerLeonhardt
approved these changes
Jun 5, 2026
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.
Fixes #319866
Summary
On macOS, Seatbelt evaluates filesystem rules against the path passed to the syscall. The terminal sandbox previously replaced configured symlink paths with their canonical targets when generating filesystem policies. As a result, an explicitly allowed symlink path could still be denied even though its target appeared in
allowRead.This change:
realpathtarget when it differs from the original pathValidation
npm run compile-check-ts-nativenpm run transpile-clientThe focused
TerminalSandboxEnginesuite could not be executed in the current environment: the Electron runner has no X server, and the headless Node runner requires Node 24 while the terminal sandbox exposes Node 22.