Skip to content

Commit 45996f9

Browse files
committed
Fail open on unresolvable local settings paths
1 parent 7b529eb commit 45996f9

2 files changed

Lines changed: 17 additions & 1 deletion

File tree

src/config/settings.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,9 @@ function physicalPathIdentity(path: string): string {
405405
try {
406406
return join(realpathSync.native(candidate), ...missingSegments.reverse());
407407
} catch (err) {
408-
if (!isENOENT(err)) throw err;
408+
// Anything but a missing segment (ENOTDIR, EACCES, ...) is not aliasable;
409+
// fall back to the lexical path so the fail-open loader sees it.
410+
if (!isENOENT(err)) return resolve(path);
409411
const parent = dirname(candidate);
410412
if (parent === candidate) return resolve(path);
411413
missingSegments.push(basename(candidate));

tests/unit/config.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,20 @@ test("local settings target is omitted when it aliases global settings", async (
103103
}
104104
});
105105

106+
test("local settings target falls back to the lexical path when .corbits is a regular file", async () => {
107+
const { globalSettingsPath, resolveLocalSettingsPath } =
108+
await import("../../src/config/settings.js");
109+
const root = await mkdtemp(join(tmpdir(), "ic-unit-config-notdir-"));
110+
try {
111+
await writeFile(join(root, ".corbits"), "");
112+
expect(resolveLocalSettingsPath(root, globalSettingsPath(join(root, "home")))).toBe(
113+
join(root, ".corbits", "settings.json"),
114+
);
115+
} finally {
116+
await rm(root, { recursive: true, force: true });
117+
}
118+
});
119+
106120
test("local settings target detects a symlink alias before the settings file exists", async () => {
107121
const { globalSettingsPath, resolveLocalSettingsPath } =
108122
await import("../../src/config/settings.js");

0 commit comments

Comments
 (0)