From 951b38db67a0b5a753e1acd97a7ec9a8275c8892 Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Wed, 21 Jan 2026 11:38:25 +0100 Subject: [PATCH] chore: update lint scripts and improve formatting consistency - Added `lint:fix` scripts for backend, frontend, and documentation. - Enabled `biome check --write` for unsafe fixes in backend scripts. - Fixed imports, formatting, and logging for improved code clarity. - Adjusted service unit tests for better readability and maintainability. --- backend/biome.json | 3 ++- backend/package.json | 2 +- backend/src/auth/auth.controller.spec.ts | 7 ++++- backend/src/auth/auth.controller.ts | 11 +++++++- backend/src/auth/bootstrap.service.spec.ts | 31 ++++++++++++++-------- backend/src/auth/bootstrap.service.ts | 18 +++++++++---- backend/src/auth/rbac.service.ts | 6 ++++- backend/src/s3/s3.service.spec.ts | 1 - frontend/package.json | 1 + package.json | 4 +++ 10 files changed, 62 insertions(+), 22 deletions(-) diff --git a/backend/biome.json b/backend/biome.json index 25e82d8..daed53d 100644 --- a/backend/biome.json +++ b/backend/biome.json @@ -24,7 +24,8 @@ "rules": { "recommended": true, "suspicious": { - "noUnknownAtRules": "off" + "noUnknownAtRules": "off", + "noExplicitAny": "off" }, "style": { "useImportType": "off" diff --git a/backend/package.json b/backend/package.json index e601509..3254216 100644 --- a/backend/package.json +++ b/backend/package.json @@ -13,7 +13,7 @@ "scripts": { "build": "nest build", "lint": "biome check", - "lint:write": "biome check --write", + "lint:write": "biome check --write --unsafe", "format": "biome format --write", "start": "nest start", "start:dev": "nest start --watch", diff --git a/backend/src/auth/auth.controller.spec.ts b/backend/src/auth/auth.controller.spec.ts index 3375ce0..f78f5c7 100644 --- a/backend/src/auth/auth.controller.spec.ts +++ b/backend/src/auth/auth.controller.spec.ts @@ -24,6 +24,7 @@ import { ConfigService } from "@nestjs/config"; import { Test, TestingModule } from "@nestjs/testing"; import { AuthController } from "./auth.controller"; import { AuthService } from "./auth.service"; +import { BootstrapService } from "./bootstrap.service"; jest.mock("iron-session", () => ({ getIronSession: jest.fn().mockResolvedValue({ @@ -44,6 +45,10 @@ describe("AuthController", () => { refresh: jest.fn(), }; + const mockBootstrapService = { + consumeToken: jest.fn(), + }; + const mockConfigService = { get: jest .fn() @@ -55,6 +60,7 @@ describe("AuthController", () => { controllers: [AuthController], providers: [ { provide: AuthService, useValue: mockAuthService }, + { provide: BootstrapService, useValue: mockBootstrapService }, { provide: ConfigService, useValue: mockConfigService }, ], }).compile(); @@ -75,7 +81,6 @@ describe("AuthController", () => { password: "password", username: "test", }; - // biome-ignore lint/suspicious/noExplicitAny: Necessary to avoid defining full DTO in test await controller.register(dto as any); expect(authService.register).toHaveBeenCalledWith(dto); }); diff --git a/backend/src/auth/auth.controller.ts b/backend/src/auth/auth.controller.ts index 43b5436..c7dd02a 100644 --- a/backend/src/auth/auth.controller.ts +++ b/backend/src/auth/auth.controller.ts @@ -1,4 +1,13 @@ -import { Body, Controller, Get, Headers, Post, Query, Req, Res } from "@nestjs/common"; +import { + Body, + Controller, + Get, + Headers, + Post, + Query, + Req, + Res, +} from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { Throttle } from "@nestjs/throttler"; import type { Request, Response } from "express"; diff --git a/backend/src/auth/bootstrap.service.spec.ts b/backend/src/auth/bootstrap.service.spec.ts index 8090a36..fda6ba6 100644 --- a/backend/src/auth/bootstrap.service.spec.ts +++ b/backend/src/auth/bootstrap.service.spec.ts @@ -1,14 +1,14 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { ConfigService } from "@nestjs/config"; import { UnauthorizedException } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { Test, TestingModule } from "@nestjs/testing"; +import { UsersService } from "../users/users.service"; import { BootstrapService } from "./bootstrap.service"; import { RbacService } from "./rbac.service"; -import { UsersService } from "../users/users.service"; describe("BootstrapService", () => { let service: BootstrapService; let rbacService: RbacService; - let usersService: UsersService; + let _usersService: UsersService; const mockRbacService = { countAdmins: jest.fn(), @@ -36,7 +36,7 @@ describe("BootstrapService", () => { service = module.get(BootstrapService); rbacService = module.get(RbacService); - usersService = module.get(UsersService); + _usersService = module.get(UsersService); }); it("should be defined", () => { @@ -46,7 +46,10 @@ describe("BootstrapService", () => { describe("onApplicationBootstrap", () => { it("should generate a token if no admin exists", async () => { mockRbacService.countAdmins.mockResolvedValue(0); - const generateTokenSpy = jest.spyOn(service as any, "generateBootstrapToken"); + const generateTokenSpy = jest.spyOn( + service as any, + "generateBootstrapToken", + ); await service.onApplicationBootstrap(); @@ -56,7 +59,10 @@ describe("BootstrapService", () => { it("should not generate a token if admin exists", async () => { mockRbacService.countAdmins.mockResolvedValue(1); - const generateTokenSpy = jest.spyOn(service as any, "generateBootstrapToken"); + const generateTokenSpy = jest.spyOn( + service as any, + "generateBootstrapToken", + ); await service.onApplicationBootstrap(); @@ -70,9 +76,9 @@ describe("BootstrapService", () => { mockRbacService.countAdmins.mockResolvedValue(0); await service.onApplicationBootstrap(); - await expect( - service.consumeToken("wrong-token", "user1"), - ).rejects.toThrow(UnauthorizedException); + await expect(service.consumeToken("wrong-token", "user1")).rejects.toThrow( + UnauthorizedException, + ); }); it("should throw UnauthorizedException if user not found", async () => { @@ -97,7 +103,10 @@ describe("BootstrapService", () => { const result = await service.consumeToken(token, "user1"); - expect(rbacService.assignRoleToUser).toHaveBeenCalledWith("user-uuid", "admin"); + expect(rbacService.assignRoleToUser).toHaveBeenCalledWith( + "user-uuid", + "admin", + ); expect((service as any).bootstrapToken).toBeNull(); expect(result.message).toContain("user1 is now an administrator"); }); diff --git a/backend/src/auth/bootstrap.service.ts b/backend/src/auth/bootstrap.service.ts index d755c55..bf7fd05 100644 --- a/backend/src/auth/bootstrap.service.ts +++ b/backend/src/auth/bootstrap.service.ts @@ -1,3 +1,4 @@ +import * as crypto from "node:crypto"; import { Injectable, Logger, @@ -5,7 +6,6 @@ import { UnauthorizedException, } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; -import * as crypto from "node:crypto"; import { UsersService } from "../users/users.service"; import { RbacService } from "./rbac.service"; @@ -34,9 +34,15 @@ export class BootstrapService implements OnApplicationBootstrap { const url = `${protocol}://${domain}/auth/bootstrap-admin`; this.logger.warn("SECURITY ALERT: No administrator found in database."); - this.logger.warn("To create the first administrator, use the following endpoint:"); - this.logger.warn(`Endpoint: GET ${url}?token=${this.bootstrapToken}&username=votre_nom_utilisateur`); - this.logger.warn("Exemple: curl -X GET \"http://localhost/auth/bootstrap-admin?token=...&username=...\""); + this.logger.warn( + "To create the first administrator, use the following endpoint:", + ); + this.logger.warn( + `Endpoint: GET ${url}?token=${this.bootstrapToken}&username=votre_nom_utilisateur`, + ); + this.logger.warn( + 'Exemple: curl -X GET "http://localhost/auth/bootstrap-admin?token=...&username=..."', + ); this.logger.warn("This token is one-time use only."); } @@ -53,7 +59,9 @@ export class BootstrapService implements OnApplicationBootstrap { await this.rbacService.assignRoleToUser(user.uuid, "admin"); this.bootstrapToken = null; // One-time use - this.logger.log(`User ${username} has been promoted to administrator via bootstrap token.`); + this.logger.log( + `User ${username} has been promoted to administrator via bootstrap token.`, + ); return { message: `User ${username} is now an administrator` }; } } diff --git a/backend/src/auth/rbac.service.ts b/backend/src/auth/rbac.service.ts index d419b29..e7350d6 100644 --- a/backend/src/auth/rbac.service.ts +++ b/backend/src/auth/rbac.service.ts @@ -18,7 +18,11 @@ export class RbacService implements OnApplicationBootstrap { if (count === 0) { this.logger.log("No roles found, seeding default roles..."); const defaultRoles = [ - { name: "Administrator", slug: "admin", description: "Full system access" }, + { + name: "Administrator", + slug: "admin", + description: "Full system access", + }, { name: "Moderator", slug: "moderator", diff --git a/backend/src/s3/s3.service.spec.ts b/backend/src/s3/s3.service.spec.ts index 4965498..c053505 100644 --- a/backend/src/s3/s3.service.spec.ts +++ b/backend/src/s3/s3.service.spec.ts @@ -8,7 +8,6 @@ jest.mock("minio"); describe("S3Service", () => { let service: S3Service; let configService: ConfigService; - // biome-ignore lint/suspicious/noExplicitAny: Fine for testing purposes let minioClient: any; beforeEach(async () => { diff --git a/frontend/package.json b/frontend/package.json index 723381a..bb99e34 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,6 +7,7 @@ "build": "next build", "start": "next start", "lint": "biome check", + "lint:write": "biome check --write", "format": "biome format --write" }, "dependencies": { diff --git a/package.json b/package.json index af5a6a7..710f2fd 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,13 @@ "build:back": "pnpm run -F @memegoat/backend build", "build:docs": "pnpm run -F @memegoat/documentation build", "lint": "pnpm run lint:back && pnpm run lint:front && pnpm run lint:docs", + "lint:fix": "pnpm run lint:back:fix && pnpm run lint:front:fix && pnpm run lint:docs:fix", "lint:back": "pnpm run -F @memegoat/backend lint", + "lint:back:fix": "pnpm run -F @memegoat/backend lint:write", "lint:front": "pnpm run -F @memegoat/frontend lint", + "lint:front:fix": "pnpm run -F @memegoat/frontend lint:write", "lint:docs": "pnpm run -F @memegoat/documentation lint", + "lint:docs:fix": "pnpm run -F @memegoat/documentation lint:write", "test": "pnpm run test:back && pnpm run test:front", "test:back": "pnpm run -F @memegoat/backend test", "test:front": "pnpm run -F @memegoat/frontend test",