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
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");
}