Spaces:
Sleeping
Sleeping
File size: 3,344 Bytes
27329ef | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { buildApplication } from "../app.js";
import { parseEnvironment } from "../config/environment.js";
import { ApplicationError } from "./application-error.js";
const directories: string[] = [];
afterEach(async () => {
await Promise.all(
directories
.splice(0)
.map((directory) => rm(directory, { recursive: true, force: true })),
);
});
describe("canonical HTTP error handler", () => {
it("returns a stable request ID and exact unauthenticated session envelope", async () => {
const directory = await mkdtemp(join(tmpdir(), "oloka-error-handler-"));
directories.push(directory);
const app = await buildApplication({
environment: parseEnvironment({
NODE_ENV: "test",
OBJECT_STORAGE_ROOT: join(directory, "objects"),
DATABASE_PATH: join(directory, "database", "test.db"),
LOG_LEVEL: "silent",
}),
serveFrontend: false,
});
app.get("/api/test/rate-limit", () => {
throw new ApplicationError("RATE_LIMITED", "test_rate_limit", {
"retry-after": "5",
});
});
try {
const response = await app.inject({
method: "GET",
url: "/api/v1/auth/session",
});
expect(response.statusCode).toBe(401);
expect(response.json()).toEqual({
error: {
code: "AUTHENTICATION_REQUIRED",
retryable: true,
messageKey: "error.auth.required",
suggestedAction: "Sign in again with Google",
requestId: response.headers["x-request-id"],
},
});
const limited = await app.inject({
method: "GET",
url: "/api/test/rate-limit",
});
expect(limited.statusCode).toBe(429);
expect(limited.headers["retry-after"]).toBe("5");
expect(limited.json().error).toMatchObject({
code: "RATE_LIMITED",
messageKey: "error.rate_limited",
requestId: limited.headers["x-request-id"],
});
} finally {
await app.close();
}
});
it("maps unexpected failures to INTERNAL_ERROR without leaking the cause", async () => {
const directory = await mkdtemp(join(tmpdir(), "oloka-internal-error-"));
directories.push(directory);
const app = await buildApplication({
environment: parseEnvironment({
NODE_ENV: "test",
OBJECT_STORAGE_ROOT: join(directory, "objects"),
DATABASE_PATH: join(directory, "database", "test.db"),
LOG_LEVEL: "silent",
}),
serveFrontend: false,
});
app.get("/api/test/unexpected", () => {
throw new Error("database failed at C:\\sensitive\\production.sqlite");
});
try {
const response = await app.inject({
method: "GET",
url: "/api/test/unexpected",
});
expect(response.statusCode).toBe(500);
expect(response.json().error).toMatchObject({
code: "INTERNAL_ERROR",
messageKey: "error.internal",
requestId: response.headers["x-request-id"],
});
expect(response.body).not.toContain("production.sqlite");
expect(response.body).not.toContain("database failed");
} finally {
await app.close();
}
});
});
|