Skip to content

Commit 385aad4

Browse files
committed
fix(scan create): detect --default-branch=<name> misuse
`--default-branch` is a boolean meow flag, so `--default-branch=main` silently becomes `defaultBranch=true` with the `"main"` portion discarded. Users with that (reasonable) intuition ended up with scans that weren't tagged with any branch name and didn't show up in the Main/PR dashboard tabs. Pre-flight check in `run()` scans the raw argv for `--default-branch=<value>`. Values that coerce to boolean (`true` / `false`, any case) are let through; anything else is treated as a misuse and fails with: ✗ "--default-branch=main" looks like you meant the branch name "main". --default-branch is a boolean flag; pass the branch name with --branch instead: socket scan create --branch main --default-branch Exits with code 2 (invalid usage), consistent with other flag validation failures in this command. Added tests: * misuse form with a branch-name value is caught and logged * explicit `--default-branch=true|false|TRUE` all pass through * bare `--default-branch` with paired `--branch main` flows through
1 parent 2976ce0 commit 385aad4

File tree

2 files changed

+113
-4
lines changed

2 files changed

+113
-4
lines changed

packages/cli/src/commands/scan/cmd-scan-create.mts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,24 @@ const generalFlags: MeowFlags = {
202202
},
203203
}
204204

205-
export const cmdScanCreate = {
206-
description,
207-
hidden,
208-
run,
205+
// Scan argv for `--default-branch=<non-bool-string>`. The flag is declared
206+
// boolean, so meow coerces `--default-branch=main` to `true` and discards
207+
// "main" — silently leaving the scan without a branch tag.
208+
function findDefaultBranchValueMisuse(
209+
argv: readonly string[],
210+
): string | undefined {
211+
for (const arg of argv) {
212+
if (!arg.startsWith('--default-branch=')) {
213+
continue
214+
}
215+
const value = arg.slice('--default-branch='.length)
216+
const normalized = value.toLowerCase()
217+
if (normalized === 'true' || normalized === 'false' || value === '') {
218+
continue
219+
}
220+
return value
221+
}
222+
return undefined
209223
}
210224

211225
async function run(
@@ -272,6 +286,21 @@ async function run(
272286
`,
273287
}
274288

289+
// Detect the common `--default-branch=main` misuse before meow parses.
290+
// `--default-branch` is a boolean — meow/yargs-parser treats
291+
// `--default-branch=main` as `defaultBranch=true` and silently drops
292+
// the "main" portion, so the user's scan gets tagged without the
293+
// intended branch name and doesn't appear in the Main/PR dashboard
294+
// tabs. Fail fast with a suggestion toward the correct form.
295+
const defaultBranchMisuse = findDefaultBranchValueMisuse(argv)
296+
if (defaultBranchMisuse) {
297+
logger.fail(
298+
`"--default-branch=${defaultBranchMisuse}" looks like you meant the branch name "${defaultBranchMisuse}".\n--default-branch is a boolean flag; pass the branch name with --branch instead:\n socket scan create --branch ${defaultBranchMisuse} --default-branch`,
299+
)
300+
process.exitCode = 2
301+
return
302+
}
303+
275304
const cli = meowOrExit({
276305
argv,
277306
config,
@@ -680,3 +709,9 @@ async function run(
680709
workspace: (workspace && String(workspace)) || '',
681710
})
682711
}
712+
713+
export const cmdScanCreate = {
714+
description,
715+
hidden,
716+
run,
717+
}

packages/cli/test/unit/commands/scan/cmd-scan-create.test.mts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,5 +1366,79 @@ describe('cmd-scan-create', () => {
13661366
expect(mockHandleCreateNewScan).not.toHaveBeenCalled()
13671367
})
13681368
})
1369+
1370+
describe('--default-branch misuse detection', () => {
1371+
// --default-branch is a boolean flag; meow silently discards the
1372+
// `=<value>` portion on `--default-branch=<name>`. Catch that
1373+
// pattern before meow parses so users get a clear error pointing
1374+
// at the right shape (`--branch <name> --default-branch`).
1375+
it('fails when --default-branch=<name> is passed with a branch name', async () => {
1376+
await cmdScanCreate.run(
1377+
['--org', 'test-org', '--default-branch=main', '.'],
1378+
importMeta,
1379+
context,
1380+
)
1381+
1382+
expect(process.exitCode).toBe(2)
1383+
expect(mockHandleCreateNewScan).not.toHaveBeenCalled()
1384+
expect(mockLogger.fail).toHaveBeenCalledWith(
1385+
expect.stringContaining(
1386+
'"--default-branch=main" looks like you meant the branch name "main"',
1387+
),
1388+
)
1389+
expect(mockLogger.fail).toHaveBeenCalledWith(
1390+
expect.stringContaining('--branch main --default-branch'),
1391+
)
1392+
})
1393+
1394+
it.each([
1395+
'--default-branch=true',
1396+
'--default-branch=false',
1397+
'--default-branch=TRUE',
1398+
])('allows %s (explicit boolean form)', async arg => {
1399+
mockHasDefaultApiToken.mockReturnValueOnce(true)
1400+
1401+
await cmdScanCreate.run(
1402+
[
1403+
'--org',
1404+
'test-org',
1405+
'--branch',
1406+
'main',
1407+
arg,
1408+
'.',
1409+
'--no-interactive',
1410+
],
1411+
importMeta,
1412+
context,
1413+
)
1414+
1415+
// meow parses the flag normally and flows through to handleCreateNewScan.
1416+
expect(mockLogger.fail).not.toHaveBeenCalledWith(
1417+
expect.stringContaining('looks like you meant the branch name'),
1418+
)
1419+
})
1420+
1421+
it('allows bare --default-branch (default truthy form)', async () => {
1422+
mockHasDefaultApiToken.mockReturnValueOnce(true)
1423+
1424+
await cmdScanCreate.run(
1425+
[
1426+
'--org',
1427+
'test-org',
1428+
'--branch',
1429+
'main',
1430+
'--default-branch',
1431+
'.',
1432+
'--no-interactive',
1433+
],
1434+
importMeta,
1435+
context,
1436+
)
1437+
1438+
expect(mockLogger.fail).not.toHaveBeenCalledWith(
1439+
expect.stringContaining('looks like you meant the branch name'),
1440+
)
1441+
})
1442+
})
13691443
})
13701444
})

0 commit comments

Comments
 (0)