Files
Checkmate/server/test/unit/validation/monitorValidation.test.ts
T
harsh-aghara 87a6640c1d fix(backend): validate customUpCodes against standard HTTP status codes
Addresses reviewer feedback by enforcing strict validation on the  array. Previously, the Zod schema accepted any arbitrary number, which could allow invalid or self-defined HTTP codes (e.g., 5000) to be saved to the database.

Refs #3657
2026-06-01 13:21:30 +05:30

315 lines
8.1 KiB
TypeScript

import { describe, expect, it } from "@jest/globals";
import { createMonitorBodyValidation, editMonitorBodyValidation, importMonitorsBodyValidation } from "../../../src/validation/monitorValidation.ts";
const baseDnsBody = {
name: "DNS check",
type: "dns" as const,
url: "example.com",
};
describe("monitorValidation — DNS fields", () => {
describe("createMonitorBodyValidation", () => {
it("retains dnsServer and dnsRecordType on a DNS monitor", () => {
const parsed = createMonitorBodyValidation.parse({
...baseDnsBody,
dnsServer: "8.8.8.8",
dnsRecordType: "A",
});
expect(parsed.dnsServer).toBe("8.8.8.8");
expect(parsed.dnsRecordType).toBe("A");
});
it("accepts every supported DNS record type", () => {
for (const recordType of ["A", "AAAA", "CNAME", "MX", "TXT", "NS"] as const) {
const parsed = createMonitorBodyValidation.parse({
...baseDnsBody,
dnsServer: "1.1.1.1",
dnsRecordType: recordType,
});
expect(parsed.dnsRecordType).toBe(recordType);
}
});
it("rejects unknown DNS record types", () => {
expect(() =>
createMonitorBodyValidation.parse({
...baseDnsBody,
dnsServer: "8.8.8.8",
dnsRecordType: "BOGUS",
})
).toThrow();
});
it("treats DNS fields as optional (other monitor types still validate)", () => {
const parsed = createMonitorBodyValidation.parse({
name: "HTTP check",
type: "http",
url: "https://example.com",
});
expect(parsed.dnsServer).toBeUndefined();
expect(parsed.dnsRecordType).toBeUndefined();
});
it("rejects a DNS monitor whose url has a scheme or path", () => {
for (const badUrl of ["https://example.com", "example.com/path", "example.com:53", " example.com"]) {
expect(() =>
createMonitorBodyValidation.parse({
...baseDnsBody,
url: badUrl,
dnsServer: "8.8.8.8",
dnsRecordType: "A",
})
).toThrow();
}
});
it("rejects a DNS monitor with an invalid dnsServer", () => {
expect(() =>
createMonitorBodyValidation.parse({
...baseDnsBody,
dnsServer: "not-an-ip",
dnsRecordType: "A",
})
).toThrow();
});
it("accepts service labels with leading underscore (DMARC, SRV, ACME)", () => {
for (const url of ["_dmarc.example.com", "_imaps._tcp.example.com", "_acme-challenge.example.com"]) {
const parsed = createMonitorBodyValidation.parse({
...baseDnsBody,
url,
dnsServer: "8.8.8.8",
dnsRecordType: "TXT",
});
expect(parsed.url).toBe(url);
}
});
it("does not enforce the hostname rule for non-DNS monitors", () => {
const parsed = createMonitorBodyValidation.parse({
name: "HTTP check",
type: "http",
url: "https://example.com/some/path",
});
expect(parsed.url).toBe("https://example.com/some/path");
});
});
describe("editMonitorBodyValidation", () => {
it("retains dnsServer and dnsRecordType on edits", () => {
const parsed = editMonitorBodyValidation.parse({
dnsServer: "1.1.1.1",
dnsRecordType: "MX",
});
expect(parsed.dnsServer).toBe("1.1.1.1");
expect(parsed.dnsRecordType).toBe("MX");
});
});
describe("importMonitorsBodyValidation", () => {
it("retains dnsServer and dnsRecordType on imported DNS monitors", () => {
const parsed = importMonitorsBodyValidation.parse({
monitors: [
{
name: "Imported DNS",
type: "dns",
url: "example.com",
dnsServer: "8.8.4.4",
dnsRecordType: "TXT",
},
],
});
expect(parsed.monitors[0].dnsServer).toBe("8.8.4.4");
expect(parsed.monitors[0].dnsRecordType).toBe("TXT");
});
});
});
describe("monitorValidation — strategy gating", () => {
describe("createMonitorBodyValidation", () => {
it("accepts strategy on pagespeed monitors", () => {
const parsed = createMonitorBodyValidation.parse({
name: "PS check",
type: "pagespeed",
url: "https://example.com",
strategy: "mobile",
});
expect(parsed.strategy).toBe("mobile");
});
it("accepts pagespeed monitors without a strategy", () => {
const parsed = createMonitorBodyValidation.parse({
name: "PS check",
type: "pagespeed",
url: "https://example.com",
});
expect(parsed.strategy).toBeUndefined();
});
it("rejects strategy on non-pagespeed monitor types", () => {
for (const type of ["http", "ping", "docker", "port", "game", "grpc", "websocket", "dns", "hardware"] as const) {
expect(() =>
createMonitorBodyValidation.parse({
name: "wrong-type check",
type,
url: type === "dns" ? "example.com" : "https://example.com",
strategy: "desktop",
})
).toThrow();
}
});
it("allows non-pagespeed monitors without a strategy", () => {
const parsed = createMonitorBodyValidation.parse({
name: "HTTP check",
type: "http",
url: "https://example.com",
});
expect(parsed.strategy).toBeUndefined();
});
});
describe("editMonitorBodyValidation", () => {
it("rejects strategy when type is explicitly non-pagespeed", () => {
expect(() =>
editMonitorBodyValidation.parse({
type: "http",
strategy: "mobile",
})
).toThrow();
});
it("allows strategy when type is omitted (partial edit)", () => {
const parsed = editMonitorBodyValidation.parse({
strategy: "mobile",
});
expect(parsed.strategy).toBe("mobile");
});
});
describe("importMonitorsBodyValidation", () => {
it("does not inject a default strategy on imported HTTP monitors", () => {
const parsed = importMonitorsBodyValidation.parse({
monitors: [
{
name: "Imported HTTP",
type: "http",
url: "https://example.com",
},
],
});
expect(parsed.monitors[0].strategy).toBeUndefined();
});
it("rejects strategy on imported non-pagespeed monitors", () => {
expect(() =>
importMonitorsBodyValidation.parse({
monitors: [
{
name: "Imported HTTP",
type: "http",
url: "https://example.com",
strategy: "desktop",
},
],
})
).toThrow();
});
});
});
describe("monitorValidation — customUpCodes", () => {
const baseHttpBody = {
name: "HTTP check",
type: "http" as const,
url: "https://example.com",
};
describe("createMonitorBodyValidation", () => {
it("accepts valid HTTP status codes", () => {
const parsed = createMonitorBodyValidation.parse({
...baseHttpBody,
customUpCodes: [200, 301, 404, 503],
});
expect(parsed.customUpCodes).toEqual([200, 301, 404, 503]);
});
it("rejects invalid HTTP status codes", () => {
expect(() =>
createMonitorBodyValidation.parse({
...baseHttpBody,
customUpCodes: [5000],
})
).toThrow();
expect(() =>
createMonitorBodyValidation.parse({
...baseHttpBody,
customUpCodes: [-1],
})
).toThrow();
});
it("defaults to an empty array when not provided", () => {
const parsed = createMonitorBodyValidation.parse(baseHttpBody);
expect(parsed.customUpCodes).toEqual([]);
});
});
describe("editMonitorBodyValidation", () => {
it("accepts valid HTTP status codes on edits", () => {
const parsed = editMonitorBodyValidation.parse({
customUpCodes: [200, 201],
});
expect(parsed.customUpCodes).toEqual([200, 201]);
});
it("rejects invalid HTTP status codes on edits", () => {
expect(() =>
editMonitorBodyValidation.parse({
customUpCodes: [9999],
})
).toThrow();
});
});
describe("importMonitorsBodyValidation", () => {
it("retains valid HTTP status codes on imported HTTP monitors", () => {
const parsed = importMonitorsBodyValidation.parse({
monitors: [
{
...baseHttpBody,
customUpCodes: [404],
},
],
});
expect(parsed.monitors[0].customUpCodes).toEqual([404]);
});
it("rejects invalid HTTP status codes on imported HTTP monitors", () => {
expect(() =>
importMonitorsBodyValidation.parse({
monitors: [
{
...baseHttpBody,
customUpCodes: [5000],
},
],
})
).toThrow();
});
it("defaults to an empty array when not provided on import", () => {
const parsed = importMonitorsBodyValidation.parse({
monitors: [baseHttpBody],
});
expect(parsed.monitors[0].customUpCodes).toEqual([]);
});
});
});