diff --git a/server/_core/env.ts b/server/_core/env.ts index c2f52fc..f4dfcca 100644 --- a/server/_core/env.ts +++ b/server/_core/env.ts @@ -10,6 +10,12 @@ export function readSecretFile(path: string | undefined): string { } } +/** Préfère un secret explicite, puis le secret Docker si la variable est absente ou vide. */ +export function resolveServerSecret(value: string | undefined, secretPath: string | undefined): string { + const environmentValue = value?.trim(); + return environmentValue || readSecretFile(secretPath); +} + export const ENV = { appId: process.env.VITE_APP_ID ?? "", cookieSecret: process.env.JWT_SECRET ?? "", @@ -22,5 +28,8 @@ export const ENV = { mistralApiKey: process.env.MISTRAL_API_KEY ?? "", geminiApiKey: process.env.GEMINI_API_KEY ?? "", referentielIaUrl: process.env.REFERENTIEL_IA_URL ?? "", - referentielIaToken: process.env.REFERENTIEL_IA_TOKEN ?? readSecretFile(process.env.REFERENTIEL_IA_TOKEN_FILE), + referentielIaToken: resolveServerSecret( + process.env.REFERENTIEL_IA_TOKEN, + process.env.REFERENTIEL_IA_TOKEN_FILE, + ), }; diff --git a/server/referentialIa.test.ts b/server/referentialIa.test.ts index 27d0469..0e66a35 100644 --- a/server/referentialIa.test.ts +++ b/server/referentialIa.test.ts @@ -7,7 +7,7 @@ import { testReferentialIaConnection, type ReferentielIaConnection, } from "./referentialIa"; -import { readSecretFile } from "./_core/env"; +import { readSecretFile, resolveServerSecret } from "./_core/env"; const connection: ReferentielIaConnection = { baseUrl: "https://referentiel-ia.recette.santinova-soft.org", @@ -34,6 +34,20 @@ describe("Référentiel IA", () => { } }); + it("utilise le secret monté lorsque la variable d'environnement est vide", () => { + const directory = mkdtempSync(join(tmpdir(), "referentiel-ia-")); + const secretFile = join(directory, "token"); + try { + writeFileSync(secretFile, " mounted-secret\n", { mode: 0o600 }); + + expect(resolveServerSecret("", secretFile)).toBe("mounted-secret"); + expect(resolveServerSecret(" ", secretFile)).toBe("mounted-secret"); + expect(resolveServerSecret("environment-secret", secretFile)).toBe("environment-secret"); + } finally { + rmSync(directory, { recursive: true, force: true }); + } + }); + it("transmet une requête OpenAI-compatible à la passerelle sélectionnée", async () => { let receivedUrl = ""; let receivedInit: RequestInit | undefined; diff --git a/todo.md b/todo.md index 02f825e..cd3d87a 100644 --- a/todo.md +++ b/todo.md @@ -9,6 +9,11 @@ - [x] Vérifier une invocation contrôlée via la passerelle sans utiliser de document métier - [ ] Vérifier une extraction réelle via la passerelle et sa traçabilité dans le Référentiel IA +## Correction connexion Référentiel IA — recette — 02/10/2026 +- [x] Identifier le repli bloqué par une variable de jeton vide dans le conteneur +- [x] Corriger la lecture du secret Docker lorsqu’une variable vide est présente +- [ ] Valider et déployer le correctif en recette sans toucher à MySQL ni au volume PDF + ## Import manuel des connecteurs web — 30/09/2026 - [x] Analyser le flux serveur d’import web et définir le déclenchement manuel sécurisé - [x] Ajouter l’API de déclenchement, le suivi de résultat et le bouton avec confirmation