fix(auth): address Task 13 deployment review findings

This commit is contained in:
2026-08-17 21:31:25 +02:00
parent 9558eaa508
commit 7e52df2702
22 changed files with 1279 additions and 82 deletions
+37
View File
@@ -184,6 +184,43 @@ test("the session boundary exposes only exact health and authentication protocol
expect((await app.inject({ method: "GET", url: "/auth/configured" })).statusCode).toBe(401);
});
test("the session boundary retains the exact loopback tht maintenance identity in configured auth modes", async () => {
const app = Fastify();
app.addHook("preHandler", authenticateSession({ mode: "local" }));
app.get("/private", async (request) => getPrincipal(request));
app.post("/private", async (request) => getPrincipal(request));
const headers = {
"x-thoth-principal-issuer": "tht",
"x-thoth-principal-subject": "tht-maintenance",
"x-thoth-principal-display-name": "Tht maintenance",
"x-thoth-is-admin": "1",
};
for (const method of ["GET", "POST"] as const) {
const response = await app.inject({ method, url: "/private", headers, remoteAddress: "127.0.0.1" });
expect(response.statusCode).toBe(200);
expect(response.json()).toMatchObject({ issuer: "tht", subject: "tht-maintenance", isAdmin: true });
}
});
test("the session boundary rejects tht maintenance headers outside exact loopback provenance", async () => {
const app = Fastify();
app.addHook("preHandler", authenticateSession({ mode: "local" }));
app.get("/private", async (request) => getPrincipal(request));
const exact = {
"x-thoth-principal-issuer": "tht",
"x-thoth-principal-subject": "tht-maintenance",
"x-thoth-principal-display-name": "Tht maintenance",
"x-thoth-is-admin": "1",
};
expect((await app.inject({ method: "GET", url: "/private", headers: exact, remoteAddress: "172.30.0.9" })).statusCode).toBe(503);
expect((await app.inject({
method: "GET", url: "/private", remoteAddress: "127.0.0.1",
headers: { ...exact, "x-thoth-principal-subject": "not-maintenance" },
})).statusCode).toBe(503);
});
test("the session boundary touches a valid cookie session through the bounded Task 7 store operation", async () => {
const sessions = {
resolve: vi.fn(async () => ({
+28
View File
@@ -0,0 +1,28 @@
import { describe, expect, it } from "vitest";
import { formatStartupFailure } from "../src/startup-error.js";
describe("formatStartupFailure", () => {
it.each([
[new Error("auth_session_store_invalid"), "backend startup failed: auth_session_store_invalid"],
[new Error("auth_config_invalid"), "backend startup failed: auth_config_invalid"],
[new Error("workspace_registry_invalid"), "backend startup failed: workspace_registry_invalid"],
])("emits only an allowlisted startup cause", (error, expected) => {
expect(formatStartupFailure(error)).toBe(expected);
});
it("collapses unknown errors without exposing their message, stack, token, or path", () => {
const error = new Error(
"EACCES password=plain-secret token=token-secret at /run/secrets/private-token",
);
error.stack = "Error: raw failure\n at /app/backend/dist/server.js:42:1";
const formatted = formatStartupFailure(error);
expect(formatted).toBe("backend startup failed: startup_unknown");
for (const leaked of [
"EACCES", "plain-secret", "token-secret", "/run/secrets", "raw failure", "server.js",
]) {
expect(formatted).not.toContain(leaked);
}
});
});
+23
View File
@@ -93,6 +93,29 @@ function bridgeForChild(child: FakeBridgeChild, pathStyle: "windows" | "posix" =
}
describe("Windows auth-storage bridge", () => {
test("uses a dedicated native storage executable without replacing the harness tht", async () => {
vi.stubEnv("THT_BIN", "/opt/venv/bin/tht");
vi.stubEnv("THT_AUTH_STORAGE_BIN", "/usr/local/bin/tht-auth-storage");
const calls: Array<{ executable: string }> = [];
const bridge = createPosixAuthStorageBridge({
invoke: async (call) => {
calls.push(call);
return {
code: 0,
stdout: Buffer.from('{"version":1,"ok":true,"prepared":true}\n'),
stderr: Buffer.alloc(0),
};
},
});
await bridge.ensureLayout("/data/auth");
expect(calls).toHaveLength(1);
expect(calls[0]!.executable).toBe("/usr/local/bin/tht-auth-storage");
expect(process.env.THT_BIN).toBe("/opt/venv/bin/tht");
vi.unstubAllEnvs();
});
test("uses the same bounded hidden bridge to ensure a POSIX session layout", async () => {
const calls: Array<{ executable: string; args: readonly string[]; input: Buffer; timeoutMs: number }> = [];
const bridge = createPosixAuthStorageBridge({