Skip to content

Commit 4b687f9

Browse files
committed
fix: validate shared Vercel env var response with zod at the boundary
Parse the raw GET /v1/env page with a zod schema instead of an `as` cast, so a Vercel payload-shape change fails cleanly at the boundary rather than silently degrading to empty/partial imports. Addresses a CodeRabbit review comment.
1 parent 84c8396 commit 4b687f9

1 file changed

Lines changed: 20 additions & 13 deletions

File tree

apps/webapp/app/models/vercelIntegration.server.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,24 @@ export type VercelEnvironmentVariableValue = {
198198
};
199199

200200
/** Minimal shape of a shared (team-level) env var record from `GET /v1/env`. */
201-
type RawSharedEnvVar = {
202-
id?: string;
203-
key?: string;
204-
type?: string;
205-
target?: string[] | string;
206-
value?: string;
207-
applyToAllCustomEnvironments?: boolean;
208-
};
201+
const RawSharedEnvVarSchema = z
202+
.object({
203+
id: z.string().optional(),
204+
key: z.string().optional(),
205+
type: z.string().optional(),
206+
target: z.union([z.array(z.string()), z.string()]).optional(),
207+
value: z.string().optional(),
208+
applyToAllCustomEnvironments: z.boolean().optional(),
209+
})
210+
.passthrough();
211+
212+
type RawSharedEnvVar = z.infer<typeof RawSharedEnvVarSchema>;
213+
214+
/** Page shape of `GET /v1/env` (shared env vars), validated at the boundary. */
215+
const SharedEnvPageSchema = z.object({
216+
data: z.array(RawSharedEnvVarSchema).default([]),
217+
pagination: z.object({ next: z.number().nullish() }).nullish(),
218+
});
209219

210220
/** Narrowed Vercel project type – only id and name. */
211221
export type VercelProject = Pick<ResponseBodyProjects, "id" | "name">;
@@ -620,11 +630,8 @@ export class VercelIntegrationRepository {
620630
throw error;
621631
}
622632

623-
const json = (await response.json()) as {
624-
data?: RawSharedEnvVar[];
625-
pagination?: { next?: number | null } | null;
626-
};
627-
all.push(...(json.data ?? []));
633+
const json = SharedEnvPageSchema.parse(await response.json());
634+
all.push(...json.data);
628635

629636
// `next` is a millisecond-timestamp cursor; treat 0/null/undefined as "done".
630637
const next = json.pagination?.next;

0 commit comments

Comments
 (0)