fix: skip symlink cycles during pack instead of failing with ELOOP - #293
fix: skip symlink cycles during pack instead of failing with ELOOP#293gagan-53 wants to merge 1 commit into
Conversation
getAllFiles and getAllFilesWithCount follow symlinks via statSync and recurse into anything reported as a directory, so a symlink cycle (e.g. a self-referential link) descends until the OS raises ELOOP and pack aborts with a cryptic error. Track the real paths of directories on the current traversal path and, when recursing would revisit one, warn with the offending path and skip it. Non-cyclic symlinks are still followed and packed as before. Fixes modelcontextprotocol#292 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
I offered on #292 to test this against both cases in the report, so here is the result. Both are fixed, and the non-cyclic control is byte-identical to Setup:
The control archive holds the same four entries on both refs: The new tests have teeth. I replaced Two small notes, neither a blocker. The warning prints once per walk, so a single cycle is reported twice. A dangling symlink still fails the pack. |
Fixes #292.
Problem
When an extension directory contains a symlink cycle (e.g.
ln -s . selfloop),mcpb packaborts with a raw OS error and produces no archive:getAllFilesandgetAllFilesWithCountinsrc/node/files.tswalk the tree withstatSync(which follows symlinks) and recurse into anything reported as a directory, with no tracking of already-visited paths, so a cyclic link descends until the OS raisesELOOP.Fix
Track the real paths (
realpathSync) of the directories on the current traversal path. Before recursing into a directory, resolve its real path; if it is already on the traversal path, emit a warning naming the offending path and skip it:Packing then continues and succeeds. Behavior for everything else is unchanged:
visitedRealPathsparameter is optional and trailing on both exported functions, so the public API is backward compatible.Testing
test/symlink-cycle.test.ts: self-referential symlink, mutually recursive symlinks (A→B, B→A), a non-cyclic symlink still being followed, and coverage of bothgetAllFilesandgetAllFilesWithCount. The cycle tests fail withELOOPwithout the fix. Symlinks are created with typejunction(works unprivileged on Windows; ignored elsewhere) and the tests no-op if the environment cannot create symlinks.yarn test: 129 passed, 9 suites.yarn lint: clean.ERROR: Archive error: ELOOP: ..., exit 1, no archive; after — warning + successful pack, archive written, exit 0.