fix(github-coordination): reject malformed issue numbers instead of truncating them

normalizeIssueNumber parsed with Number.parseInt, which stops at the
first non-digit ("42oops" -> 42, "42.9" -> 42, "4e2" -> 4) and loses
precision past 2^53 (9007199254740993 became 9007199254740992). The CLI
shares this helper for --issue, --limit, and the positional issue number,
so malformed values silently targeted the wrong issue before any integer
guard downstream could notice.

Validate the entire trimmed decimal token and require
Number.isSafeInteger so malformed or out-of-range values throw
"Invalid issue number" during argument parsing, before the state store
is opened or GitHub is contacted. Whitespace, leading plus, and leading
zero tolerance is preserved. Regression coverage added at both the
library level (tests/lib/github-coordination-gh-api.test.js) and the CLI
argument parser (tests/scripts/github-coordination.test.js).

Fixes #3514
This commit is contained in:
akushonkamen
2026-10-12 01:25:09 +08:00
parent 8ce348fbea
commit 3cf0e709d5
3 changed files with 121 additions and 2 deletions
+22
View File
@@ -93,6 +93,28 @@ async function runTests() {
let passed = 0;
let failed = 0;
if (
await test('rejects malformed issue numbers during argument parsing', async () => {
const { parseArgs } = require(SCRIPT);
for (const argv of [
['node', 'github-coordination.js', 'claim', '42oops', '--repo', 'example/project'],
['node', 'github-coordination.js', 'claim', '--issue', '42.9', '--repo', 'example/project'],
['node', 'github-coordination.js', 'claim', '--issue', '4e2', '--repo', 'example/project'],
['node', 'github-coordination.js', 'claim', '--issue', '9007199254740993', '--repo', 'example/project'],
['node', 'github-coordination.js', 'claim', '--limit', '42.9', '--repo', 'example/project'],
]) {
assert.throws(() => parseArgs(argv), /Invalid issue number/);
}
const valid = parseArgs(['node', 'github-coordination.js', 'claim', '7', '--repo', 'example/project']);
assert.strictEqual(valid.issueNumber, 7);
assert.strictEqual(valid.limit, 100);
})
)
passed++;
else failed++;
if (
await test('claims an epic issue, updates GitHub state, and caches a work item', async () => {
const rootDir = createTempDir('github-coordination-claim-');