Skip to content

Commit df243c3

Browse files
committed
fix(shell): harden docker-git config scan against cache and broken symlinks
1 parent 9d67c90 commit df243c3

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

packages/lib/src/usecases/docker-git-config-search.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ type DockerGitConfigSearchState = {
1010

1111
const isDockerGitConfig = (entry: string): boolean => entry.endsWith("docker-git.json")
1212

13-
const shouldSkipDir = (entry: string): boolean => entry === ".git" || entry === ".orch" || entry === ".docker-git"
13+
const shouldSkipDir = (entry: string): boolean =>
14+
entry === ".git" || entry === ".orch" || entry === ".docker-git" || entry === ".cache"
15+
16+
const isNotFoundStatError = (error: PlatformError): boolean =>
17+
error._tag === "SystemError" && error.reason === "NotFound"
1418

1519
const processDockerGitEntry = (
1620
fs: FileSystem.FileSystem,
@@ -25,7 +29,18 @@ const processDockerGitEntry = (
2529
}
2630

2731
const resolved = path.join(dir, entry)
28-
const info = yield* _(fs.stat(resolved))
32+
const info = yield* _(
33+
fs.stat(resolved).pipe(
34+
Effect.catchAll((error) =>
35+
isNotFoundStatError(error)
36+
? Effect.succeed(null)
37+
: Effect.fail(error)
38+
)
39+
)
40+
)
41+
if (info === null) {
42+
return
43+
}
2944
if (info.type === "Directory") {
3045
state.stack.push(resolved)
3146
return

packages/lib/tests/usecases/docker-git-config-search.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,35 @@ describe("findDockerGitConfigPaths", () => {
4242
const includedNested = path.join(root, "org/repo-b/nested/docker-git.json")
4343
const ignoredGit = path.join(root, "org/repo-a/.git/docker-git.json")
4444
const ignoredOrch = path.join(root, "org/repo-a/.orch/docker-git.json")
45+
const ignoredRootCache = path.join(root, ".cache/packages/pnpm/store/v10/index/docker-git.json")
4546
const ignoredDockerGit = path.join(root, ".docker-git/.cache/git-mirrors/docker-git.json")
4647

4748
yield* _(writeFileWithParents(fs, path, includedMain))
4849
yield* _(writeFileWithParents(fs, path, includedNested))
4950
yield* _(writeFileWithParents(fs, path, ignoredGit))
5051
yield* _(writeFileWithParents(fs, path, ignoredOrch))
52+
yield* _(writeFileWithParents(fs, path, ignoredRootCache))
5153
yield* _(writeFileWithParents(fs, path, ignoredDockerGit))
5254

5355
const found = yield* _(findDockerGitConfigPaths(fs, path, root))
5456
expect([...found].sort()).toEqual([includedMain, includedNested].sort())
5557
})
5658
).pipe(Effect.provide(NodeContext.layer)))
59+
60+
it.effect("skips broken symlinks without failing search", () =>
61+
withTempDir((root) =>
62+
Effect.gen(function*(_) {
63+
const fs = yield* _(FileSystem.FileSystem)
64+
const path = yield* _(Path.Path)
65+
const includedMain = path.join(root, "org/repo-a/docker-git.json")
66+
const brokenLink = path.join(root, "org/repo-a/broken-link")
67+
const missingTarget = path.join(root, "org/repo-a/missing-target")
68+
69+
yield* _(writeFileWithParents(fs, path, includedMain))
70+
yield* _(fs.symlink(missingTarget, brokenLink))
71+
72+
const found = yield* _(findDockerGitConfigPaths(fs, path, root))
73+
expect(found).toEqual([includedMain])
74+
})
75+
).pipe(Effect.provide(NodeContext.layer)))
5776
})

0 commit comments

Comments
 (0)