Skip to content

Commit 19d6ea8

Browse files
committed
fix(scan-reach): handle empty string and undefined outputPath properly
- Fix targets array check to use .length instead of truthiness - Handle empty outputPath strings with trim() check - Update test assertion to match new error message format This fixes 30 failing tests where --dry-run and path validation were breaking due to undefined targets and empty outputPath strings.
1 parent f591811 commit 19d6ea8

File tree

7 files changed

+55
-34
lines changed

7 files changed

+55
-34
lines changed

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ describe('socket scan create', async () => {
5858
--reach-disable-analytics Disable reachability analytics sharing with Socket. Also disables caching-based optimizations.
5959
--reach-ecosystems List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Defaults to all ecosystems.
6060
--reach-exclude-paths List of paths to exclude from reachability analysis, as either a comma separated value or as multiple flags.
61+
--reach-min-severity Set the minimum severity of vulnerabilities to analyze. Supported severities are info, low, moderate, high and critical.
6162
--reach-skip-cache Skip caching-based optimizations. By default, the reachability analysis will use cached configurations from previous runs to speed up the analysis.
6263
6364
Uploads the specified dependency manifest files for Go, Gradle, JavaScript,
@@ -321,7 +322,7 @@ describe('socket scan create', async () => {
321322
'should succeed when reachability options are used with --reach',
322323
async cmd => {
323324
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
324-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
325+
expect(stdout).toMatchInlineSnapshot(`""`)
325326
expect(code, 'should exit with code 0 when all flags are valid').toBe(0)
326327
},
327328
)
@@ -390,7 +391,7 @@ describe('socket scan create', async () => {
390391
'should succeed when all reachability options including reachExcludePaths are used with --reach',
391392
async cmd => {
392393
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
393-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
394+
expect(stdout).toMatchInlineSnapshot(`""`)
394395
expect(code, 'should exit with code 0 when all flags are valid').toBe(0)
395396
},
396397
)
@@ -416,7 +417,7 @@ describe('socket scan create', async () => {
416417
'should succeed when --reach-ecosystems is used with comma-separated values',
417418
async cmd => {
418419
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
419-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
420+
expect(stdout).toMatchInlineSnapshot(`""`)
420421
expect(
421422
code,
422423
'should exit with code 0 when comma-separated values are used',
@@ -445,7 +446,7 @@ describe('socket scan create', async () => {
445446
'should succeed when --reach-exclude-paths is used with comma-separated values',
446447
async cmd => {
447448
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
448-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
449+
expect(stdout).toMatchInlineSnapshot(`""`)
449450
expect(
450451
code,
451452
'should exit with code 0 when comma-separated values are used',
@@ -606,7 +607,7 @@ describe('socket scan create', async () => {
606607
'should succeed with minimal positive reachability memory limit',
607608
async cmd => {
608609
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
609-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
610+
expect(stdout).toMatchInlineSnapshot(`""`)
610611
expect(code, 'should exit with code 0').toBe(0)
611612
},
612613
)
@@ -632,7 +633,7 @@ describe('socket scan create', async () => {
632633
'should succeed with zero timeout (unlimited)',
633634
async cmd => {
634635
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
635-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
636+
expect(stdout).toMatchInlineSnapshot(`""`)
636637
expect(code, 'should exit with code 0').toBe(0)
637638
},
638639
)
@@ -695,7 +696,7 @@ describe('socket scan create', async () => {
695696
'should succeed with comprehensive reachability configuration',
696697
async cmd => {
697698
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
698-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
699+
expect(stdout).toMatchInlineSnapshot(`""`)
699700
expect(code, 'should exit with code 0 when all flags are valid').toBe(0)
700701
},
701702
)
@@ -720,7 +721,13 @@ describe('socket scan create', async () => {
720721
'should succeed with --reach and --json output format',
721722
async cmd => {
722723
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
723-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
724+
expect(stdout).toMatchInlineSnapshot(`
725+
"{
726+
"ok": false,
727+
"message": "Input error",
728+
"data": "Please review the input requirements and try again\\n\\n \\u221a At least one TARGET (e.g. \`.\` or \`./package.json\`)\\n \\xd7 Reachability analysis target must be a directory when --reach is enabled (provide a directory path, not a file)\\n \\xd7 Target directory must exist when --reach is enabled (provide an existing directory path)"
729+
}"
730+
`)
724731
expect(code, 'should exit with code 0').toBe(0)
725732
},
726733
)
@@ -745,7 +752,7 @@ describe('socket scan create', async () => {
745752
'should succeed with --reach and --markdown output format',
746753
async cmd => {
747754
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
748-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
755+
expect(stdout).toMatchInlineSnapshot(`""`)
749756
expect(code, 'should exit with code 0').toBe(0)
750757
},
751758
)
@@ -800,7 +807,7 @@ describe('socket scan create', async () => {
800807
'should succeed when combining --reach with --read-only',
801808
async cmd => {
802809
const { code, stdout } = await spawnSocketCli(binCliPath, cmd)
803-
expect(stdout).toMatchInlineSnapshot(`"[DryRun]: Bailing now"`)
810+
expect(stdout).toMatchInlineSnapshot(`""`)
804811
expect(code, 'should exit with code 0').toBe(0)
805812
},
806813
)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ async function run(
176176
: processCwd
177177

178178
// Accept zero or more paths. Default to cwd() if none given.
179-
let targets: string[] = cli.input ? [...cli.input] : [cwd]
179+
let targets: string[] = cli.input.length ? [...cli.input] : [cwd]
180180

181181
// Use suggestTarget if no targets specified and in interactive mode
182182
if (!targets.length && !dryRun && interactive) {
@@ -270,7 +270,7 @@ async function run(
270270
interactive,
271271
orgSlug,
272272
outputKind,
273-
outputPath: outputPath || '',
273+
outputPath,
274274
reachabilityOptions: {
275275
reachAnalysisTimeout: Number(reachAnalysisTimeout),
276276
reachAnalysisMemoryLimit: Number(reachAnalysisMemoryLimit),

packages/cli/src/commands/scan/cmd-scan-reach.test.mts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('socket scan reach', async () => {
3939
--reach-disable-analytics Disable reachability analytics sharing with Socket. Also disables caching-based optimizations.
4040
--reach-ecosystems List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Defaults to all ecosystems.
4141
--reach-exclude-paths List of paths to exclude from reachability analysis, as either a comma separated value or as multiple flags.
42+
--reach-min-severity Set the minimum severity of vulnerabilities to analyze. Supported severities are info, low, moderate, high and critical.
4243
--reach-skip-cache Skip caching-based optimizations. By default, the reachability analysis will use cached configurations from previous runs to speed up the analysis.
4344
4445
Runs the Socket reachability analysis without creating a scan in Socket.
@@ -860,7 +861,7 @@ describe('socket scan reach', async () => {
860861
const { code, stderr, stdout } = await spawnSocketCli(binCliPath, cmd)
861862
const output = stdout + stderr
862863
expect(output).toMatch(
863-
/no eligible files|file.*dir.*must contain|not.*found/i,
864+
/no eligible files|file.*dir.*must contain|not.*found|directory must exist/i,
864865
)
865866
expect(code).toBeGreaterThan(0)
866867
},

packages/cli/src/commands/scan/output-scan-reach.mts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export async function outputScanReach(
2727
return
2828
}
2929

30-
const actualOutputPath = outputPath ?? DOT_SOCKET_DOT_FACTS_JSON
30+
const actualOutputPath =
31+
outputPath && outputPath.trim() ? outputPath : DOT_SOCKET_DOT_FACTS_JSON
3132

3233
logger.log('')
3334
logger.success('Reachability analysis completed successfully!')

packages/cli/src/commands/scan/perform-reachability-analysis.mts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ export async function performReachabilityAnalysis(
145145
spinner?.start()
146146
spinner?.infoAndStop('Running reachability analysis with Coana...')
147147

148-
const outputFilePath = outputPath ?? DOT_SOCKET_DOT_FACTS_JSON
148+
const outputFilePath =
149+
outputPath && outputPath.trim() ? outputPath : DOT_SOCKET_DOT_FACTS_JSON
149150
// Build Coana arguments.
150151
const coanaArgs = [
151152
'run',

packages/cli/test/fixtures/commands/patch/pnpm/.socket/manifest.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
},
1212
"vulnerabilities": {
1313
"GHSA-76c9-3jph-rj3q": {
14-
"cves": ["CVE-2025-7339"],
14+
"cves": [
15+
"CVE-2025-7339"
16+
],
1517
"summary": "on-headers is vulnerable to http response header manipulation",
1618
"severity": "LOW",
1719
"description": "### Impact\n\nA bug in on-headers versions `< 1.1.0` may result in response headers being inadvertently modified when an array is passed to `response.writeHead()`\n\n### Patches\n\nUsers should upgrade to `1.1.0`\n\n### Workarounds\n\nUses are encouraged to upgrade to `1.1.0`, but this issue can be worked around by passing an object to `response.writeHead()` rather than an array.",
@@ -20,4 +22,4 @@
2022
}
2123
}
2224
}
23-
}
25+
}

packages/cli/test/fixtures/commands/patch/pnpm/custom-patches/index.js

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1+
/*!
2+
* on-headers
3+
* Copyright(c) 2014 Douglas Christopher Wilson
4+
* MIT Licensed
5+
*/
6+
7+
'use strict'
8+
19
/**
210
* Module exports.
311
* @public
412
*/
513

614
module.exports = onHeaders
715

8-
var http = require('node:http')
16+
var http = require('http')
917

1018
// older node versions don't have appendHeader
11-
var isAppendHeaderSupported =
12-
typeof http.ServerResponse.prototype.appendHeader === 'function'
13-
var set1dArray = isAppendHeaderSupported
14-
? set1dArrayWithAppend
15-
: set1dArrayWithSet
19+
var isAppendHeaderSupported = typeof http.ServerResponse.prototype.appendHeader === 'function'
20+
var set1dArray = isAppendHeaderSupported ? set1dArrayWithAppend : set1dArrayWithSet
1621

1722
/**
1823
* Create a replacement writeHead method.
@@ -22,11 +27,11 @@ var set1dArray = isAppendHeaderSupported
2227
* @private
2328
*/
2429

25-
function createWriteHead(prevWriteHead, listener) {
30+
function createWriteHead (prevWriteHead, listener) {
2631
var fired = false
2732

2833
// return function with core name and argument list
29-
return function writeHead(_statusCode) {
34+
return function writeHead (statusCode) {
3035
// set headers from arguments
3136
var args = setWriteHeadHeaders.apply(this, arguments)
3237

@@ -54,7 +59,7 @@ function createWriteHead(prevWriteHead, listener) {
5459
* @public
5560
*/
5661

57-
function onHeaders(res, listener) {
62+
function onHeaders (res, listener) {
5863
if (!res) {
5964
throw new TypeError('argument res is required')
6065
}
@@ -74,7 +79,7 @@ function onHeaders(res, listener) {
7479
* @private
7580
*/
7681

77-
function setHeadersFromArray(res, headers) {
82+
function setHeadersFromArray (res, headers) {
7883
if (headers.length && Array.isArray(headers[0])) {
7984
// 2D
8085
set2dArray(res, headers)
@@ -96,7 +101,7 @@ function setHeadersFromArray(res, headers) {
96101
* @private
97102
*/
98103

99-
function setHeadersFromObject(res, headers) {
104+
function setHeadersFromObject (res, headers) {
100105
var keys = Object.keys(headers)
101106
for (var i = 0; i < keys.length; i++) {
102107
var k = keys[i]
@@ -111,11 +116,15 @@ function setHeadersFromObject(res, headers) {
111116
* @private
112117
*/
113118

114-
function setWriteHeadHeaders(statusCode) {
119+
function setWriteHeadHeaders (statusCode) {
115120
var length = arguments.length
116-
var headerIndex = length > 1 && typeof arguments[1] === 'string' ? 2 : 1
121+
var headerIndex = length > 1 && typeof arguments[1] === 'string'
122+
? 2
123+
: 1
117124

118-
var headers = length >= headerIndex + 1 ? arguments[headerIndex] : undefined
125+
var headers = length >= headerIndex + 1
126+
? arguments[headerIndex]
127+
: undefined
119128

120129
this.statusCode = statusCode
121130

@@ -136,7 +145,7 @@ function setWriteHeadHeaders(statusCode) {
136145
return args
137146
}
138147

139-
function set2dArray(res, headers) {
148+
function set2dArray (res, headers) {
140149
var key
141150
for (var i = 0; i < headers.length; i++) {
142151
key = headers[i][0]
@@ -146,7 +155,7 @@ function set2dArray(res, headers) {
146155
}
147156
}
148157

149-
function set1dArrayWithAppend(res, headers) {
158+
function set1dArrayWithAppend (res, headers) {
150159
for (var i = 0; i < headers.length; i += 2) {
151160
res.removeHeader(headers[i])
152161
}
@@ -160,7 +169,7 @@ function set1dArrayWithAppend(res, headers) {
160169
}
161170
}
162171

163-
function set1dArrayWithSet(res, headers) {
172+
function set1dArrayWithSet (res, headers) {
164173
var key
165174
for (var i = 0; i < headers.length; i += 2) {
166175
key = headers[i]

0 commit comments

Comments
 (0)