diff --git a/scripts/run-additional-boundary-checks.mjs b/scripts/run-additional-boundary-checks.mjs index 1124f8b4ace..2a51c5b51b6 100644 --- a/scripts/run-additional-boundary-checks.mjs +++ b/scripts/run-additional-boundary-checks.mjs @@ -66,19 +66,22 @@ export const BOUNDARY_CHECKS = [ ["lint:ui:no-raw-window-open", "pnpm", ["lint:ui:no-raw-window-open"]], ].map(([label, command, args]) => ({ label, command, args })); -export function resolveConcurrency(value, fallback = 4) { - const parsed = Number.parseInt(String(value ?? ""), 10); - if (!Number.isFinite(parsed) || parsed < 1) { - return fallback; - } - return parsed; +export function resolveConcurrency(value, fallback = 4, label = "concurrency") { + return resolvePositiveInteger(value, fallback, label); } -export function resolvePositiveInteger(value, fallback) { - const parsed = Number.parseInt(String(value ?? ""), 10); - if (!Number.isFinite(parsed) || parsed < 1) { +export function resolvePositiveInteger(value, fallback, label = "value") { + if (value === undefined || value === null || value === "") { return fallback; } + const text = String(value).trim(); + if (!/^\d+$/u.test(text)) { + throw new Error(`${label} must be a positive integer; got: ${value}`); + } + const parsed = Number(text); + if (!Number.isSafeInteger(parsed) || parsed < 1) { + throw new Error(`${label} must be a positive integer; got: ${value}`); + } return parsed; } @@ -432,17 +435,27 @@ function resolveCliShardSpec(args, env) { } if (import.meta.url === `file://${process.argv[1]}`) { - const concurrency = resolveConcurrency( + const concurrencyRaw = process.env.OPENCLAW_ADDITIONAL_BOUNDARY_CONCURRENCY ?? - process.env.OPENCLAW_EXTENSION_BOUNDARY_CONCURRENCY, + process.env.OPENCLAW_EXTENSION_BOUNDARY_CONCURRENCY; + const concurrencyLabel = + process.env.OPENCLAW_ADDITIONAL_BOUNDARY_CONCURRENCY === undefined + ? "OPENCLAW_EXTENSION_BOUNDARY_CONCURRENCY" + : "OPENCLAW_ADDITIONAL_BOUNDARY_CONCURRENCY"; + const concurrency = resolveConcurrency( + concurrencyRaw, + 4, + concurrencyLabel, ); const checkTimeoutMs = resolvePositiveInteger( process.env.OPENCLAW_ADDITIONAL_BOUNDARY_TIMEOUT_MS, DEFAULT_CHECK_TIMEOUT_MS, + "OPENCLAW_ADDITIONAL_BOUNDARY_TIMEOUT_MS", ); const outputMaxBytes = resolvePositiveInteger( process.env.OPENCLAW_ADDITIONAL_BOUNDARY_OUTPUT_MAX_BYTES, DEFAULT_OUTPUT_MAX_BYTES, + "OPENCLAW_ADDITIONAL_BOUNDARY_OUTPUT_MAX_BYTES", ); const shards = parseShardSelection(resolveCliShardSpec(process.argv.slice(2), process.env)); const checks = selectChecksForShard(BOUNDARY_CHECKS, shards); diff --git a/test/scripts/run-additional-boundary-checks.test.ts b/test/scripts/run-additional-boundary-checks.test.ts index 557540b1216..23c9b856e0e 100644 --- a/test/scripts/run-additional-boundary-checks.test.ts +++ b/test/scripts/run-additional-boundary-checks.test.ts @@ -6,6 +6,7 @@ import { parseShardSelection, parseShardSpec, resolveConcurrency, + resolvePositiveInteger, runChecks, runSingleCheck, selectChecksForShard, @@ -35,8 +36,24 @@ describe("run-additional-boundary-checks", () => { it("normalizes concurrency input", () => { expect(resolveConcurrency("6")).toBe(6); - expect(resolveConcurrency("0")).toBe(4); - expect(resolveConcurrency("nope", 2)).toBe(2); + expect(resolveConcurrency(undefined, 2)).toBe(2); + expect(() => resolveConcurrency("0")).toThrow("concurrency must be a positive integer; got: 0"); + expect(() => resolveConcurrency("6x", 2)).toThrow( + "concurrency must be a positive integer; got: 6x", + ); + }); + + it("rejects malformed timeout and output limit integers", () => { + expect(resolvePositiveInteger("25", 50, "OPENCLAW_ADDITIONAL_BOUNDARY_TIMEOUT_MS")).toBe(25); + expect(resolvePositiveInteger(undefined, 50, "OPENCLAW_ADDITIONAL_BOUNDARY_TIMEOUT_MS")).toBe( + 50, + ); + expect(() => + resolvePositiveInteger("1000ms", 50, "OPENCLAW_ADDITIONAL_BOUNDARY_TIMEOUT_MS"), + ).toThrow("OPENCLAW_ADDITIONAL_BOUNDARY_TIMEOUT_MS must be a positive integer; got: 1000ms"); + expect(() => + resolvePositiveInteger("1e3", 50, "OPENCLAW_ADDITIONAL_BOUNDARY_OUTPUT_MAX_BYTES"), + ).toThrow("OPENCLAW_ADDITIONAL_BOUNDARY_OUTPUT_MAX_BYTES must be a positive integer; got: 1e3"); }); it("formats command display text", () => {