Skip to content

Commit 758f61c

Browse files
authored
Update socket scan reach to include the same flags as socket scan create --reach (#708)
* update socket scan reach to include the same flags as socket scan create --reach and to use the same --manifests-tar-hash based approach for computing SBOMs * update socket scan reach description * fix bug where reachability analyses were not included in the rollup external dependencies * move dryrun bail to end cmd-scan-reach
1 parent 8ea5851 commit 758f61c

10 files changed

Lines changed: 671 additions & 261 deletions

.config/rollup.dist.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ async function copyExternalPackages() {
121121
[
122122
[blessedPath, ['lib/**/*.js', 'usr/**/**', 'vendor/**/*.js', 'LICENSE*']],
123123
[blessedContribPath, ['lib/**/*.js', 'index.js', 'LICENSE*']],
124-
[coanaPath, ['**/*.mjs']],
124+
[coanaPath, ['**/*.mjs', 'coana-repos/**/*']],
125125
[
126126
socketRegistryPath,
127127
[

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

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { logger } from '@socketsecurity/registry/lib/logger'
44

55
import { handleCreateNewScan } from './handle-create-new-scan.mts'
66
import { outputCreateNewScan } from './output-create-new-scan.mts'
7+
import { reachabilityFlags } from './reachability-flags.mts'
78
import { suggestOrgSlug } from './suggest-org-slug.mts'
89
import { suggestTarget } from './suggest_target.mts'
910
import constants from '../../constants.mts'
@@ -31,42 +32,6 @@ const {
3132
SOCKET_DEFAULT_REPOSITORY,
3233
} = constants
3334

34-
const reachabilityFlags: MeowFlags = {
35-
reachDisableAnalytics: {
36-
type: 'boolean',
37-
description:
38-
'Disable reachability analytics sharing with Socket. Also disables caching-based optimizations.',
39-
},
40-
reachAnalysisMemoryLimit: {
41-
type: 'number',
42-
description:
43-
'The maximum memory in MB to use for the reachability analysis. The default is 8192MB.',
44-
default: 8192,
45-
},
46-
reachAnalysisTimeout: {
47-
type: 'number',
48-
description:
49-
'Set timeout for the reachability analysis. Split analysis runs may cause the total scan time to exceed this timeout significantly.',
50-
},
51-
reachEcosystems: {
52-
type: 'string',
53-
isMultiple: true,
54-
description:
55-
'List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Defaults to all ecosystems.',
56-
},
57-
reachContinueOnFailingProjects: {
58-
type: 'boolean',
59-
description:
60-
'Continue reachability analysis even when some projects/workspaces fail. Default is to crash the CLI at the first failing project/workspace.',
61-
},
62-
reachExcludePaths: {
63-
type: 'string',
64-
isMultiple: true,
65-
description:
66-
'List of paths to exclude from reachability analysis, as either a comma separated value or as multiple flags.',
67-
},
68-
}
69-
7035
const config: CliCommandConfig = {
7136
commandName: 'create',
7237
description: 'Create a new Socket scan and report',

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

Lines changed: 133 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,21 @@ import path from 'node:path'
33
import { logger } from '@socketsecurity/registry/lib/logger'
44

55
import { handleScanReach } from './handle-scan-reach.mts'
6+
import { reachabilityFlags } from './reachability-flags.mts'
7+
import { suggestTarget } from './suggest_target.mts'
68
import constants from '../../constants.mts'
7-
import { commonFlags, outputFlags } from '../../flags.mts'
9+
import { type MeowFlags, commonFlags, outputFlags } from '../../flags.mts'
810
import { checkCommandInput } from '../../utils/check-input.mts'
11+
import { cmdFlagValueToArray } from '../../utils/cmd.mts'
12+
import { determineOrgSlug } from '../../utils/determine-org-slug.mts'
13+
import {
14+
type EcosystemString,
15+
getEcosystemChoicesForMeow,
16+
} from '../../utils/ecosystem.mts'
917
import { getOutputKind } from '../../utils/get-output-kind.mts'
1018
import { meowOrExit } from '../../utils/meow-with-subcommands.mts'
1119
import { getFlagListOutput } from '../../utils/output-formatting.mts'
20+
import { hasDefaultToken } from '../../utils/sdk.mts'
1221

1322
import type { CliCommandConfig } from '../../utils/meow-with-subcommands.mts'
1423

@@ -21,18 +30,51 @@ const config: CliCommandConfig = {
2130
flags: {
2231
...commonFlags,
2332
...outputFlags,
33+
cwd: {
34+
type: 'string',
35+
description: 'working directory, defaults to process.cwd()',
36+
},
37+
org: {
38+
type: 'string',
39+
description:
40+
'Force override the organization slug, overrides the default org from config',
41+
},
42+
...reachabilityFlags,
2443
},
25-
help: (command, config) => `
44+
help: (command, config) => {
45+
const allFlags = config.flags || {}
46+
const generalFlags: MeowFlags = {}
47+
48+
// Separate general flags from reachability flags
49+
for (const [key, value] of Object.entries(allFlags)) {
50+
if (!reachabilityFlags[key]) {
51+
generalFlags[key] = value
52+
}
53+
}
54+
55+
return `
2656
Usage
2757
$ ${command} [options] [CWD=.]
2858
2959
Options
30-
${getFlagListOutput(config.flags)}
60+
${getFlagListOutput(generalFlags)}
61+
62+
Reachability Options
63+
${getFlagListOutput(reachabilityFlags)}
64+
65+
Runs the Socket reachability analysis without creating a scan in Socket.
66+
The output is written to .socket.facts.json in the current working directory.
67+
68+
Note: Manifest files are uploaded to Socket's backend services because the
69+
reachability analysis requires creating a Software Bill of Materials (SBOM)
70+
from these files before the analysis can run.
3171
3272
Examples
3373
$ ${command}
3474
$ ${command} ./proj
35-
`,
75+
$ ${command} ./proj --reach-ecosystems npm,pypi
76+
`
77+
},
3678
}
3779

3880
export const cmdScanReach = {
@@ -53,11 +95,85 @@ async function run(
5395
parentName,
5496
})
5597

56-
const { dryRun, json, markdown } = cli.flags
98+
const {
99+
cwd: cwdOverride,
100+
dryRun = false,
101+
interactive = true,
102+
json,
103+
markdown,
104+
org: orgFlag,
105+
reachAnalysisMemoryLimit,
106+
reachAnalysisTimeout,
107+
reachContinueOnFailingProjects,
108+
reachDisableAnalytics,
109+
} = cli.flags as {
110+
cwd: string
111+
dryRun: boolean
112+
interactive: boolean
113+
json: boolean
114+
markdown: boolean
115+
org: string
116+
reachAnalysisTimeout?: number
117+
reachAnalysisMemoryLimit?: number
118+
reachContinueOnFailingProjects: boolean
119+
reachDisableAnalytics: boolean
120+
}
121+
122+
// Process comma-separated values for isMultiple flags
123+
const reachEcosystemsRaw = cmdFlagValueToArray(cli.flags['reachEcosystems'])
124+
const reachExcludePaths = cmdFlagValueToArray(cli.flags['reachExcludePaths'])
125+
126+
// Validate ecosystem values
127+
const validEcosystems = getEcosystemChoicesForMeow()
128+
const reachEcosystems: EcosystemString[] = []
129+
for (const ecosystem of reachEcosystemsRaw) {
130+
if (!validEcosystems.includes(ecosystem)) {
131+
throw new Error(
132+
`Invalid ecosystem: "${ecosystem}". Valid values are: ${validEcosystems.join(', ')}`,
133+
)
134+
}
135+
reachEcosystems.push(ecosystem as EcosystemString)
136+
}
57137

58138
const outputKind = getOutputKind(json, markdown)
59139

60-
const wasValidInput = checkCommandInput(outputKind)
140+
const cwd =
141+
cwdOverride && cwdOverride !== 'process.cwd()'
142+
? path.resolve(process.cwd(), String(cwdOverride))
143+
: process.cwd()
144+
145+
// Accept zero or more paths. Default to cwd() if none given.
146+
let targets = cli.input || [cwd]
147+
148+
// Use suggestTarget if no targets specified and in interactive mode
149+
if (!targets.length && !dryRun && interactive) {
150+
targets = await suggestTarget()
151+
}
152+
153+
// Determine org slug
154+
const [orgSlug] = await determineOrgSlug(
155+
String(orgFlag || ''),
156+
interactive,
157+
dryRun,
158+
)
159+
160+
const hasApiToken = hasDefaultToken()
161+
162+
const wasValidInput = checkCommandInput(
163+
outputKind,
164+
{
165+
nook: true,
166+
test: !!orgSlug,
167+
message: 'Org name by default setting, --org, or auto-discovered',
168+
fail: 'missing',
169+
},
170+
{
171+
nook: true,
172+
test: hasApiToken,
173+
message: 'This command requires an API token for access',
174+
fail: 'missing (try `socket login`)',
175+
},
176+
)
61177
if (!wasValidInput) {
62178
return
63179
}
@@ -67,16 +183,19 @@ async function run(
67183
return
68184
}
69185

70-
const { unknownFlags } = cli
71-
72-
let [cwd = '.'] = cli.input
73-
// Note: path.resolve vs .join:
74-
// If given path is absolute then cwd should not affect it.
75-
cwd = path.resolve(process.cwd(), cwd)
76-
77186
await handleScanReach({
78187
cwd,
188+
orgSlug,
79189
outputKind,
80-
unknownFlags,
190+
targets,
191+
interactive,
192+
reachabilityOptions: {
193+
reachContinueOnFailingProjects: Boolean(reachContinueOnFailingProjects),
194+
reachDisableAnalytics: Boolean(reachDisableAnalytics),
195+
reachAnalysisTimeout: Number(reachAnalysisTimeout),
196+
reachAnalysisMemoryLimit: Number(reachAnalysisMemoryLimit),
197+
reachEcosystems,
198+
reachExcludePaths,
199+
},
81200
})
82201
}

0 commit comments

Comments
 (0)