Openstatus www.openstatus.dev

fix: api depreacted regions monitor schema (#1442)

authored by

Maximilian Kaske and committed by
GitHub
d814002d 87c6a3dc

+90 -12
+28
apps/server/src/routes/v1/monitors/post.test.ts
··· 1 1 import { expect, test } from "bun:test"; 2 2 3 3 import { app } from "@/index"; 4 + import { createErrorSchema } from "@/libs/errors"; 4 5 import { MonitorSchema } from "./schema"; 5 6 6 7 test("create a valid monitor", async () => { ··· 91 92 92 93 expect(res.status).toBe(401); 93 94 }); 95 + 96 + test("create a monitor with deprecated regions should return 400", async () => { 97 + const res = await app.request("/v1/monitor", { 98 + method: "POST", 99 + headers: { 100 + "x-openstatus-key": "1", 101 + "content-type": "application/json", 102 + }, 103 + body: JSON.stringify({ 104 + regions: ["ams", "jnb", "hkg", "waw"], 105 + name: "Testing Deprecated Regions", 106 + description: "Testing Deprecated Regions", 107 + url: "https://www.openstatus.dev", 108 + method: "GET", 109 + active: true, 110 + }), 111 + }); 112 + 113 + const json = await res.json(); 114 + const errorSchema = createErrorSchema("BAD_REQUEST").safeParse(json); 115 + 116 + expect(res.status).toBe(400); 117 + expect(errorSchema.success).toBe(true); 118 + expect(errorSchema.data?.message).toMatch( 119 + "Deprecated regions are not allowed: hkg, waw", 120 + ); 121 + });
+62 -12
apps/server/src/routes/v1/monitors/schema.ts
··· 6 6 monitorPeriodicitySchema, 7 7 monitorRegions, 8 8 } from "@openstatus/db/src/schema/constants"; 9 + import { regionDict } from "@openstatus/utils"; 9 10 import { ZodError } from "zod"; 10 11 11 12 const statusAssertion = z ··· 94 95 regions: z 95 96 .preprocess( 96 97 (val) => { 97 - try { 98 - if (Array.isArray(val)) return val; 99 - if (String(val).length > 0) { 100 - return String(val).split(","); 101 - } 102 - return []; 103 - } catch (e) { 98 + let regions: Array<unknown> = []; 99 + if (Array.isArray(val)) { 100 + regions = val; 101 + } 102 + if (String(val).length > 0) { 103 + regions = String(val).split(","); 104 + } 105 + 106 + const deprecatedRegions = regions.filter((r) => { 107 + const deprecated = 108 + regionDict[r as keyof typeof regionDict].deprecated; 109 + if (deprecated) return true; 110 + return false; 111 + }); 112 + 113 + if (deprecatedRegions.length > 0) { 104 114 throw new ZodError([ 105 115 { 106 116 code: "custom", 107 - path: ["headers"], 108 - message: e instanceof Error ? e.message : "Invalid value", 117 + path: ["regions"], 118 + message: `Deprecated regions are not allowed: ${deprecatedRegions.join( 119 + ", ", 120 + )}`, 109 121 }, 110 122 ]); 111 123 } 124 + 125 + return regions; 112 126 }, 113 127 z.array(z.enum(monitorRegions)), 114 128 ) ··· 343 357 description: "Whether the monitor is public", 344 358 default: false, 345 359 }), 346 - regions: z.array(z.enum(monitorRegions)).openapi({ 347 - description: "Regions to run the request in", 348 - }), 360 + regions: z 361 + .preprocess( 362 + (val) => { 363 + let regions: Array<unknown> = []; 364 + if (Array.isArray(val)) { 365 + regions = val; 366 + } 367 + if (String(val).length > 0) { 368 + regions = String(val).split(","); 369 + } 370 + 371 + const deprecatedRegions = regions.filter((r) => { 372 + const deprecated = 373 + regionDict[r as keyof typeof regionDict].deprecated; 374 + if (deprecated) return true; 375 + return false; 376 + }); 377 + 378 + if (deprecatedRegions.length > 0) { 379 + throw new ZodError([ 380 + { 381 + code: "custom", 382 + path: ["regions"], 383 + message: `Deprecated regions are not allowed: ${deprecatedRegions.join( 384 + ", ", 385 + )}`, 386 + }, 387 + ]); 388 + } 389 + 390 + return regions; 391 + }, 392 + z.array(z.enum(monitorRegions)), 393 + ) 394 + .default([]) 395 + .openapi({ 396 + example: ["ams"], 397 + description: "Where we should monitor it", 398 + }), 349 399 openTelemetry: z 350 400 .object({ 351 401 endpoint: z