diff --git a/src/main/project-groups/nested-repo-discovery.test.ts b/src/main/project-groups/nested-repo-discovery.test.ts index c1ec7dd19..65332a887 100644 --- a/src/main/project-groups/nested-repo-discovery.test.ts +++ b/src/main/project-groups/nested-repo-discovery.test.ts @@ -1,4 +1,4 @@ -import { mkdtemp, mkdir, writeFile, rm } from 'fs/promises' +import { mkdtemp, mkdir, writeFile, rm, symlink } from 'fs/promises' import { join } from 'path' import { tmpdir } from 'os' import { afterEach, describe, expect, it } from 'vitest' @@ -76,4 +76,19 @@ describe('scanNestedRepos', () => { expect(result.selectedPathKind).toBe('git_repo') expect(result.repos).toEqual([]) }) + + it.skipIf(process.platform === 'win32')( + 'does not follow symlinked directories outside the selected folder', + async () => { + const root = await tempRoot() + const external = await tempRoot() + await mkdir(join(external, 'outside-repo'), { recursive: true }) + await makeGitRepo(join(external, 'outside-repo')) + await symlink(external, join(root, 'linked'), 'dir') + + const result = await scanNestedRepos({ path: root }) + + expect(result.repos).toEqual([]) + } + ) }) diff --git a/src/main/project-groups/nested-repo-discovery.ts b/src/main/project-groups/nested-repo-discovery.ts index 07b65974a..129e35b9e 100644 --- a/src/main/project-groups/nested-repo-discovery.ts +++ b/src/main/project-groups/nested-repo-discovery.ts @@ -70,13 +70,10 @@ async function hasGitMarker(dirPath: string): Promise { } async function readLocalDirectory(dirPath: string): Promise { - const entries = await readdir(dirPath) - const result: NestedRepoDirectoryEntry[] = [] - for (const name of entries) { - const childStat = await stat(join(dirPath, name)).catch(() => null) - result.push({ name, isDirectory: childStat?.isDirectory() === true }) - } - return result + // Why: Dirent data avoids one stat per child and keeps symlinked directories + // from expanding the scan outside the selected folder. + const entries = await readdir(dirPath, { withFileTypes: true }) + return entries.map((entry) => ({ name: entry.name, isDirectory: entry.isDirectory() })) } export async function scanNestedRepos(args: {