fix(auth): make diagnostics match runtime safety

This commit is contained in:
2026-08-17 11:23:52 +02:00
parent f0ae680671
commit 7cfbee36fa
14 changed files with 619 additions and 99 deletions
+37 -1
View File
@@ -18,7 +18,7 @@ import {
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { basename, join } from "node:path";
import { afterEach, describe, expect, test, vi } from "vitest";
const fsHooks = vi.hoisted(() => ({
@@ -66,6 +66,7 @@ vi.mock("node:fs", async (importOriginal) => {
import {
createFileAuthSessionStore,
deriveCsrfToken,
validateAuthSessionRoot,
type AuthSessionStore,
type FileAuthSessionStoreOptions,
type SessionCreateInput,
@@ -241,6 +242,41 @@ async function isolatedOidcCreator(storageRoot: string, attempts: number): Promi
}
describe("file-backed auth session store", () => {
test.skipIf(process.platform === "win32")("exports its side-effect-free canonical session-root validator", () => {
const valid = root();
expect(() => validateAuthSessionRoot(valid)).not.toThrow();
const outer = root();
const realRoot = join(outer, "real-auth");
mkdirSync(realRoot, { mode: 0o700 });
chmodSync(realRoot, 0o700);
const linkedRoot = join(outer, "linked-auth");
symlinkSync(realRoot, linkedRoot);
const traversal = `${valid}/../${basename(valid)}`;
const absent = join(outer, "absent-auth");
const fileParent = join(outer, "not-a-directory");
writeFileSync(fileParent, "blocked", { mode: 0o600 });
for (const unsafe of [traversal, linkedRoot, absent, join(fileParent, "auth")]) {
expect(() => validateAuthSessionRoot(unsafe)).toThrow("auth_session_store_invalid");
}
chmodSync(valid, 0o750);
expect(() => validateAuthSessionRoot(valid)).toThrow("auth_session_store_invalid");
});
test.skipIf(process.platform === "win32")("rejects a session root owned by another identity", () => {
const storageRoot = root();
fsHooks.transformLstat = (observed, info) => {
if (observed !== storageRoot) return info;
const foreign = Object.create(info) as import("node:fs").Stats;
Object.defineProperty(foreign, "uid", { value: info.uid + 1 });
return foreign;
};
expect(() => validateAuthSessionRoot(storageRoot)).toThrow("auth_session_store_invalid");
});
test("fails closed and revokes a session when constructed without validity dependencies", async () => {
const storageRoot = root();
const store = createFileAuthSessionStore(storageRoot);