From 7335040168e64140248f7067272971fe7ffb633f Mon Sep 17 00:00:00 2001 From: Aman Ganapathy <84686202+nams1570@users.noreply.github.com> Date: Wed, 18 Mar 2026 11:19:51 -0700 Subject: [PATCH] [Fix]: Deal with Result Admin Validation Sentry Noise for TrustedDomains by Nixing Read Validation (#1264) ### Context We get a lot of noise on sentry about the result admin validation failing from the onList handler. However, we no longer care about validating reads for trustedDomains. Via config pushes, people can set them to anything anyway. There's no value in being stricter on reads than on writes. ### Summary of Changes We scope our schema changes to just the onList and read handlers for trusted domains for the most part, though relaxing the params validation also affects delete. In practice, delete needs to do an exact match to find what needs to be deleted so this is fine. Also, without relaxing it for delete, you wouldn't be able to delete a domain you had previously put in. --- .../latest/integrations/custom/domains/crud.tsx | 14 ++++++-------- .../api/latest/integrations/neon/domains/crud.tsx | 14 ++++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/apps/backend/src/app/api/latest/integrations/custom/domains/crud.tsx b/apps/backend/src/app/api/latest/integrations/custom/domains/crud.tsx index 429408fbc8..5553e2eddb 100644 --- a/apps/backend/src/app/api/latest/integrations/custom/domains/crud.tsx +++ b/apps/backend/src/app/api/latest/integrations/custom/domains/crud.tsx @@ -2,22 +2,20 @@ import { Tenancy } from "@/lib/tenancies"; import { createCrudHandlers } from "@/route-handlers/crud-handler"; import { CrudTypeOf, createCrud } from "@stackframe/stack-shared/dist/crud"; import * as schemaFields from "@stackframe/stack-shared/dist/schema-fields"; -import { yupMixed, yupObject } from "@stackframe/stack-shared/dist/schema-fields"; +import { yupMixed, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields"; import { StatusError, throwErr } from "@stackframe/stack-shared/dist/utils/errors"; import { createLazyProxy } from "@stackframe/stack-shared/dist/utils/proxies"; import { stringCompare } from "@stackframe/stack-shared/dist/utils/strings"; import { projectsCrudHandlers } from "../../../internal/projects/current/crud"; -const domainSchema = schemaFields.wildcardProtocolAndDomainSchema.max(300).defined() - .matches(/^https?:\/\//, 'URL must start with http:// or https://') - .meta({ openapiField: { description: 'URL. Must start with http:// or https://', exampleValue: 'https://example.com' } }); - const domainReadSchema = yupObject({ - domain: domainSchema.defined(), + domain: yupString().defined(), }); const domainCreateSchema = yupObject({ - domain: domainSchema.defined(), + domain: schemaFields.wildcardProtocolAndDomainSchema.max(300).defined() + .matches(/^https?:\/\//, 'URL must start with http:// or https://') + .meta({ openapiField: { description: 'URL. Must start with http:// or https://', exampleValue: 'https://example.com' } }), }); export const domainDeleteSchema = yupMixed(); @@ -53,7 +51,7 @@ function domainConfigToLegacyConfig(domain: Tenancy['config']['domains']['truste export const domainCrudHandlers = createLazyProxy(() => createCrudHandlers(domainCrud, { paramsSchema: yupObject({ - domain: domainSchema.optional(), + domain: yupString().optional(), }), onCreate: async ({ auth, data, params }) => { const oldDomains = auth.tenancy.config.domains.trustedDomains; diff --git a/apps/backend/src/app/api/latest/integrations/neon/domains/crud.tsx b/apps/backend/src/app/api/latest/integrations/neon/domains/crud.tsx index efcdf88ffe..92fd490159 100644 --- a/apps/backend/src/app/api/latest/integrations/neon/domains/crud.tsx +++ b/apps/backend/src/app/api/latest/integrations/neon/domains/crud.tsx @@ -2,22 +2,20 @@ import { Tenancy } from "@/lib/tenancies"; import { createCrudHandlers } from "@/route-handlers/crud-handler"; import { CrudTypeOf, createCrud } from "@stackframe/stack-shared/dist/crud"; import * as schemaFields from "@stackframe/stack-shared/dist/schema-fields"; -import { yupMixed, yupObject } from "@stackframe/stack-shared/dist/schema-fields"; +import { yupMixed, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields"; import { StatusError, throwErr } from "@stackframe/stack-shared/dist/utils/errors"; import { createLazyProxy } from "@stackframe/stack-shared/dist/utils/proxies"; import { stringCompare } from "@stackframe/stack-shared/dist/utils/strings"; import { projectsCrudHandlers } from "../../../internal/projects/current/crud"; -const domainSchema = schemaFields.wildcardProtocolAndDomainSchema.max(300).defined() - .matches(/^https?:\/\//, 'URL must start with http:// or https://') - .meta({ openapiField: { description: 'URL. Must start with http:// or https://', exampleValue: 'https://example.com' } }); - const domainReadSchema = yupObject({ - domain: domainSchema.defined(), + domain: yupString().defined(), }); const domainCreateSchema = yupObject({ - domain: domainSchema.defined(), + domain: schemaFields.wildcardProtocolAndDomainSchema.max(300).defined() + .matches(/^https?:\/\//, 'URL must start with http:// or https://') + .meta({ openapiField: { description: 'URL. Must start with http:// or https://', exampleValue: 'https://example.com' } }), }); export const domainDeleteSchema = yupMixed(); @@ -52,7 +50,7 @@ function domainConfigToLegacyConfig(domain: Tenancy['config']['domains']['truste export const domainCrudHandlers = createLazyProxy(() => createCrudHandlers(domainCrud, { paramsSchema: yupObject({ - domain: domainSchema.optional(), + domain: yupString().optional(), }), onCreate: async ({ auth, data, params }) => { const oldDomains = auth.tenancy.config.domains.trustedDomains;