diff --git a/packages/builder/vite.config.mjs b/packages/builder/vite.config.mjs index a84fba2dae..f5ff388952 100644 --- a/packages/builder/vite.config.mjs +++ b/packages/builder/vite.config.mjs @@ -79,7 +79,7 @@ export default defineConfig(({ mode }) => { "process.env.POSTHOG_TOKEN": JSON.stringify(process.env.POSTHOG_TOKEN), }), copyFonts("fonts"), - ...(isProduction ? [] : devOnlyPlugins), + ...(isProduction ? [] : devOnlyPlugins), ], optimizeDeps: { exclude: ["@roxi/routify", "fsevents"], diff --git a/packages/server/src/migrations/functions/backfill/global/configs.ts b/packages/server/src/migrations/functions/backfill/global/configs.ts index bb0781eba3..04eb9caff2 100644 --- a/packages/server/src/migrations/functions/backfill/global/configs.ts +++ b/packages/server/src/migrations/functions/backfill/global/configs.ts @@ -15,12 +15,11 @@ import { } from "@budibase/types" import env from "./../../../../environment" -export function getConfigParams(type?: ConfigType): DatabaseQueryOpts { - const configType = type || "" +export function getConfigParams(): DatabaseQueryOpts { return { include_docs: true, - startkey: `${DocumentType.CONFIG}${SEPARATOR}${configType}`, - endkey: `${DocumentType.CONFIG}${SEPARATOR}${configType}${UNICODE_MAX}`, + startkey: `${DocumentType.CONFIG}${SEPARATOR}`, + endkey: `${DocumentType.CONFIG}${SEPARATOR}${UNICODE_MAX}`, } } diff --git a/packages/worker/src/api/controllers/global/configs.ts b/packages/worker/src/api/controllers/global/configs.ts index 087feede3c..4a19168c4f 100644 --- a/packages/worker/src/api/controllers/global/configs.ts +++ b/packages/worker/src/api/controllers/global/configs.ts @@ -199,7 +199,7 @@ async function verifyOIDCConfig(config: OIDCConfigs) { await verifySSOConfig(ConfigType.OIDC, config.configs[0]) } -async function verifyAIConfig(config: AIConfig, existingConfig?: AIConfig) { +export async function verifyAIConfig(config: AIConfig, existingConfig?: AIConfig) { if (!existingConfig) return // ensure that the redacted API keys are not overwritten in the DB diff --git a/packages/worker/src/api/controllers/global/tests/configs.spec.ts b/packages/worker/src/api/controllers/global/tests/configs.spec.ts new file mode 100644 index 0000000000..1a1d78757d --- /dev/null +++ b/packages/worker/src/api/controllers/global/tests/configs.spec.ts @@ -0,0 +1,76 @@ +import { TestConfiguration, structures } from "../../../../tests" +import { constants, configs } from "@budibase/backend-core" +import { AIConfig, UserCtx } from "@budibase/types" +import { find, verifyAIConfig } from "../configs" + +jest.mock("@budibase/backend-core", () => ({ + ...jest.requireActual("@budibase/backend-core"), + configs: { + getConfig: jest.fn(), + save: jest.fn() + }, +})) + +describe("Global configs controller", () => { + it("Should strip secrets when pulling AI config", async () => { + configs.getConfig.mockResolvedValue({ + config: { + ai: { + apiKey: "abc123APIKey", + baseUrl: "https://api.example.com", + } + } + }) + const ctx = { + params: { + type: "ai" + }, + throw: jest.fn() + } as UserCtx + + await find(ctx) + + expect(ctx.body).toEqual({ + config: { + ai: { + apiKey: "--secret-value--", + "baseUrl": "https://api.example.com" + } + } + }) + }) + + it("Should not update existing secrets when updating an existing AI Config", async () => { + const newConfig = { + type: "ai", + config: { + aiconfig: { + provider: "OpenAI", + isDefault: true, + name: "MyConfig", + active: true, + defaultModel: "gpt4", + apiKey: "--secret-value--" + } + } + } + + const existingConfig = { + type: "ai", + config: { + aiconfig: { + provider: "OpenAI", + isDefault: true, + name: "MyConfig", + active: true, + defaultModel: "gpt4", + apiKey: "myapikey" + } + } + } + + await verifyAIConfig(newConfig, existingConfig) + // should be unchanged + expect(newConfig.config.aiconfig.apiKey === "myapikey") + }) +})