From 3576d1e9674edfbb2415dc5f9836b05a3cade51e Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 16 Jun 2026 23:11:55 +0200 Subject: [PATCH] fix(testbox): reject unsafe Crabbox version tuples --- scripts/crabbox-wrapper.mjs | 14 +++++++++++++- test/scripts/crabbox-wrapper.test.ts | 13 +++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/scripts/crabbox-wrapper.mjs b/scripts/crabbox-wrapper.mjs index b9266db8f14a..00f9bff72bde 100755 --- a/scripts/crabbox-wrapper.mjs +++ b/scripts/crabbox-wrapper.mjs @@ -199,12 +199,24 @@ function parseCrabboxVersion(value) { if (!match) { return null; } + const tuple = match.slice(1, 4).map(parseVersionTuplePart); + if (tuple.some((part) => part === null)) { + return null; + } return { - tuple: match.slice(1, 4).map((part) => Number.parseInt(part, 10)), + tuple, suffix: match[4] ?? "", }; } +function parseVersionTuplePart(value) { + if (!/^\d+$/u.test(value)) { + return null; + } + const parsed = Number(value); + return Number.isSafeInteger(parsed) ? parsed : null; +} + function compareVersionTuples(left, right) { for (let index = 0; index < 3; index += 1) { const diff = left[index] - right[index]; diff --git a/test/scripts/crabbox-wrapper.test.ts b/test/scripts/crabbox-wrapper.test.ts index cf9e94ae2924..8beaa2c93cb3 100644 --- a/test/scripts/crabbox-wrapper.test.ts +++ b/test/scripts/crabbox-wrapper.test.ts @@ -449,6 +449,19 @@ describe.concurrent("scripts/crabbox-wrapper", () => { expect(result.stderr).toContain("selected binary reported version=crabbox 0.22.0-rc.1"); }); + it("rejects unsafe Crabbox version numbers at the Blacksmith minimum gate", () => { + const result = runWrapper( + "provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n", + ["run", "--provider", "blacksmith-testbox", "--", "echo ok"], + { env: { OPENCLAW_FAKE_CRABBOX_VERSION: "crabbox 0.9007199254740993.0" } }, + ); + + expect(result.status).toBe(2); + expect(result.stderr).toContain( + "selected binary reported version=crabbox 0.9007199254740993.0", + ); + }); + it("accepts post-release Crabbox describe builds at the Blacksmith minimum boundary", () => { const result = runWrapper( "provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",