Skip to content

Commit 9295cc7

Browse files
authored
feat: add feature flags (#1205)
## Ticket(s) lié(s) <!-- If you have a Jira Ticket / Sentry Ticket / GitHub Issue --> ## Description Mise en place du mécanisme de feature flags (FF) en base de données. - Récupération des Feature flags lors du login (dans le profile utilisateur) - Déplacement des tests unitaires de login vers les tests d'intégrations ## Screenshot / liens loom ## Check-list - [ ] Ma branche est rebase sur main - [ ] Des tests ont été écrits pour tous les endpoints créés ou modifiés - [ ] Refacto "à la volée" des parties sur lesquelles j'ai codée - [ ] Plus de `console.log` - [ ] J'ai ajouté une validation de schéma sur la route que j'ai ajouté ou modifié - [ ] J'ai converti les fichiers vue en `<script lang="ts">` - [ ] Mon code est en Typescript (autant que possible) **Testing instructions** <!-- Explain how another dev can test this PR. Create a workflow using checkboxes to explain how to run your code and the expected outputs: ${{ Test the following }} - [x] ${{ QA Scenario 1 }} - [x] ${{ QA Scenario 2 }} - [x] ${{ QA Scenario 3 }} -->
2 parents 1fdb8f8 + 5489a2c commit 9295cc7

33 files changed

Lines changed: 1252 additions & 942 deletions

.npmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# pnpm (workspace-wide)
22
# Supply-chain hardening: avoid installing packages that are too fresh
3-
minimum-release-age=103680
3+
minimum-release-age=40000
44
# Ensure monorepo workspace packages are linked instead of fetched from the registry
55
link-workspace-packages=true
66
prefer-workspace-packages=true

.talismanrc

Lines changed: 391 additions & 383 deletions
Large diffs are not rendered by default.

packages/backend/jest.setup.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@ process.env.PG_VAO_CIPHER_DATA =
1515
process.env.S3_BUCKET_NAME = "vao";
1616

1717
process.env.DEBUG = "*warn*";
18+
process.env.TOKEN_SECRET_FO = "test";
19+
process.env.TOKEN_SECRET_BO = "test";
20+
process.env.TOKEN_SECRET = "test";
21+
process.env.TOKEN_SECRET_LINK = "test";

packages/backend/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"test:debug": "corepack pnpm rebuild @sentry/profiling-node && jest --config=jest.config.js --debug --detectOpenHandles",
1414
"test:watch": "corepack pnpm rebuild @sentry/profiling-node && jest --config=jest.config.js --watch",
1515
"test:coverage": "corepack pnpm rebuild @sentry/profiling-node && jest --config=jest.config.js --coverage",
16-
"build": "tsc -b ./tsconfig.json"
16+
"build": "tsc -b ./tsconfig.json",
17+
"typecheck": "tsc --noEmit"
1718
},
1819
"lint-staged": {
1920
"src/**/*.{js,ts}": "corepack pnpm exec eslint"
@@ -22,6 +23,7 @@
2223
"@aws-sdk/client-s3": "^3.649.0",
2324
"@sentry/node": "^8.49.0",
2425
"@sentry/profiling-node": "^8.49.0",
26+
"@types/supertest": "^6.0.2",
2527
"@vao/shared-bridge": "workspace:^",
2628
"axios": "^1.7.4",
2729
"body-parser": "~1.20.3",

packages/backend/src/__tests__/admin/accept-cgu.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import request from "supertest";
33

44
import app from "../../app";
55
import config from "../../config";
6-
// @ts-expect-error js file
6+
// @ts-expect-error: js file
77
import jwtMiddleware from "../../middlewares/bo-check-JWT-without-CGU";
88
import { createAdminUserValide } from "../helper/fixtures/userHelper";
99
import {
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { ERRORS_LOGIN } from "@vao/shared-bridge";
2+
import crypto from "crypto";
3+
import request from "supertest";
4+
5+
import app from "../../app";
6+
import config from "../../config";
7+
import { UsersRepository as AdminUsersRepository } from "../../repositories/admin/Users";
8+
import {
9+
createTestContainer,
10+
removeTestContainer,
11+
} from "../helper/testContainer";
12+
13+
beforeAll(async () => {
14+
await createTestContainer();
15+
16+
config.tokenSecret_BO = crypto.randomBytes(32).toString("hex");
17+
config.algorithm = "HS256";
18+
config.accessToken.expiresIn = 60000;
19+
config.refreshToken.expiresIn = 120000;
20+
});
21+
22+
afterAll(async () => {
23+
await removeTestContainer();
24+
});
25+
26+
describe("POST /bo-authentication/email/login", () => {
27+
it("should login a validated admin user and set BO cookies", async () => {
28+
const password = "HelloHello1!!";
29+
const timestamp = Date.now();
30+
const email = `bologin${timestamp}@example.com`;
31+
32+
const { user: createdUsers } = await AdminUsersRepository.create({
33+
user: {
34+
cgu_accepted: true,
35+
cgu_accepted_at: new Date(),
36+
deleted: false,
37+
email,
38+
nom: "BoNom",
39+
password,
40+
prenom: "BoPrenom",
41+
ter_code: "FRA",
42+
validated: true,
43+
},
44+
});
45+
46+
expect(createdUsers[0]).toBeDefined();
47+
48+
const response = await request(app)
49+
.post("/bo-authentication/email/login")
50+
.send({ email, password });
51+
52+
expect(response.status).toBe(200);
53+
expect(response.body.user).toBeDefined();
54+
expect(response.body.user.email).toBe(email);
55+
expect(response.body.user.featureFlags).toBeDefined();
56+
57+
const setCookieHeader = response.headers["set-cookie"] || [];
58+
expect(setCookieHeader).toEqual(
59+
expect.arrayContaining([
60+
expect.stringContaining("VAO_BO_access_token="),
61+
expect.stringContaining("VAO_BO_refresh_token="),
62+
]),
63+
);
64+
});
65+
66+
it("should return 404 when admin user does not exist", async () => {
67+
const password = "SomePassword1!!";
68+
const timestamp = Date.now();
69+
const email = `bo-login-not-found-${timestamp}@example.com`;
70+
71+
const response = await request(app)
72+
.post("/bo-authentication/email/login")
73+
.send({ email, password });
74+
75+
expect(response.status).toBe(404);
76+
expect(response.body.name).toBe(ERRORS_LOGIN.WrongCredentials);
77+
});
78+
79+
it("should return 400 when payload is invalid", async () => {
80+
const timestamp = Date.now();
81+
const email = `bo-login-bad-payload-${timestamp}@example.com`;
82+
83+
const response = await request(app)
84+
.post("/bo-authentication/email/login")
85+
// missing password
86+
.send({ email });
87+
88+
expect(response.status).toBe(400);
89+
expect(response.body.name).toBe("AppError");
90+
});
91+
});

packages/backend/src/__tests__/admin/herbergement.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { NextFunction } from "express";
1+
import { UserDto } from "@vao/shared-bridge";
2+
import { NextFunction, Response } from "express";
23
import request from "supertest";
34

45
import app from "../../app";
@@ -14,8 +15,8 @@ import {
1415
let authUser = { id: 1, role: "admin" };
1516

1617
jest.mock("../../middlewares/common/checkJWT", () => {
17-
return async (req: UserRequest, _res: Response, next: NextFunction) => {
18-
req.decoded = authUser as any;
18+
return async (req: UserRequest, res: Response, next: NextFunction) => {
19+
req.decoded = authUser as unknown as UserDto;
1920
next();
2021
};
2122
});

packages/backend/src/__tests__/helper/fixtures/userHelper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const createUsagersUser = async (user = {}) => {
2626
terCode: "FRA",
2727
...user,
2828
};
29-
const result = await createFrontUserService(fixture);
29+
const result = await createFrontUserService(fixture as any);
3030
return result.user;
3131
};
3232

packages/backend/src/__tests__/usagers/accept-cgu.test.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
// import { statusUserFront } from "@vao/shared-bridge";
2-
import crypto from "crypto";
31
import request from "supertest";
42

53
import app from "../../app";
6-
import config from "../../config";
7-
// @ts-expect-error js file
4+
// @ts-expect-error: js file
85
import jwtMiddleware from "../../middlewares/checkJWTWithoutCGU";
96
import { createUsagersUserValide } from "../helper/fixtures/userHelper";
107
import {
@@ -16,16 +13,10 @@ const mockJwtMiddleware = jwtMiddleware as jest.Mock;
1613
jest.mock("../../middlewares/checkJWTWithoutCGU", () => jest.fn());
1714

1815
let user: any;
19-
// const userFixtureComplement = {
20-
// cgu_accepted: false,
21-
// status_code: statusUserFront.VALIDATED,
22-
// };
2316

2417
beforeAll(async () => {
2518
await createTestContainer();
2619
user = await createUsagersUserValide();
27-
// Surcharger la clé secrète pour les tests car elle est défini par environnement
28-
config.tokenSecret_FO = crypto.randomBytes(32).toString("hex");
2920
});
3021

3122
beforeEach(() => {

0 commit comments

Comments
 (0)