Skip to content

fix(agent/agentcontext): canonicalize scan root in symlink boundary check#26175

Open
kylecarbs wants to merge 1 commit into
mainfrom
fix/agentcontext-macos-canonicalization
Open

fix(agent/agentcontext): canonicalize scan root in symlink boundary check#26175
kylecarbs wants to merge 1 commit into
mainfrom
fix/agentcontext-macos-canonicalization

Conversation

@kylecarbs

@kylecarbs kylecarbs commented Jun 9, 2026

Copy link
Copy Markdown
Member

Summary

Fixes coder/internal#1574: macOS test flakes in agent/agentcontext caused by /var being a symlink to /private/var.

Root cause

On macOS, t.TempDir() returns paths under /var/folders/... while filepath.EvalSymlinks (and the package's CanonicalizePath) resolves them to /private/var/folders/.... Two distinct symptoms followed:

  1. Production bug in resolveReadTarget (caused TestResolver_SymlinkInsideScanRootAllowed). The symlink boundary check resolved the target via EvalSymlinks but only filepath.Cleaned the scan root, so a /private/var/.../target was rejected as escaping a /var/.../scanRoot. This is a real production hazard: the working directory provided to the Manager is not canonicalized before being added to scan roots, so a workspace mounted under a symlinked prefix would have legitimate in-root symlinks rejected as StatusInvalid.
  2. Test-only path mismatch (caused the rest). Tests compared the raw t.TempDir() against paths returned by Manager.AddSource, Manager.HasSource, Manager.Sources, Manager.Snapshot, and the HTTP API, all of which return canonical paths.

Fix

  • resolveReadTarget now applies filepath.EvalSymlinks to the scan root before the prefix check, symmetrically with the target. Escaping targets are still rejected. This mirrors the same lenient EvalSymlinks pattern already used in agent/agentgit/agentgit.go and agent/x/agentmcp/configwatcher.go.
  • Tests now use the existing testutil.TempDirResolved(t) helper (already used by agentmcp and agentgit tests for exactly this macOS issue) for temp dirs whose paths are compared against Manager/API outputs.

The pre-existing security tests (TestResolver_SymlinkOutsideScanRootRejected, TestValidateSourcePath_RejectsOutsideRoot, etc.) still pass, so the symlink boundary remains enforced.

Verification

Reproduced the macOS failure on Linux by constructing a temp tree where the scan root is reached through a synthetic symlinked prefix (mimicking /var -> /private/var). With only the production fix applied, the resolver case passes. With the test-side fixes applied, all previously-failing tests in the issue pass under go test ./agent/agentcontext -count=5 and go test -race ./agent/agentcontext -count=2.

Failing tests covered
  • TestResolver_SymlinkInsideScanRootAllowed
  • TestManager_HasSource
  • TestManager_SeedSourcesLateBindsAfterManifest
  • TestManager_InitialSourcesSeeded
  • TestManager_AddSourceTriggersResolve
  • TestValidateSourcePath_AllowsInsideRoot
  • TestAPI_GetAndDeleteSource
  • TestAPI_AddAndListSource

Authored by Coder Agents on behalf of @kylecarbs.

@kylecarbs kylecarbs force-pushed the fix/agentcontext-macos-canonicalization branch from 2509213 to d9ed34c Compare June 9, 2026 18:15
…heck

On macOS, /var is a symlink to /private/var, so filepath.EvalSymlinks
on a symlink target inside a scan root produces a /private/var path
even when the caller's scanRoot is still /var/.... The boundary check
in resolveReadTarget compared the canonical target against an
un-canonical scan root and rejected legitimate in-root symlinks as
StatusInvalid. This matches the lenient EvalSymlinks pattern already
used in agentgit and agentmcp.

Canonicalize scanRoot symmetrically with the target before the
prefix check so symlinks inside the scan root are accepted while
escaping targets are still rejected.

Fixes the macOS test flakes in agent/agentcontext where t.TempDir()
returns /var/folders/... paths that diverge from the canonical form
the Manager and API surface. The affected tests now pin to the
canonical temp dir via testutil.TempDirResolved, the same helper
already used in agentmcp and agentgit.
@kylecarbs kylecarbs force-pushed the fix/agentcontext-macos-canonicalization branch from d9ed34c to 2c3b78e Compare June 9, 2026 18:16
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.

flake: agentcontext path canonicalization on macOS (multiple tests)

2 participants