From d9806e84e659e3dabc8c2786dfbe88cbf667c1d2 Mon Sep 17 00:00:00 2001 From: fuomag9 <1580624+fuomag9@users.noreply.github.com> Date: Thu, 26 Mar 2026 10:33:47 +0100 Subject: [PATCH] fix: resolve lint and typecheck errors in API routes and tests - Remove unused imports (users, and) from api-tokens model - Fix password_hash destructure lint error in user routes - Fix apiErrorResponse mock pattern in all 12 test files (use instanceof) - Remove stale eslint-disable directives from test files - Add eslint override for tests (no-explicit-any, no-require-imports) - Fix unused vars in settings and tokens tests - Fix unused tokenB in integration test Co-Authored-By: Claude Opus 4.6 (1M context) --- app/api/v1/users/[id]/route.ts | 3 ++- app/api/v1/users/route.ts | 3 ++- eslint.config.mjs | 7 +++++++ src/lib/models/api-tokens.ts | 4 ++-- tests/integration/api-tokens.test.ts | 2 +- tests/unit/api-routes/access-lists.test.ts | 8 ++++---- tests/unit/api-routes/audit-log.test.ts | 8 ++++---- tests/unit/api-routes/ca-certificates.test.ts | 8 ++++---- tests/unit/api-routes/caddy.test.ts | 8 ++++---- tests/unit/api-routes/certificates.test.ts | 8 ++++---- tests/unit/api-routes/client-certificates.test.ts | 8 ++++---- tests/unit/api-routes/instances.test.ts | 8 ++++---- tests/unit/api-routes/l4-proxy-hosts.test.ts | 8 ++++---- tests/unit/api-routes/proxy-hosts.test.ts | 8 ++++---- tests/unit/api-routes/settings.test.ts | 10 +++++----- tests/unit/api-routes/tokens.test.ts | 10 +++++----- tests/unit/api-routes/users.test.ts | 8 ++++---- 17 files changed, 64 insertions(+), 55 deletions(-) diff --git a/app/api/v1/users/[id]/route.ts b/app/api/v1/users/[id]/route.ts index 31f96002..b42a5151 100644 --- a/app/api/v1/users/[id]/route.ts +++ b/app/api/v1/users/[id]/route.ts @@ -3,7 +3,8 @@ import { requireApiUser, requireApiAdmin, apiErrorResponse, ApiAuthError } from import { getUserById, updateUserProfile } from "@/src/lib/models/user"; function stripPasswordHash(user: Record) { - const { password_hash, ...rest } = user; + const { password_hash: _, ...rest } = user; + void _; return rest; } diff --git a/app/api/v1/users/route.ts b/app/api/v1/users/route.ts index 9c6b3a6f..94f6a68c 100644 --- a/app/api/v1/users/route.ts +++ b/app/api/v1/users/route.ts @@ -3,7 +3,8 @@ import { requireApiAdmin, apiErrorResponse } from "@/src/lib/api-auth"; import { listUsers } from "@/src/lib/models/user"; function stripPasswordHash(user: Record) { - const { password_hash, ...rest } = user; + const { password_hash: _, ...rest } = user; + void _; return rest; } diff --git a/eslint.config.mjs b/eslint.config.mjs index acadd073..49e31d39 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -19,4 +19,11 @@ export default [ '@next/next/no-img-element': 'off', }, }, + { + files: ['tests/**/*.{ts,tsx}'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-require-imports': 'off', + }, + }, ]; diff --git a/src/lib/models/api-tokens.ts b/src/lib/models/api-tokens.ts index 37ff62bd..2c1f948c 100644 --- a/src/lib/models/api-tokens.ts +++ b/src/lib/models/api-tokens.ts @@ -1,7 +1,7 @@ import { createHash, randomBytes } from "node:crypto"; import db, { nowIso, toIso } from "../db"; -import { apiTokens, users } from "../db/schema"; -import { eq, and } from "drizzle-orm"; +import { apiTokens } from "../db/schema"; +import { eq } from "drizzle-orm"; export type ApiToken = { id: number; diff --git a/tests/integration/api-tokens.test.ts b/tests/integration/api-tokens.test.ts index aee11fb5..742a96bf 100644 --- a/tests/integration/api-tokens.test.ts +++ b/tests/integration/api-tokens.test.ts @@ -196,7 +196,7 @@ describe('api-tokens integration', () => { const userB = await insertUser({ email: 'b@localhost', subject: 'b@localhost', role: 'user' }); const { token: tokenA } = await insertApiToken(userA.id, { name: 'A Token' }); - const { token: tokenB } = await insertApiToken(userB.id, { name: 'B Token' }); + await insertApiToken(userB.id, { name: 'B Token' }); // User B deletes only their own tokens await db.delete(apiTokens).where(eq(apiTokens.createdBy, userB.id)); diff --git a/tests/unit/api-routes/access-lists.test.ts b/tests/unit/api-routes/access-lists.test.ts index 6e2c08f8..8e67a655 100644 --- a/tests/unit/api-routes/access-lists.test.ts +++ b/tests/unit/api-routes/access-lists.test.ts @@ -19,11 +19,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/audit-log.test.ts b/tests/unit/api-routes/audit-log.test.ts index bbb4e981..24a13543 100644 --- a/tests/unit/api-routes/audit-log.test.ts +++ b/tests/unit/api-routes/audit-log.test.ts @@ -14,11 +14,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/ca-certificates.test.ts b/tests/unit/api-routes/ca-certificates.test.ts index bb761313..300ab96b 100644 --- a/tests/unit/api-routes/ca-certificates.test.ts +++ b/tests/unit/api-routes/ca-certificates.test.ts @@ -17,11 +17,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/caddy.test.ts b/tests/unit/api-routes/caddy.test.ts index 15766dc2..6f2aa563 100644 --- a/tests/unit/api-routes/caddy.test.ts +++ b/tests/unit/api-routes/caddy.test.ts @@ -13,11 +13,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/certificates.test.ts b/tests/unit/api-routes/certificates.test.ts index 56085d72..13e77ba2 100644 --- a/tests/unit/api-routes/certificates.test.ts +++ b/tests/unit/api-routes/certificates.test.ts @@ -17,11 +17,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/client-certificates.test.ts b/tests/unit/api-routes/client-certificates.test.ts index 6697197a..33e861d0 100644 --- a/tests/unit/api-routes/client-certificates.test.ts +++ b/tests/unit/api-routes/client-certificates.test.ts @@ -16,11 +16,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/instances.test.ts b/tests/unit/api-routes/instances.test.ts index 03fde65a..a7a10ecf 100644 --- a/tests/unit/api-routes/instances.test.ts +++ b/tests/unit/api-routes/instances.test.ts @@ -19,11 +19,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/l4-proxy-hosts.test.ts b/tests/unit/api-routes/l4-proxy-hosts.test.ts index b1c1c000..128957e7 100644 --- a/tests/unit/api-routes/l4-proxy-hosts.test.ts +++ b/tests/unit/api-routes/l4-proxy-hosts.test.ts @@ -17,11 +17,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/proxy-hosts.test.ts b/tests/unit/api-routes/proxy-hosts.test.ts index 3b1ea127..848fc766 100644 --- a/tests/unit/api-routes/proxy-hosts.test.ts +++ b/tests/unit/api-routes/proxy-hosts.test.ts @@ -17,11 +17,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; diff --git a/tests/unit/api-routes/settings.test.ts b/tests/unit/api-routes/settings.test.ts index 8fb5cbc5..ff75a21b 100644 --- a/tests/unit/api-routes/settings.test.ts +++ b/tests/unit/api-routes/settings.test.ts @@ -41,11 +41,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; @@ -218,7 +218,7 @@ describe('PUT /api/v1/settings/[group]', () => { const body = {}; const response = await PUT(createMockRequest({ method: 'PUT', body }), { params: Promise.resolve({ group: 'sync-token' }) }); - const data = await response.json(); + await response.json(); expect(response.status).toBe(200); expect(mockSetSlaveMasterToken).toHaveBeenCalledWith(null); diff --git a/tests/unit/api-routes/tokens.test.ts b/tests/unit/api-routes/tokens.test.ts index d6afb6b5..4f846c9a 100644 --- a/tests/unit/api-routes/tokens.test.ts +++ b/tests/unit/api-routes/tokens.test.ts @@ -16,11 +16,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, }; @@ -124,7 +124,7 @@ describe('POST /api/v1/tokens', () => { mockCreateApiToken.mockResolvedValue(tokenResult as any); const response = await POST(createMockRequest({ method: 'POST', body: { name: 'Expiring Token', expires_at: '2027-01-01' } })); - const data = await response.json(); + await response.json(); expect(response.status).toBe(201); expect(mockCreateApiToken).toHaveBeenCalledWith('Expiring Token', 1, '2027-01-01'); diff --git a/tests/unit/api-routes/users.test.ts b/tests/unit/api-routes/users.test.ts index 56a0f1ea..6e0e3c9a 100644 --- a/tests/unit/api-routes/users.test.ts +++ b/tests/unit/api-routes/users.test.ts @@ -15,11 +15,11 @@ vi.mock('@/src/lib/api-auth', () => { requireApiAdmin: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), requireApiUser: vi.fn().mockResolvedValue({ userId: 1, role: 'admin', authMethod: 'bearer' }), apiErrorResponse: vi.fn((error: unknown) => { - const { NextResponse } = require('next/server'); - if (error && typeof error === 'object' && 'status' in error) { - return NextResponse.json({ error: (error as Error).message }, { status: (error as any).status }); + const { NextResponse: NR } = require('next/server'); + if (error instanceof ApiAuthError) { + return NR.json({ error: error.message }, { status: error.status }); } - return NextResponse.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); + return NR.json({ error: error instanceof Error ? error.message : 'Internal server error' }, { status: 500 }); }), ApiAuthError, };