feat(server): activate projected authentication safely

This commit is contained in:
User
2026-08-22 01:01:36 +02:00
parent 903c0b4de5
commit 3d9a9f0675
32 changed files with 1837 additions and 38 deletions
@@ -20,6 +20,7 @@ import { stringify } from "yaml";
import { afterEach, expect, test, vi } from "vitest";
import { createProjectedAuthenticationConfigProvider } from "../src/auth/runtime-projection.js";
import { createCurrentLocalUserRegistryResolver } from "../src/auth/local-registry.js";
import { loadConfig } from "../src/config.js";
const fsHook = vi.hoisted(() => ({
path: undefined as string | undefined,
@@ -308,6 +309,35 @@ test("loads a complete OIDC projection without a users snapshot", () => {
});
});
test("loadConfig selects an immutable projected local provider and its in-memory registry", async () => {
const root = projectionRoot();
writeReadyProjection(root, localProjectionFixture("projected-user", passwordHash));
const config = loadConfig({
THT_AUTH_RUNTIME_PROJECTION_ROOT: root,
THT_AUTH_STATE_ROOT: "/state/auth",
});
const loaded = config.authentication?.current();
expect(loaded).toMatchObject({ value: { mode: "local" }, runtimeProjection: expect.any(Object) });
const registry = createCurrentLocalUserRegistryResolver().resolve(loaded!);
expect(await registry?.findByUsername("PROJECTED-USER")).toMatchObject({ username: "projected-user" });
});
test("loadConfig selects an immutable projected OIDC provider without direct-file fallback", () => {
const root = projectionRoot();
writeReadyOidcProjection(root);
const config = loadConfig({
THT_AUTH_RUNTIME_PROJECTION_ROOT: root,
THT_AUTH_CONFIG_FILE: "/run/thothii-auth/auth.yaml",
THT_AUTH_STATE_ROOT: "/state/auth",
});
expect(config.authentication?.current()).toMatchObject({
value: { mode: "oidc" },
runtimeProjection: expect.any(Object),
});
});
test("rejects a trailing-slash runtime root", () => {
const root = projectionRoot();
writeReadyProjection(
+25
View File
@@ -117,6 +117,31 @@ test("loadConfig makes an existing auth.yaml authoritative and rejects AUTH_MODE
}
});
test.each([
["relative root", { THT_AUTH_RUNTIME_PROJECTION_ROOT: "relative" }],
["conflicting direct file", {
THT_AUTH_RUNTIME_PROJECTION_ROOT: "/run/thothii-auth",
THT_AUTH_CONFIG_FILE: "/different/auth.yaml",
}],
])("rejects projected authentication configuration: %s", (_name, env) => {
expect(() => loadConfig(env)).toThrow("authentication configuration is invalid");
});
test("keeps the direct auth-file provider when the runtime projection environment is absent", () => {
const { directory, file } = authFile(oidcAuthConfig());
try {
const loaded = loadConfig({ THT_AUTH_CONFIG_FILE: file, THT_AUTH_STATE_ROOT: "/state/auth" });
const current = loaded.authentication?.current();
expect(current).toMatchObject({
sourcePath: file,
value: { mode: "oidc" },
});
expect(current?.runtimeProjection).toBeUndefined();
} finally {
rmSync(directory, { recursive: true, force: true });
}
});
test("loadConfig rejects an auth config path that exists but is not a regular file", () => {
const directory = mkdtempSync(join(realpathSync(tmpdir()), "thothii-app-auth-config-directory-"));
try {