From fcc9547a30b2ebc8fa3400f6533df868afacb800 Mon Sep 17 00:00:00 2001 From: Djalim Simaila Date: Sun, 26 Apr 2026 23:01:59 +0200 Subject: [PATCH] feat(dev): add compose files and dev-login bypass route - compose.prod.yml: production stack with registry image, healthcheck, migration service - compose.test.yml: local test stack with source mount and LOCAL=true - routes/dev-login.ts: fake admin JWT login, only active when LOCAL=true - routes/_middleware.ts: expose /dev-login as public route Co-Authored-By: Claude Sonnet 4.6 --- compose.prod.yml | 36 +++++++++++++++++++++++++++++++ compose.test.yml | 49 +++++++++++++++++++++++++++++++++++++++++++ routes/_middleware.ts | 1 + routes/dev-login.ts | 48 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 compose.prod.yml create mode 100644 compose.test.yml create mode 100644 routes/dev-login.ts diff --git a/compose.prod.yml b/compose.prod.yml new file mode 100644 index 0000000..6fcc5bc --- /dev/null +++ b/compose.prod.yml @@ -0,0 +1,36 @@ +services: + db: + image: postgres:17-alpine + restart: unless-stopped + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASS} + POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_DB: ${POSTGRES_DB:-polympr} + volumes: + - db_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"] + interval: 5s + timeout: 5s + retries: 10 + + migrate: + image: registry.docker.polytech.djalim.fr/polympr:latest + command: node_modules/.bin/drizzle-kit migrate + env_file: .env + depends_on: + db: + condition: service_healthy + + app: + image: registry.docker.polytech.djalim.fr/polympr:latest + restart: unless-stopped + ports: + - "4430:443" + env_file: .env + depends_on: + migrate: + condition: service_completed_successfully + +volumes: + db_data: diff --git a/compose.test.yml b/compose.test.yml new file mode 100644 index 0000000..18478d8 --- /dev/null +++ b/compose.test.yml @@ -0,0 +1,49 @@ +services: + db: + image: postgres:17-alpine + restart: unless-stopped + environment: + POSTGRES_PASSWORD: testpass + POSTGRES_USER: postgres + POSTGRES_DB: polympr_test + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 10 + + migrate: + image: denoland/deno:alpine + working_dir: /app + volumes: + - .:/app + command: task migrate + environment: + POSTGRES_HOST: db + POSTGRES_PORT: 5432 + POSTGRES_USER: postgres + POSTGRES_PASS: testpass + POSTGRES_DB: polympr_test + LOCAL: "true" + depends_on: + db: + condition: service_healthy + + app: + image: denoland/deno:alpine + working_dir: /app + volumes: + - .:/app + command: run -A --unstable-ffi main.ts + ports: + - "4430:443" + environment: + POSTGRES_HOST: db + POSTGRES_PORT: 5432 + POSTGRES_USER: postgres + POSTGRES_PASS: testpass + POSTGRES_DB: polympr_test + LOCAL: "true" + depends_on: + migrate: + condition: service_completed_successfully diff --git a/routes/_middleware.ts b/routes/_middleware.ts index 01b449e..2588e7b 100644 --- a/routes/_middleware.ts +++ b/routes/_middleware.ts @@ -10,6 +10,7 @@ const PUBLIC_ROUTES = [ "/about", "/partials/about", "/contact", + "/dev-login", ]; const jwtKeyCache: Record = {}; diff --git a/routes/dev-login.ts b/routes/dev-login.ts new file mode 100644 index 0000000..b50898e --- /dev/null +++ b/routes/dev-login.ts @@ -0,0 +1,48 @@ +import { FreshContext, Handlers } from "$fresh/server.ts"; +import { CasContent, LoginJWT, State } from "$root/defaults/interfaces.ts"; +import { createJwt } from "@popov/jwt"; +import { setCookie } from "$std/http/cookie.ts"; +import { getKey } from "$root/routes/_middleware.ts"; + +const FAKE_ADMIN: CasContent = { + amuCampus: "local", + amuComposante: "local", + amuDateValidation: "", + coGroup: "", + eduPersonPrimaryAffiliation: "employee", + eduPersonPrincipalName: "admin@local", + mail: "admin@local", + displayName: "Admin Local", + givenName: "Admin", + memberOf: [], + sn: "Local", + supannCivilite: "", + supannEntiteAffectation: "", + supannEtuAnneeInscription: "", + supannEtuEtape: "", + uid: "admin-local", +}; + +export const handler: Handlers = { + async GET(_request: Request, _context: FreshContext) { + if (Deno.env.get("LOCAL") !== "true") { + return new Response("Not available outside LOCAL mode.", { status: 403 }); + } + + const now = Math.floor(Date.now() / 1000); + const payload: LoginJWT = { + iss: "PolyMPR", + iat: now, + exp: now + 0xe10, + aud: "PolyMPR", + user: FAKE_ADMIN, + }; + + const token = await createJwt(payload, getKey(FAKE_ADMIN.uid)); + const headers = new Headers(); + setCookie(headers, { name: "sessionToken", value: token }); + headers.set("Location", "/apps"); + + return new Response(null, { status: 302, headers }); + }, +};