From 294f4077f02c8f160a9622d1132314d5994dd940 Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev Date: Mon, 9 Mar 2026 10:00:33 +0700 Subject: [PATCH] Add Infisical secret loading at startup --- Dockerfile | 7 +++++-- scripts/load-secrets.mjs | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 scripts/load-secrets.mjs diff --git a/Dockerfile b/Dockerfile index 70efdb2..81f159c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,10 +14,13 @@ FROM node:22-alpine WORKDIR /app COPY package.json ./ -RUN npm install --omit=dev +RUN npm install --omit=dev && npm install @infisical/sdk COPY --from=builder /app/dist ./dist +COPY scripts ./scripts + +ENV INFISICAL_SECRET_PATHS="/geo,/shared" EXPOSE 8000 -CMD ["node", "dist/index.js"] +CMD ["sh", "-c", "node scripts/load-secrets.mjs && . ./.env.infisical && node dist/index.js"] diff --git a/scripts/load-secrets.mjs b/scripts/load-secrets.mjs new file mode 100644 index 0000000..ed43069 --- /dev/null +++ b/scripts/load-secrets.mjs @@ -0,0 +1,44 @@ +import { InfisicalSDK } from "@infisical/sdk"; +import { writeFileSync } from "fs"; + +const INFISICAL_API_URL = process.env.INFISICAL_API_URL; +const INFISICAL_CLIENT_ID = process.env.INFISICAL_CLIENT_ID; +const INFISICAL_CLIENT_SECRET = process.env.INFISICAL_CLIENT_SECRET; +const INFISICAL_PROJECT_ID = process.env.INFISICAL_PROJECT_ID; +const INFISICAL_ENV = process.env.INFISICAL_ENV || "prod"; +const SECRET_PATHS = (process.env.INFISICAL_SECRET_PATHS || "/shared").split(","); + +if (!INFISICAL_API_URL || !INFISICAL_CLIENT_ID || !INFISICAL_CLIENT_SECRET || !INFISICAL_PROJECT_ID) { + process.stderr.write("Missing required Infisical environment variables\n"); + process.exit(1); +} + +const client = new InfisicalSDK({ siteUrl: INFISICAL_API_URL }); + +await client.auth().universalAuth.login({ + clientId: INFISICAL_CLIENT_ID, + clientSecret: INFISICAL_CLIENT_SECRET, +}); + +process.stderr.write(`Loading secrets from Infisical (env: ${INFISICAL_ENV})...\n`); + +const envLines = []; + +for (const secretPath of SECRET_PATHS) { + const response = await client.secrets().listSecrets({ + projectId: INFISICAL_PROJECT_ID, + environment: INFISICAL_ENV, + secretPath: secretPath.trim(), + expandSecretReferences: true, + }); + + for (const secret of response.secrets) { + const escapedValue = secret.secretValue.replace(/'/g, "'\\''"); + envLines.push(`export ${secret.secretKey}='${escapedValue}'`); + } + + process.stderr.write(` ${secretPath.trim()}: ${response.secrets.length} secrets loaded\n`); +} + +writeFileSync(".env.infisical", envLines.join("\n")); +process.stderr.write("Secrets written to .env.infisical\n");