STET

agent_patch

runs/2026-02-27__21-30-28__gpt-5-1-codex-mini/flux-pr-3820/flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/agent-logs/agent.patch

15234 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/README.md b/app/README.md
index 3cf25ab..f4e8d12 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/README.md
+++ b/app/README.md
@@ -777,6 +777,7 @@ z.string().startsWith(string);
 z.string().endsWith(string);
 z.string().datetime(); // ISO 8601; by default only `Z` timezone allowed
 z.string().ip(); // defaults to allow both IPv4 and IPv6
+z.string().cidr(); // accepts IPv4 or IPv6 with prefix length (CIDR notation)
 
 // transforms
 z.string().trim(); // trim whitespace
@@ -921,6 +922,27 @@ ipv4.parse("84d5:51a0:9114:1855:4cfa:f2d7:1f12:7003"); // fail
 
 const ipv6 = z.string().ip({ version: "v6" });
 ipv6.parse("192.168.1.1"); // fail
+
+### CIDR ranges
+
+The `z.string().cidr()` method validates IPv4 or IPv6 addresses that include a CIDR prefix length. The prefix must be between 0 and 32 for IPv4 networks, and between 0 and 128 for IPv6 networks.
+
+```ts
+const network = z.string().cidr();
+
+network.parse("192.168.0.0/16"); // pass
+network.parse("2001:db8::/32"); // pass
+
+network.parse("192.168.0.0"); // fail (missing prefix length)
+network.parse("2001:db8::/129"); // fail (prefix length out of range)
+```
+
+You can restrict the expected IP version just like `z.string().ip()`:
+
+```ts
+const ipv4Network = z.string().cidr({ version: "v4" });
+const ipv6Network = z.string().cidr({ version: "v6" });
+```
 ```
 
 ## Numbers
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/README_ZH.md b/app/README_ZH.md
index 09bf6b1..d77f871 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/README_ZH.md
+++ b/app/README_ZH.md
@@ -475,6 +475,7 @@ z.string().startsWith(string);
 z.string().endsWith(string);
 z.string().datetime(); // ISO 8601;默认值为无 UTC 偏移,选项见下文
 z.string().ip(); // 默认为 IPv4 和 IPv6,选项见下文
+z.string().cidr(); // 验证带前缀长度的 IPv4 或 IPv6(CIDR 表示法)
 
 // 转变
 z.string().trim(); // 减除空白
@@ -570,6 +571,27 @@ const ipv6 = z.string().ip({ version: "v6" });
 ipv6.parse("192.168.1.1"); // fail
 ```
 
+### CIDR 网段
+
+`z.string().cidr()` 用于验证包含前缀的 IPv4 或 IPv6 地址。IPv4 前缀必须在 0 到 32 之间,IPv6 前缀必须在 0 到 128 之间。
+
+```ts
+const network = z.string().cidr();
+
+network.parse("192.168.0.0/16"); // pass
+network.parse("2001:db8::/32"); // pass
+
+network.parse("192.168.0.0"); // fail(缺少前缀)
+network.parse("2001:db8::/129"); // fail(前缀超出范围)
+```
+
+你也可以像 `z.string().ip()` 一样限制 IP 版本:
+
+```ts
+const ipv4Network = z.string().cidr({ version: "v4" });
+const ipv6Network = z.string().cidr({ version: "v6" });
+```
+
 ## Numbers
 
 在创建数字模式时,你可以自定义某些错误信息
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/deno/lib/README.md b/app/deno/lib/README.md
index a3c8886..02e9bd6 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/deno/lib/README.md
+++ b/app/deno/lib/README.md
@@ -787,6 +787,7 @@ z.string().startsWith(string);
 z.string().endsWith(string);
 z.string().datetime(); // ISO 8601; by default only `Z` timezone allowed
 z.string().ip(); // defaults to allow both IPv4 and IPv6
+z.string().cidr(); // accepts IPv4 or IPv6 with prefix length (CIDR notation)
 
 // transforms
 z.string().trim(); // trim whitespace
@@ -933,6 +934,27 @@ const ipv6 = z.string().ip({ version: "v6" });
 ipv6.parse("192.168.1.1"); // fail
 ```
 
+### CIDR ranges
+
+The `z.string().cidr()` method validates IPv4 or IPv6 addresses with a CIDR prefix length. IPv4 prefixes must be between 0 and 32, and IPv6 prefixes must be between 0 and 128.
+
+```ts
+const network = z.string().cidr();
+
+network.parse("192.168.0.0/16"); // pass
+network.parse("2001:db8::/32"); // pass
+
+network.parse("192.168.0.0"); // fail (missing prefix length)
+network.parse("2001:db8::/129"); // fail (prefix length out of range)
+```
+
+You can restrict the IP version just like `z.string().ip()`:
+
+```ts
+const ipv4Network = z.string().cidr({ version: "v4" });
+const ipv6Network = z.string().cidr({ version: "v6" });
+```
+
 ## Numbers
 
 You can customize certain error messages when creating a number schema.
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/deno/lib/ZodError.ts b/app/deno/lib/ZodError.ts
index e757cd8..21ad657 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/deno/lib/ZodError.ts
+++ b/app/deno/lib/ZodError.ts
@@ -103,6 +103,7 @@ export type StringValidation =
   | "time"
   | "duration"
   | "ip"
+  | "cidr"
   | "base64"
   | { includes: string; position?: number }
   | { startsWith: string }
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/deno/lib/__tests__/string.test.ts b/app/deno/lib/__tests__/string.test.ts
index 6443871..b539f36 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/deno/lib/__tests__/string.test.ts
+++ b/app/deno/lib/__tests__/string.test.ts
@@ -763,9 +763,31 @@ test("IP validation", () => {
     "1.1.1",
   ];
   // no parameters check IPv4 or IPv6
-  const ipSchema = z.string().ip();
-  expect(validIPs.every((ip) => ipSchema.safeParse(ip).success)).toBe(true);
-  expect(
-    invalidIPs.every((ip) => ipSchema.safeParse(ip).success === false)
-  ).toBe(true);
+const ipSchema = z.string().ip();
+expect(validIPs.every((ip) => ipSchema.safeParse(ip).success)).toBe(true);
+expect(
+  invalidIPs.every((ip) => ipSchema.safeParse(ip).success === false)
+).toBe(true);
+});
+
+test("CIDR validation", () => {
+  const cidr = z.string().cidr();
+  const validRanges = ["192.168.0.0/16", "2001:db8::/32"];
+  const invalidRanges = ["192.168.0.0", "2001:db8::", "256.0.0.0/24", "2001::/129", "2001::/foo"];
+
+  for (const range of validRanges) {
+    expect(cidr.safeParse(range).success).toBe(true);
+  }
+
+  for (const range of invalidRanges) {
+    expect(cidr.safeParse(range).success).toBe(false);
+  }
+
+  const ipv4Cidr = z.string().cidr({ version: "v4" });
+  expect(ipv4Cidr.safeParse("192.168.0.0/16").success).toBe(true);
+  expect(ipv4Cidr.safeParse("2001:db8::/32").success).toBe(false);
+
+  const ipv6Cidr = z.string().cidr({ version: "v6" });
+  expect(ipv6Cidr.safeParse("2001:db8::/32").success).toBe(true);
+  expect(ipv6Cidr.safeParse("192.168.0.0/16").success).toBe(false);
 });
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/deno/lib/types.ts b/app/deno/lib/types.ts
index 9cee39a..6a4390f 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/deno/lib/types.ts
+++ b/app/deno/lib/types.ts
@@ -565,6 +565,7 @@ export type ZodStringCheck =
     }
   | { kind: "duration"; message?: string }
   | { kind: "ip"; version?: IpVersion; message?: string }
+  | { kind: "cidr"; version?: IpVersion; message?: string }
   | { kind: "base64"; message?: string };
 
 export interface ZodStringDef extends ZodTypeDef {
@@ -660,15 +661,37 @@ export function datetimeRegex(args: {
   return new RegExp(`^${regex}$`);
 }
 
+function getIpVersion(ip: string): IpVersion | undefined {
+  if (ipv4Regex.test(ip)) return "v4";
+  if (ipv6Regex.test(ip)) return "v6";
+  return undefined;
+}
+
 function isValidIP(ip: string, version?: IpVersion) {
-  if ((version === "v4" || !version) && ipv4Regex.test(ip)) {
-    return true;
-  }
-  if ((version === "v6" || !version) && ipv6Regex.test(ip)) {
-    return true;
+  const detectedVersion = getIpVersion(ip);
+  if (!detectedVersion) return false;
+  if (version && version !== detectedVersion) return false;
+  return true;
+}
+
+function isValidCIDR(value: string, version?: IpVersion) {
+  const [address, prefix, ...rest] = value.split("/");
+  if (rest.length || !address || !prefix) return false;
+  if (!/^[0-9]+$/.test(prefix)) return false;
+
+  const prefixLen = Number(prefix);
+  if (!Number.isFinite(prefixLen) || !Number.isInteger(prefixLen)) {
+    return false;
   }
 
-  return false;
+  const detectedVersion = getIpVersion(address);
+  if (!detectedVersion) return false;
+  if (version && detectedVersion !== version) return false;
+
+  const maxPrefix = detectedVersion === "v4" ? 32 : 128;
+  if (prefixLen < 0 || prefixLen > maxPrefix) return false;
+
+  return true;
 }
 
 export class ZodString extends ZodType<string, ZodStringDef, string> {
@@ -923,6 +946,16 @@ export class ZodString extends ZodType<string, ZodStringDef, string> {
           });
           status.dirty();
         }
+      } else if (check.kind === "cidr") {
+        if (!isValidCIDR(input.data, check.version)) {
+          ctx = this._getOrReturnCtx(input, ctx);
+          addIssueToContext(ctx, {
+            validation: "cidr",
+            code: ZodIssueCode.invalid_string,
+            message: check.message,
+          });
+          status.dirty();
+        }
       } else if (check.kind === "ip") {
         if (!isValidIP(input.data, check.version)) {
           ctx = this._getOrReturnCtx(input, ctx);
@@ -1006,6 +1039,10 @@ export class ZodString extends ZodType<string, ZodStringDef, string> {
     return this._addCheck({ kind: "ip", ...errorUtil.errToObj(options) });
   }
 
+  cidr(options?: string | { version?: IpVersion; message?: string }) {
+    return this._addCheck({ kind: "cidr", ...errorUtil.errToObj(options) });
+  }
+
   datetime(
     options?:
       | string
@@ -1199,6 +1236,9 @@ export class ZodString extends ZodType<string, ZodStringDef, string> {
   get isIP() {
     return !!this._def.checks.find((ch) => ch.kind === "ip");
   }
+  get isCIDR() {
+    return !!this._def.checks.find((ch) => ch.kind === "cidr");
+  }
   get isBase64() {
     return !!this._def.checks.find((ch) => ch.kind === "base64");
   }
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/src/ZodError.ts b/app/src/ZodError.ts
index c1f7aa3..6e0da79 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/src/ZodError.ts
+++ b/app/src/ZodError.ts
@@ -103,6 +103,7 @@ export type StringValidation =
   | "time"
   | "duration"
   | "ip"
+  | "cidr"
   | "base64"
   | { includes: string; position?: number }
   | { startsWith: string }
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/src/__tests__/string.test.ts b/app/src/__tests__/string.test.ts
index f7037fc..78671ca 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/src/__tests__/string.test.ts
+++ b/app/src/__tests__/string.test.ts
@@ -768,3 +768,25 @@ test("IP validation", () => {
     invalidIPs.every((ip) => ipSchema.safeParse(ip).success === false)
   ).toBe(true);
 });
+
+test("CIDR validation", () => {
+  const cidr = z.string().cidr();
+  const validRanges = ["192.168.0.0/16", "2001:db8::/32"];
+  const invalidRanges = ["192.168.0.0", "2001:db8::", "256.0.0.0/24", "2001::/129", "2001::/foo"];
+
+  for (const range of validRanges) {
+    expect(cidr.safeParse(range).success).toBe(true);
+  }
+
+  for (const range of invalidRanges) {
+    expect(cidr.safeParse(range).success).toBe(false);
+  }
+
+  const ipv4Cidr = z.string().cidr({ version: "v4" });
+  expect(ipv4Cidr.safeParse("192.168.0.0/16").success).toBe(true);
+  expect(ipv4Cidr.safeParse("2001:db8::/32").success).toBe(false);
+
+  const ipv6Cidr = z.string().cidr({ version: "v6" });
+  expect(ipv6Cidr.safeParse("2001:db8::/32").success).toBe(true);
+  expect(ipv6Cidr.safeParse("192.168.0.0/16").success).toBe(false);
+});
diff --git a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/src/types.ts b/app/src/types.ts
index be49c70..f6b7341 100644
--- a/tmp/agent-patch-flux-pr-3820.1-of-1.2026-02-27__21-30-28__gpt-5-1-codex-mini/app/src/types.ts
+++ b/app/src/types.ts
@@ -565,6 +565,7 @@ export type ZodStringCheck =
     }
   | { kind: "duration"; message?: string }
   | { kind: "ip"; version?: IpVersion; message?: string }
+  | { kind: "cidr"; version?: IpVersion; message?: string }
   | { kind: "base64"; message?: string };
 
 export interface ZodStringDef extends ZodTypeDef {
@@ -660,15 +661,37 @@ export function datetimeRegex(args: {
   return new RegExp(`^${regex}$`);
 }
 
+function getIpVersion(ip: string): IpVersion | undefined {
+  if (ipv4Regex.test(ip)) return "v4";
+  if (ipv6Regex.test(ip)) return "v6";
+  return undefined;
+}
+
 function isValidIP(ip: string, version?: IpVersion) {
-  if ((version === "v4" || !version) && ipv4Regex.test(ip)) {
-    return true;
-  }
-  if ((version === "v6" || !version) && ipv6Regex.test(ip)) {
-    return true;
+  const detectedVersion = getIpVersion(ip);
+  if (!detectedVersion) return false;
+  if (version && version !== detectedVersion) return false;
+  return true;
+}
+
+function isValidCIDR(value: string, version?: IpVersion) {
+  const [address, prefix, ...rest] = value.split("/");
+  if (rest.length || !address || !prefix) return false;
+  if (!/^[0-9]+$/.test(prefix)) return false;
+
+  const prefixLen = Number(prefix);
+  if (!Number.isFinite(prefixLen) || !Number.isInteger(prefixLen)) {
+    return false;
   }
 
-  return false;
+  const detectedVersion = getIpVersion(address);
+  if (!detectedVersion) return false;
+  if (version && detectedVersion !== version) return false;
+
+  const maxPrefix = detectedVersion === "v4" ? 32 : 128;
+  if (prefixLen < 0 || prefixLen > maxPrefix) return false;
+
+  return true;
 }
 
 export class ZodString extends ZodType<string, ZodStringDef, string> {
@@ -923,6 +946,16 @@ export class ZodString extends ZodType<string, ZodStringDef, string> {
           });
           status.dirty();
         }
+      } else if (check.kind === "cidr") {
+        if (!isValidCIDR(input.data, check.version)) {
+          ctx = this._getOrReturnCtx(input, ctx);
+          addIssueToContext(ctx, {
+            validation: "cidr",
+            code: ZodIssueCode.invalid_string,
+            message: check.message,
+          });
+          status.dirty();
+        }
       } else if (check.kind === "ip") {
         if (!isValidIP(input.data, check.version)) {
           ctx = this._getOrReturnCtx(input, ctx);
@@ -1006,6 +1039,10 @@ export class ZodString extends ZodType<string, ZodStringDef, string> {
     return this._addCheck({ kind: "ip", ...errorUtil.errToObj(options) });
   }
 
+  cidr(options?: string | { version?: IpVersion; message?: string }) {
+    return this._addCheck({ kind: "cidr", ...errorUtil.errToObj(options) });
+  }
+
   datetime(
     options?:
       | string
@@ -1199,6 +1236,9 @@ export class ZodString extends ZodType<string, ZodStringDef, string> {
   get isIP() {
     return !!this._def.checks.find((ch) => ch.kind === "ip");
   }
+  get isCIDR() {
+    return !!this._def.checks.find((ch) => ch.kind === "cidr");
+  }
   get isBase64() {
     return !!this._def.checks.find((ch) => ch.kind === "base64");
   }