diff --git a/apps/backend/src/app/api/latest/internal/configs/crud.tsx b/apps/backend/src/app/api/latest/internal/configs/crud.tsx index d49a486fc..03ed2092e 100644 --- a/apps/backend/src/app/api/latest/internal/configs/crud.tsx +++ b/apps/backend/src/app/api/latest/internal/configs/crud.tsx @@ -7,7 +7,7 @@ export const configCrudHandlers = createLazyProxy(() => createCrudHandlers(confi paramsSchema: yupObject({}), onRead: async ({ auth }) => { return { - configString: JSON.stringify(auth.tenancy.config), + config_string: JSON.stringify(auth.tenancy.config), }; }, })); diff --git a/apps/backend/src/app/api/latest/internal/configs/overrides/crud.tsx b/apps/backend/src/app/api/latest/internal/configs/overrides/crud.tsx index ed44f9a2b..c16e35228 100644 --- a/apps/backend/src/app/api/latest/internal/configs/overrides/crud.tsx +++ b/apps/backend/src/app/api/latest/internal/configs/overrides/crud.tsx @@ -1,4 +1,4 @@ -import { getRenderedEnvironmentConfigQuery, overrideEnvironmentConfigOverride } from "@/lib/config"; +import { getRenderedEnvironmentConfigQuery, overrideEnvironmentConfigOverride, validateEnvironmentConfigOverride } from "@/lib/config"; import { globalPrismaClient, rawQuery } from "@/prisma-client"; import { createCrudHandlers } from "@/route-handlers/crud-handler"; import { configOverrideCrud } from "@stackframe/stack-shared/dist/interface/crud/config"; @@ -9,16 +9,27 @@ import { createLazyProxy } from "@stackframe/stack-shared/dist/utils/proxies"; export const configOverridesCrudHandlers = createLazyProxy(() => createCrudHandlers(configOverrideCrud, { paramsSchema: yupObject({}), onUpdate: async ({ auth, data }) => { - if (data.configOverrideString) { + if (data.config_override_string) { let parsedConfig; try { - parsedConfig = JSON.parse(data.configOverrideString); + parsedConfig = JSON.parse(data.config_override_string); } catch (e) { if (e instanceof SyntaxError) { throw new StatusError(StatusError.BadRequest, 'Invalid config JSON'); } throw e; } + + const validationResult = await validateEnvironmentConfigOverride({ + environmentConfigOverride: parsedConfig, + branchId: auth.tenancy.branchId, + projectId: auth.tenancy.project.id, + }); + + if (validationResult.status === "error") { + throw new StatusError(StatusError.BadRequest, validationResult.error); + } + await overrideEnvironmentConfigOverride({ projectId: auth.tenancy.project.id, branchId: auth.tenancy.branchId, @@ -32,7 +43,7 @@ export const configOverridesCrudHandlers = createLazyProxy(() => createCrudHandl })); return { - configOverrideString: JSON.stringify(updatedConfig), + config_override_string: JSON.stringify(updatedConfig), }; }, })); diff --git a/apps/e2e/tests/backend/endpoints/api/v1/internal/config-overrides.test.ts b/apps/e2e/tests/backend/endpoints/api/v1/internal/config-overrides.test.ts index e06067013..1e4a9e27f 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/internal/config-overrides.test.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/internal/config-overrides.test.ts @@ -339,14 +339,14 @@ it("returns an error when the oauth config is misconfigured", async ({ expect }) }); // Test invalid OAuth provider type - const invalidTypeResponse = await niceBackendFetch("/api/v1/internal/config-overrides", { + const invalidTypeResponse = await niceBackendFetch("/api/v1/internal/configs/overrides", { method: "PATCH", accessType: "admin", headers: { 'x-stack-admin-access-token': adminAccessToken, }, body: { - config: JSON.stringify({ + config_override_string: JSON.stringify({ 'auth.oauth.providers.invalid': { type: 'invalid-provider', isShared: false, @@ -359,43 +359,13 @@ it("returns an error when the oauth config is misconfigured", async ({ expect }) }, }); - expect(invalidTypeResponse.status).toBe(400); - - // Test missing required fields for non-shared provider - const missingFieldsResponse = await niceBackendFetch("/api/v1/internal/config-overrides", { - method: "PATCH", - accessType: "admin", - headers: { - 'x-stack-admin-access-token': adminAccessToken, - }, - body: { - config: JSON.stringify({ - 'auth.oauth.providers.google': { - type: 'google', - isShared: false, - allowSignIn: true, - allowConnectedAccounts: true, - // Missing clientId and clientSecret - }, - }), - }, - }); - - expect(missingFieldsResponse.status).toBe(400); - - // Test invalid JSON - const invalidJsonResponse = await niceBackendFetch("/api/v1/internal/config-overrides", { - method: "PATCH", - accessType: "admin", - headers: { - 'x-stack-admin-access-token': adminAccessToken, - }, - body: { - config: "invalid json", - }, - }); - - expect(invalidJsonResponse.status).toBe(400); + expect(invalidTypeResponse).toMatchInlineSnapshot(` + NiceResponse { + "status": 400, + "body": "[ERROR] auth.oauth.providers.invalid.type must be one of the following values: google, github, microsoft, spotify, facebook, discord, gitlab, bitbucket, linkedin, apple, x, twitch", + "headers": Headers {