@github-actions[bot]2w ago
feat(apollo): support CIDR blocks in API key IP allowlist
loading diff…
API key IP allowlists currently accept only bare IPv4/IPv6 addresses and enforce them with exact string matching (allowedIps.includes(clientIp)). This adds CIDR block support (e.g. 198.51.100.0/24) for both validation and enforcement.
apps/apollo/src/lib/apiKeys/ipValidation.ts (new) — isIpOrCidr (validation) and ipMatchesAllowlist (subnet-containment matching). Built on the ip-address lib, which is already a direct dep and already used for CIDR matching in trusted_ip_ranges.ts — no new dependency added. Matching compares parsed bigint ranges, is version-aware (no cross-version matches), and unwraps IPv4-mapped IPv6 client addresses (::ffff:1.2.3.4) so a mapped client still matches a bare IPv4 entry.authMiddleware.ts — validateAllowedIps now uses ipMatchesAllowlist(clientIp, allowedIps) instead of exact includes.v3 .../api_keys/create.ts, v3.1 .../allowed_ips.ts, internal-dashboard .../allowed_ips.ts) — allowed_ips entries switch from z.string().ip() (which rejects CIDR) to z.string().refine(isIpOrCidr, ...). Response schemas left as z.array(z.string()) so reads of historically-stored values are never rejected.ipValidation.test.ts (new) — covers bare v4/v6, CIDR blocks, malformed input, in/out-of-range, /32, IPv6, mapped ::ffff:, cross-version, malformed entries (no throw), unparseable client.isIpOrCidr + ipMatchesAllowlist against the cases abovecheck-types — no errors in changed files198.51.100.5/24 as 198.51.100.0/24) is deferred — entries are stored as submitted; matching handles non-canonical forms correctly.