fix(auth): pin native auth storage operations

This commit is contained in:
2026-08-17 14:52:21 +02:00
parent 6d438f4c7e
commit cb0e873ed7
23 changed files with 3016 additions and 1385 deletions
+3 -71
View File
@@ -7,7 +7,6 @@ import { createAuthenticationConfigProvider } from "../src/auth/config.js";
import { createAuthentikGroupCatalog } from "../src/auth/authentik-group-catalog.js";
import { createLocalUserRegistry } from "../src/auth/local-registry.js";
import { createOidcProtocol, OidcJwksUnavailableError } from "../src/auth/oidc-client.js";
import { validateAuthSessionRoot } from "../src/auth/session-store.js";
import type { LoadedAuthConfig } from "../src/auth/types.js";
const sentinels = [
@@ -152,7 +151,7 @@ test("distinguishes a valid registry without an enabled admin from a malformed r
chmodSync(validUsers, 0o600);
const validReport = await createAuthDiagnoser({
authMode: "local", authStateRoot: validRoot,
sessionRootValidator: validateAuthSessionRoot,
sessionRootValidator: acceptSessionRoot,
authentication: { current: () => localConfig(join(validRoot, "auth.yaml")) },
localUserRegistry: createLocalUserRegistry(validUsers),
}).inspect({ live: false });
@@ -164,7 +163,7 @@ test("distinguishes a valid registry without an enabled admin from a malformed r
chmodSync(malformedUsers, 0o600);
const malformedReport = await createAuthDiagnoser({
authMode: "local", authStateRoot: malformedRoot,
sessionRootValidator: validateAuthSessionRoot,
sessionRootValidator: acceptSessionRoot,
authentication: { current: () => localConfig(join(malformedRoot, "auth.yaml")) },
localUserRegistry: createLocalUserRegistry(malformedUsers),
}).inspect({ live: false });
@@ -182,7 +181,7 @@ test("maps unsafe auth.yaml storage from the real provider to a redacted config
chmodSync(unsafePath, 0o640);
const report = await createAuthDiagnoser({
authMode: "local", authStateRoot: root,
sessionRootValidator: validateAuthSessionRoot,
sessionRootValidator: acceptSessionRoot,
authentication: createAuthenticationConfigProvider(unsafePath),
}).inspect({ live: false });
@@ -442,73 +441,6 @@ test("redacts exceptional configuration, registry, protocol, and catalog errors"
expect(report.checks.every((check) => check.level === "error" || check.level === "info")).toBe(true);
});
test.skipIf(process.platform === "win32")("uses the runtime validator for canonical, private session roots", async () => {
const dependencies = (authStateRoot: string) => ({
authMode: "none" as const,
authStateRoot,
sessionRootValidator: validateAuthSessionRoot,
});
const valid = privateRoot();
await expect(createAuthDiagnoser(dependencies(valid)).inspect({ live: false }))
.resolves.toMatchObject({ ready: true, checks: [expect.objectContaining({ code: "auth_ready" })] });
const realRoot = join(privateRoot(), "real-auth");
mkdirSync(realRoot, { mode: 0o700 });
chmodSync(realRoot, 0o700);
const linkedRoot = join(privateRoot(), "linked-auth");
symlinkSync(realRoot, linkedRoot);
const absent = join(privateRoot(), "absent-auth");
const absentParent = join(privateRoot(), "absent-parent");
const absentNested = join(absentParent, "auth");
const blockedParent = join(privateRoot(), "not-a-directory");
writeFileSync(blockedParent, "blocked", { mode: 0o600 });
const traversal = `${valid}/../${basename(valid)}`;
const missingReport = await createAuthDiagnoser(dependencies(absent)).inspect({ live: false });
expect(missingReport).toMatchObject({ ready: true, checks: [expect.objectContaining({ code: "auth_ready" })] });
expect(existsSync(absent)).toBe(false);
for (const unsafe of [traversal, linkedRoot, absentNested, join(blockedParent, "auth")]) {
const report = await createAuthDiagnoser(dependencies(unsafe)).inspect({ live: false });
expect(report).toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "auth_session_store_invalid" })] });
expect(JSON.stringify(report)).not.toContain(unsafe);
}
expect(existsSync(absentParent)).toBe(false);
chmodSync(valid, 0o750);
await expect(createAuthDiagnoser(dependencies(valid)).inspect({ live: false }))
.resolves.toMatchObject({ ready: false, checks: [expect.objectContaining({ code: "auth_session_store_invalid" })] });
});
test.skipIf(process.platform === "win32")("diagnoses unsafe existing session-store children without creating missing children", async () => {
const root = privateRoot();
const outside = privateRoot();
symlinkSync(outside, join(root, "sessions"));
const linked = await createAuthDiagnoser({
authMode: "none", authStateRoot: root, sessionRootValidator: validateAuthSessionRoot,
}).inspect({ live: false });
expect(linked).toMatchObject({
ready: false,
checks: [expect.objectContaining({ code: "auth_session_store_invalid" })],
});
expect(existsSync(join(root, "oidc"))).toBe(false);
expect(JSON.stringify(linked)).not.toContain(root);
rmSync(join(root, "sessions"));
mkdirSync(join(root, "sessions"), { mode: 0o700 });
chmodSync(join(root, "sessions"), 0o700);
mkdirSync(join(root, "oidc"), { mode: 0o700 });
chmodSync(join(root, "oidc"), 0o750);
const nonPrivate = await createAuthDiagnoser({
authMode: "none", authStateRoot: root, sessionRootValidator: validateAuthSessionRoot,
}).inspect({ live: false });
expect(nonPrivate).toMatchObject({
ready: false,
checks: [expect.objectContaining({ code: "auth_session_store_invalid" })],
});
});
test.skipIf(process.platform === "win32")("routes production POSIX static validation through the native auth-storage bridge", async () => {
const validateRoot = vi.fn(async () => undefined);
const report = await createAuthDiagnoser({