Skip to content

fix(file): dedup symlink-cycle glob results and clarify symlink trust model - #1811

Merged
dyoshikawa merged 2 commits into
mainfrom
resolve-scrap-issue-1808-symlink-followups
Jun 10, 2026
Merged

fix(file): dedup symlink-cycle glob results and clarify symlink trust model#1811
dyoshikawa merged 2 commits into
mainfrom
resolve-scrap-issue-1808-symlink-followups

Conversation

@dyoshikawa

Copy link
Copy Markdown
Owner

Background

Issue #1808 consolidated the follow-up findings from the code and security reviews of PR #1802 (fix(file): follow symbolic links in findFilesByGlobs, resolving #1707). None blocked that PR, but they were tracked so they would not be lost. Each was re-validated against the current code before this fix.

Changes

  • fix: Update pnpm version to 10.12.2 in CI and release workflows #1 (mid) — circular symlink duplication. findFilesByGlobs now deduplicates results by real path (realpath), keeping the first path per real file in sorted order. A directory symlink cycle (which globby follows up to the kernel ELOOP limit, ~40 levels) no longer yields ~40× duplicated entries that AiDir.collectOtherFiles would read and re-emit. Added a circular-symlink test and a link-and-target-collapse test.
  • fix: add claudecode to valid targets in parser validation #2 (mid) — wrong comment rationale. Confirmed src/lib/git-client.ts does a non-bare clone (--no-checkout --filter=blob:none then git checkout), so symlinks are resolvable — the old comment ("unresolved symlinks in a bare clone are meaningless") was factually wrong. Rewrote it to state the real reason: walkDirectory skips symlinks as a security hardening for untrusted remote content (commit 51bf0443), a distinct code path from the local, trusted findFilesByGlobs.
  • Add support for sst/opencode #3 (mid) — realpath containment. Recorded an explicit design decision instead of adding a containment check: enforcing realpath containment against a single root would break issue Support symlinked shared skills in multi-directory repositories #1707's use case of sharing files that live elsewhere in the same repository (and --input-root trees legitimately point outside themselves). The remote-fetch path already skips symlinks, so untrusted content is not an attack vector. Documented in the code comment and the new docs section.
  • Add support for Openhands CLI #4 (low) — E2E-level coverage. Added a skills-processor.test.ts case that loads a skill directory which is a symlink to a real directory elsewhere.
  • Add support for opencode-ai/opencode #5 (low) — Windows. Guarded the symlink unit tests with describe.skipIf(process.platform === "win32") / it.skipIf(...) since fs.symlink needs admin or Developer Mode on Windows.
  • Add support for gemini-cli #6 (low) — discoverability. Added a feature-wide Symlinks section to docs/reference/file-formats.md (covering all features and plain .rulesync/ usage, not just --input-root), cross-linked it from the input-root guide, and synced skills/rulesync/.

pnpm cicheck passes locally (6194 tests; the content sync-check passes once the synced skills files are committed).

Closes #1808

🤖 Generated with Claude Code

cm-dyoshikawa and others added 2 commits June 9, 2026 22:52
… model

Follow-ups from PR #1802 review (issue #1808):
- Deduplicate findFilesByGlobs results by real path so directory symlink cycles
  (which globby follows up to the kernel ELOOP limit) no longer yield ~40x
  duplicated entries that get read and re-emitted (#1)
- Rewrite the findFilesByGlobs comment: git-client.ts skips symlinks as a
  security hardening for untrusted remote content (commit 51bf044), not because
  a bare clone makes them meaningless — it does a non-bare checkout (#2)
- Document the intentional trade-off of not enforcing realpath containment
  (it would break the issue #1707 shared-file use case); record the decision in
  the comment and docs rather than adding a containment check (#3)
- Add a skills-processor test loading a symlinked skill directory (#4)
- Guard symlink unit tests with skipIf(win32) since fs.symlink needs admin /
  Developer Mode on Windows (#5)
- Add a feature-wide Symlinks section to docs/reference/file-formats.md and
  cross-link it from the input-root guide; sync skills/rulesync (#6)

Closes #1808

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address low-severity review findings on PR #1811:
- Narrow the Symlinks docs wording: glob-based discovery (rules, commands,
  subagents, skills) follows symlinks; mcp/ignore/permissions load a single
  fixed-path file that the OS resolves transparently on read (no glob discovery)
- Strengthen the link-and-target dedup test to assert the sorted-first path
  (linked.md) survives and its target (real.md) is dropped

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dyoshikawa
dyoshikawa merged commit 7fcde86 into main Jun 10, 2026
8 checks passed
@dyoshikawa

Copy link
Copy Markdown
Owner Author

@dyoshikawa Thank you!

@dyoshikawa
dyoshikawa deleted the resolve-scrap-issue-1808-symlink-followups branch June 10, 2026 06:04
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.

Follow-ups from PR #1802 review: symlink following in findFilesByGlobs (cycle dedup, comment fix, boundary check, tests, docs)

2 participants