feat(auth): add local login and CSRF-protected sessions

This commit is contained in:
2026-08-16 23:23:55 +02:00
parent 8477a69a29
commit 29bfb41363
10 changed files with 1062 additions and 35 deletions
+11 -9
View File
@@ -163,19 +163,20 @@ test("a durable maintenance marker initializes admission closed after backend re
}
});
test.each(["none", "upstream"] as const)(
"maintenance control is loopback-only and independent of %s authentication",
async (authMode) => {
test("maintenance control requires an upstream identity and remains loopback-only", async () => {
const dir = mkdtempSync(path.join(tmpdir(), "tht-maintenance-control-"));
const marker = path.join(dir, "maintenance.json");
try {
const app = buildApp(loadConfig({
AUTH_MODE: authMode,
AUTH_MODE: "upstream",
THT_HARNESS_DIR: "../harness",
THT_MAINTENANCE_FILE: marker,
}), { thtRunner: {} as any });
const activated = await app.inject({ method: "POST", url: "/internal/maintenance/activate" });
expect((await app.inject({ method: "POST", url: "/internal/maintenance/activate" })).statusCode).toBe(401);
const activated = await app.inject({
method: "POST", url: "/internal/maintenance/activate", headers: aliceHeaders,
});
expect(activated.statusCode).toBe(200);
expect(activated.json()).toEqual({ active: true, admissions: 0 });
@@ -190,15 +191,16 @@ test.each(["none", "upstream"] as const)(
});
expect(spoofedProxy.statusCode).toBe(403);
const status = await app.inject({ method: "GET", url: "/internal/maintenance/status" });
const status = await app.inject({ method: "GET", url: "/internal/maintenance/status", headers: aliceHeaders });
expect(status.json()).toEqual({ active: true, admissions: 0 });
const deactivated = await app.inject({ method: "POST", url: "/internal/maintenance/deactivate" });
const deactivated = await app.inject({
method: "POST", url: "/internal/maintenance/deactivate", headers: aliceHeaders,
});
expect(deactivated.json()).toEqual({ active: false, admissions: 0 });
} finally {
rmSync(dir, { recursive: true, force: true });
}
},
);
});
test("maintenance endpoints report marker-derived state after post-rename and post-remove fsync failures", async () => {
const dir = mkdtempSync(path.join(tmpdir(), "tht-maintenance-endpoint-fsync-"));