From a5c83c03b4650ebe14abf11df86fc6f71ccff351 Mon Sep 17 00:00:00 2001 From: huyplb Date: Tue, 28 Jul 2026 12:31:51 -0600 Subject: [PATCH] fix(ci): clear the security/detect-unsafe-regex error blocking every PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Azure Key Vault host check used `^\d{1,3}(\.\d{1,3}){3}$` to reject raw IPv4. That pattern is linear in practice — every quantifier is bounded and both ends are anchored — but security/detect-unsafe-regex flags the repeated group, and `npx eslint .` is a required job, so the error failed CI on every open PR regardless of what the PR touched. State the same rule by splitting on '.' instead: no regex ambiguity to argue about, and the intent reads more plainly. Verified behaviourally identical to the old pattern across 17 cases (valid/invalid octet counts, trailing and leading dots, over-long octets, hostnames, empty string). Repo-wide eslint now reports 0 errors (50 warnings remain; CI runs `npx eslint .` without --max-warnings, so warnings do not fail the job). Co-Authored-By: Claude Opus 5 --- apps/web/src/backend/modules/cloud-secrets.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/web/src/backend/modules/cloud-secrets.ts b/apps/web/src/backend/modules/cloud-secrets.ts index c2813b8..fc41549 100644 --- a/apps/web/src/backend/modules/cloud-secrets.ts +++ b/apps/web/src/backend/modules/cloud-secrets.ts @@ -88,8 +88,14 @@ export function assertAzureVaultUrl(vaultUrl: string): void { ) { throw new Error('Azure Key Vault URL hostname is not allowed'); } - // Reject raw IPv4 / IPv6 - if (/^\d{1,3}(\.\d{1,3}){3}$/.test(host) || host.includes(':')) { + // Reject raw IPv4 / IPv6. Split rather than match `^\d{1,3}(\.\d{1,3}){3}$`: + // that pattern is linear in practice (every quantifier is bounded and both + // ends anchored), but security/detect-unsafe-regex flags the repeated group + // and failed CI on every PR. Splitting states the same rule with no regex + // ambiguity to argue about. + const octets = host.split('.'); + const isRawIpv4 = octets.length === 4 && octets.every((o) => /^\d{1,3}$/.test(o)); + if (isRawIpv4 || host.includes(':')) { throw new Error('Azure Key Vault URL must use a vault hostname, not an IP'); } const allowedSuffixes = [