Merge pull request #5374 from aspatari/fix/infisical-expand-secret-references

fix(vault): expand Infisical secret references when listing secrets
This commit is contained in:
Narciso E. Núñez Arias 2026-09-08 14:08:52 -04:00 committed by GitHub
commit 887a457f15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 0 deletions

View File

@ -20,6 +20,7 @@ import {
import { azureClient } from "@dokploy/server/utils/vault/azure";
import { dopplerClient } from "@dokploy/server/utils/vault/doppler";
import { hashicorpClient } from "@dokploy/server/utils/vault/hashicorp";
import { infisicalClient } from "@dokploy/server/utils/vault/infisical";
import { phaseClient } from "@dokploy/server/utils/vault/phase";
import { scalewayClient } from "@dokploy/server/utils/vault/scaleway";
@ -431,6 +432,56 @@ describe("azure client", () => {
});
});
describe("infisical client", () => {
const config = {
providerType: "infisical" as const,
siteUrl: "https://app.infisical.com",
clientId: "client-1",
clientSecret: "client-secret",
projectId: "workspace-1",
environmentSlug: "prod",
secretPath: "/frontend",
};
const loginResponse = () => jsonResponse({ accessToken: "token-1" });
it("asks the list endpoint to expand secret references", async () => {
mockFetch.mockResolvedValueOnce(loginResponse()).mockResolvedValueOnce(
jsonResponse({
secrets: [{ secretKey: "DB_URL", secretValue: "postgres://real" }],
}),
);
const result = await infisicalClient.getSecrets(config, ["DB_URL"]);
expect(result).toEqual({ DB_URL: "postgres://real" });
const [listUrl] = mockFetch.mock.calls[1] as [string];
const params = new URL(listUrl).searchParams;
expect(params.get("expandSecretReferences")).toBe("true");
expect(params.get("workspaceId")).toBe("workspace-1");
expect(params.get("environment")).toBe("prod");
expect(params.get("secretPath")).toBe("/frontend");
});
it("throws a clear error for a missing secret", async () => {
mockFetch
.mockResolvedValueOnce(loginResponse())
.mockResolvedValueOnce(jsonResponse({ secrets: [] }));
await expect(
infisicalClient.getSecrets(config, ["ABSENT"]),
).rejects.toThrow('secret "ABSENT" not found in environment "prod"');
});
it("propagates authentication failures with the status code", async () => {
mockFetch.mockResolvedValueOnce(jsonResponse({}, false, 401));
await expect(
infisicalClient.getSecrets(config, ["DB_URL"]),
).rejects.toThrow("authentication failed (status 401)");
});
});
describe("doppler client", () => {
it("propagates auth errors with the status code", async () => {
mockFetch.mockResolvedValue(jsonResponse({}, false, 401));

View File

@ -38,6 +38,12 @@ const fetchSecrets = async (config: InfisicalConfig) => {
workspaceId: config.projectId,
environment: config.environmentSlug,
secretPath: config.secretPath,
// Infisical's list endpoint leaves secret references (`${env.folder.KEY}`)
// unexpanded unless asked, so without this a referencing secret arrives as
// the literal `${...}` string, lands in the generated .env and the deploy
// still reports success. Single secrets read via /raw/{name} expand by
// default, which makes the difference easy to miss in the UI.
expandSecretReferences: "true",
});
const response = await vaultFetch(
`${baseUrl(config)}/api/v3/secrets/raw?${params.toString()}`,