feat(15-03): update E2E seed and auth tests for OIDC architecture

- E2E seed creates API key instead of user for authentication
- Auth service tests cover only API key CRUD (removed user/session tests)
- Auth middleware tests validate three-way auth: API key, Bearer token, OIDC session
- Auth route tests mock getAuth for OIDC session, test /me and /keys endpoints
- Remove all references to createUser, verifyPassword, createSession in auth tests
This commit is contained in:
2026-04-04 20:54:18 +02:00
parent 79b27b6bcc
commit 689a56b2b7
4 changed files with 167 additions and 216 deletions

View File

@@ -1,17 +1,34 @@
import { beforeEach, describe, expect, test } from "bun:test";
import { beforeEach, describe, expect, mock, test } from "bun:test";
import { Hono } from "hono";
import { requireAuth } from "../../src/server/middleware/auth";
import {
createApiKey,
createSession,
createUser,
} from "../../src/server/services/auth.service";
import { createApiKey } from "../../src/server/services/auth.service";
import { createTestDb } from "../helpers/db";
// Mock @hono/oidc-auth - must be before importing middleware
const mockGetAuth = mock(() => null as any);
mock.module("@hono/oidc-auth", () => ({
getAuth: mockGetAuth,
oidcAuthMiddleware: () => async (_c: any, next: any) => next(),
processOAuthCallback: async (c: any) => c.json({ ok: true }),
revokeSession: async () => {},
}));
// Mock verifyAccessToken from oauth.service
const mockVerifyAccessToken = mock(() => Promise.resolve(false));
mock.module("../../src/server/services/oauth.service", () => ({
verifyAccessToken: mockVerifyAccessToken,
}));
// Import middleware AFTER mocks are set up
const { requireAuth } = await import("../../src/server/middleware/auth");
let db: ReturnType<typeof createTestDb>;
beforeEach(() => {
db = createTestDb();
mockGetAuth.mockReset();
mockGetAuth.mockReturnValue(null);
mockVerifyAccessToken.mockReset();
mockVerifyAccessToken.mockReturnValue(Promise.resolve(false));
});
function createApp() {
@@ -37,35 +54,16 @@ describe("auth middleware", () => {
expect(res.status).toBe(200);
});
test("returns 403 setup_required when no users exist", async () => {
test("rejects POST with no auth credentials", async () => {
const app = createApp();
const res = await app.request("/items", { method: "POST" });
expect(res.status).toBe(403);
const body = await res.json();
expect(body.error).toBe("setup_required");
});
test("rejects POST without auth when users exist", async () => {
const app = createApp();
await createUser(db, "admin", "pass");
const res = await app.request("/items", { method: "POST" });
expect(res.status).toBe(401);
});
test("allows POST with valid session cookie", async () => {
const app = createApp();
const user = await createUser(db, "admin", "pass");
const session = createSession(db, user.id);
const res = await app.request("/items", {
method: "POST",
headers: { Cookie: `gearbox_session=${session.id}` },
});
expect(res.status).toBe(200);
const body = await res.json();
expect(body.error).toBe("Authentication required");
});
test("allows POST with valid API key", async () => {
const app = createApp();
await createUser(db, "admin", "pass");
const key = await createApiKey(db, "test");
const res = await app.request("/items", {
method: "POST",
@@ -76,11 +74,52 @@ describe("auth middleware", () => {
test("rejects POST with invalid API key", async () => {
const app = createApp();
await createUser(db, "admin", "pass");
const res = await app.request("/items", {
method: "POST",
headers: { "X-API-Key": "invalid" },
headers: { "X-API-Key": "invalid-key-value" },
});
expect(res.status).toBe(401);
const body = await res.json();
expect(body.error).toBe("Invalid API key");
});
test("allows POST with valid Bearer token", async () => {
const app = createApp();
mockVerifyAccessToken.mockReturnValue(Promise.resolve(true));
const res = await app.request("/items", {
method: "POST",
headers: { Authorization: "Bearer valid-token-123" },
});
expect(res.status).toBe(200);
});
test("rejects POST with invalid Bearer token", async () => {
const app = createApp();
mockVerifyAccessToken.mockReturnValue(Promise.resolve(false));
const res = await app.request("/items", {
method: "POST",
headers: { Authorization: "Bearer invalid-token" },
});
expect(res.status).toBe(401);
const body = await res.json();
expect(body.error).toBe("invalid_token");
});
test("allows POST with valid OIDC session", async () => {
const app = createApp();
mockGetAuth.mockReturnValue({ sub: "user-123", email: "test@example.com" });
const res = await app.request("/items", { method: "POST" });
expect(res.status).toBe(200);
});
test("API key takes priority over OIDC session", async () => {
const app = createApp();
const key = await createApiKey(db, "test");
mockGetAuth.mockReturnValue({ sub: "user-123" });
const res = await app.request("/items", {
method: "POST",
headers: { "X-API-Key": key.rawKey },
});
expect(res.status).toBe(200);
});
});