chore: upgrade Node.js runtime to v24 across codebase #419
@@ -609,5 +609,94 @@ describe("AuthService", () => {
|
||||
|
||||
await expect(service.verifySession("any-token")).rejects.toThrow("Database connection lost");
|
||||
});
|
||||
|
||||
it("should redact Bearer tokens from logged error messages", async () => {
|
||||
const auth = service.getAuth();
|
||||
const errorWithToken = new Error(
|
||||
"Request failed: Bearer eyJhbGciOiJIUzI1NiJ9.secret-payload in header"
|
||||
);
|
||||
const mockGetSession = vi.fn().mockRejectedValue(errorWithToken);
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
const loggerError = vi.spyOn(service["logger"], "error");
|
||||
|
||||
await expect(service.verifySession("any-token")).rejects.toThrow();
|
||||
|
||||
expect(loggerError).toHaveBeenCalledWith(
|
||||
"Session verification failed due to unexpected error",
|
||||
expect.stringContaining("Bearer [REDACTED]")
|
||||
);
|
||||
expect(loggerError).toHaveBeenCalledWith(
|
||||
"Session verification failed due to unexpected error",
|
||||
expect.not.stringContaining("eyJhbGciOiJIUzI1NiJ9")
|
||||
);
|
||||
});
|
||||
|
||||
it("should redact Bearer tokens from error stack traces", async () => {
|
||||
const auth = service.getAuth();
|
||||
const errorWithToken = new Error("Something went wrong");
|
||||
errorWithToken.stack =
|
||||
"Error: Something went wrong\n at fetch (Bearer abc123-secret-token)\n at verifySession";
|
||||
const mockGetSession = vi.fn().mockRejectedValue(errorWithToken);
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
const loggerError = vi.spyOn(service["logger"], "error");
|
||||
|
||||
await expect(service.verifySession("any-token")).rejects.toThrow();
|
||||
|
||||
expect(loggerError).toHaveBeenCalledWith(
|
||||
"Session verification failed due to unexpected error",
|
||||
expect.stringContaining("Bearer [REDACTED]")
|
||||
);
|
||||
expect(loggerError).toHaveBeenCalledWith(
|
||||
"Session verification failed due to unexpected error",
|
||||
expect.not.stringContaining("abc123-secret-token")
|
||||
);
|
||||
});
|
||||
|
||||
it("should warn when a non-Error string value is thrown", async () => {
|
||||
const auth = service.getAuth();
|
||||
const mockGetSession = vi.fn().mockRejectedValue("string-error");
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
const loggerWarn = vi.spyOn(service["logger"], "warn");
|
||||
|
||||
const result = await service.verifySession("any-token");
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(loggerWarn).toHaveBeenCalledWith(
|
||||
"Session verification received non-Error thrown value",
|
||||
"string-error"
|
||||
);
|
||||
});
|
||||
|
||||
it("should warn with JSON when a non-Error object is thrown", async () => {
|
||||
const auth = service.getAuth();
|
||||
const mockGetSession = vi.fn().mockRejectedValue({ code: "ERR_UNKNOWN" });
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
const loggerWarn = vi.spyOn(service["logger"], "warn");
|
||||
|
||||
const result = await service.verifySession("any-token");
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(loggerWarn).toHaveBeenCalledWith(
|
||||
"Session verification received non-Error thrown value",
|
||||
JSON.stringify({ code: "ERR_UNKNOWN" })
|
||||
);
|
||||
});
|
||||
|
||||
it("should not warn for expected auth errors (Error instances)", async () => {
|
||||
const auth = service.getAuth();
|
||||
const mockGetSession = vi.fn().mockRejectedValue(new Error("Invalid token provided"));
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
const loggerWarn = vi.spyOn(service["logger"], "warn");
|
||||
|
||||
const result = await service.verifySession("bad-token");
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(loggerWarn).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -139,14 +139,24 @@ export class AuthService {
|
||||
|
||||
if (!isExpectedAuthError) {
|
||||
// Infrastructure or unexpected — propagate as 500
|
||||
const safeMessage = (error.stack ?? error.message).replace(
|
||||
/Bearer\s+\S+/gi,
|
||||
"Bearer [REDACTED]"
|
||||
);
|
||||
this.logger.error(
|
||||
"Session verification failed due to unexpected error",
|
||||
error.stack ?? error.message
|
||||
safeMessage
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// Non-Error thrown values or expected auth errors
|
||||
// Non-Error thrown values — log for observability, treat as auth failure
|
||||
if (!(error instanceof Error)) {
|
||||
this.logger.warn(
|
||||
"Session verification received non-Error thrown value",
|
||||
typeof error === "object" ? JSON.stringify(error) : String(error),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user