Skip to content

Commit fce6b34

Browse files
committed
Add --workspace flag for full scan association
Signed-off-by: lelia <lelia@socket.dev>
1 parent f03fecd commit fce6b34

File tree

8 files changed

+87
-16
lines changed

8 files changed

+87
-16
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ interface ScanCreateFlags {
7474
reportLevel: REPORT_LEVEL
7575
setAsAlertsPage: boolean
7676
tmp: boolean
77+
workspace: string
7778
}
7879

7980
export const CMD_NAME = 'create'
@@ -165,6 +166,12 @@ const generalFlags: MeowFlags = {
165166
shortFlag: 'r',
166167
description: 'Repository name',
167168
},
169+
workspace: {
170+
type: 'string',
171+
default: '',
172+
description:
173+
'The workspace in the Socket Organization that the repository is in to associate with the full scan.',
174+
},
168175
report: {
169176
type: 'boolean',
170177
description:
@@ -319,6 +326,7 @@ async function run(
319326
branch: branchName,
320327
repo: repoName,
321328
report,
329+
workspace,
322330
} = cli.flags as unknown as ScanCreateFlags
323331

324332
let { 0: orgSlug } = await determineOrgSlug(
@@ -363,6 +371,10 @@ async function run(
363371
repoName = await getRepoName(cwd)
364372
}
365373
}
374+
if (!workspace && sockJson.defaults?.scan?.create?.workspace) {
375+
workspace = sockJson.defaults.scan.create.workspace
376+
logger.info(`Using default --workspace from ${SOCKET_JSON}:`, workspace)
377+
}
366378
if (typeof report !== 'boolean') {
367379
if (sockJson.defaults?.scan?.create?.report !== undefined) {
368380
report = sockJson.defaults.scan.create.report
@@ -639,5 +651,6 @@ async function run(
639651
reportLevel,
640652
targets,
641653
tmp: Boolean(tmp),
654+
workspace: (workspace && String(workspace)) || '',
642655
})
643656
}

packages/cli/src/commands/scan/fetch-create-org-full-scan.mts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type FetchCreateOrgFullScanConfigs = {
1414
pullRequest: number
1515
repoName: string
1616
scanType: string | undefined
17+
workspace?: string | undefined
1718
}
1819

1920
export type FetchCreateOrgFullScanOptions = {
@@ -40,6 +41,7 @@ export async function fetchCreateOrgFullScan(
4041
pullRequest,
4142
repoName,
4243
scanType,
44+
workspace,
4345
} = { __proto__: null, ...config } as FetchCreateOrgFullScanConfigs
4446

4547
const {
@@ -71,6 +73,7 @@ export async function fetchCreateOrgFullScan(
7173
...(pullRequest ? { pull_request: String(pullRequest) } : {}),
7274
...(repoName ? { repo: repoName } : {}),
7375
...(scanType ? { scan_type: scanType } : {}),
76+
...(workspace ? { workspace } : {}),
7477
...(pendingHead !== undefined
7578
? { set_as_pending_head: Boolean(pendingHead) }
7679
: {}),

packages/cli/src/commands/scan/handle-create-new-scan.mts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export type HandleCreateNewScanConfig = {
6868
reportLevel: REPORT_LEVEL
6969
targets: string[]
7070
tmp: boolean
71+
workspace?: string | undefined
7172
}
7273

7374
export async function handleCreateNewScan({
@@ -91,8 +92,12 @@ export async function handleCreateNewScan({
9192
reportLevel,
9293
targets,
9394
tmp,
95+
workspace,
9496
}: HandleCreateNewScanConfig): Promise<void> {
95-
debug('notice', `Creating new scan for ${orgSlug}/${repoName}`)
97+
debug(
98+
'notice',
99+
`Creating new scan for ${orgSlug}/${workspace ? `${workspace}/` : ''}${repoName}`,
100+
)
96101
debugDir('inspect', {
97102
autoManifest,
98103
branchName,
@@ -106,6 +111,7 @@ export async function handleCreateNewScan({
106111
reportLevel,
107112
targets,
108113
tmp,
114+
workspace,
109115
})
110116

111117
if (autoManifest) {
@@ -288,6 +294,7 @@ export async function handleCreateNewScan({
288294
scanType: reach.runReachabilityAnalysis
289295
? SCAN_TYPE_SOCKET_TIER1
290296
: SCAN_TYPE_SOCKET,
297+
workspace,
291298
},
292299
{
293300
cwd,

packages/cli/src/commands/scan/setup-scan-config.mts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { SOCKET_JSON } from '../../constants/paths.mts'
99
import {
1010
detectDefaultBranch,
1111
getRepoName,
12+
getRepoOwner,
1213
gitBranch,
1314
} from '../../utils/git/operations.mjs'
1415
import {
@@ -156,6 +157,22 @@ async function configureScan(
156157
delete config.repo
157158
}
158159

160+
const defaultWorkspace = await input({
161+
message:
162+
'(--workspace) The workspace in the Socket Organization that the repository is in to associate with the full scan.',
163+
default: config.workspace || (await getRepoOwner(cwd)) || '',
164+
required: false,
165+
// validate: async string => bool
166+
})
167+
if (defaultWorkspace === undefined) {
168+
return canceledByUser()
169+
}
170+
if (defaultWorkspace) {
171+
config.workspace = defaultWorkspace
172+
} else {
173+
delete config.workspace
174+
}
175+
159176
const defaultBranchName = await input({
160177
message:
161178
'(--branch) What branch name (slug) should be reported to Socket for this dir?',

packages/cli/src/utils/basics/vfs-extract.mts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,16 @@
1313
*/
1414

1515
import { createHash } from 'node:crypto'
16-
import { existsSync, promises as fs } from 'node:fs'
1716
import { homedir } from 'node:os'
1817
import path from 'node:path'
1918

2019
import { debug } from '@socketsecurity/lib/debug'
21-
import { safeDelete, safeMkdir } from '@socketsecurity/lib/fs'
2220
import { getDefaultLogger } from '@socketsecurity/lib/logger'
2321
import { normalizePath } from '@socketsecurity/lib/paths/normalize'
2422
import { spawn } from '@socketsecurity/lib/spawn'
2523

2624
import { UPDATE_STORE_DIR } from '../../constants/paths.mts'
27-
import { getOpengrepVersion } from '../../env/opengrep-version.mts'
28-
import { getPyCliVersion } from '../../env/pycli-version.mts'
2925
import { getPythonMajorMinor } from '../../env/python-version.mts'
30-
import { getTrivyVersion } from '../../env/trivy-version.mts'
31-
import { getTrufflehogVersion } from '../../env/trufflehog-version.mts'
3226
import { isSeaBinary } from '../sea/detect.mts'
3327

3428
const logger = getDefaultLogger()
@@ -167,7 +161,9 @@ export async function extractBasicsTools(
167161

168162
const isPlatWin = process.platform === 'win32'
169163
const tools = BASICS_TOOLS
170-
const extractedPaths: Record<string, string> = {}
164+
const extractedPaths: Partial<
165+
Record<(typeof BASICS_TOOLS)[number], string>
166+
> = {}
171167

172168
try {
173169
// Extract all tools using process.smol.mount().
@@ -195,9 +191,14 @@ export async function extractBasicsTools(
195191
// Validate all extracted binaries work after extraction.
196192
logger.group('Validating extracted basics tools...')
197193

194+
const pythonRoot = extractedPaths['python']
195+
if (!pythonRoot) {
196+
throw new Error('Failed to extract python from VFS')
197+
}
198+
198199
const pythonExe = isPlatWin ? 'python3.exe' : 'python3'
199200
const pythonPath = normalizePath(
200-
path.join(extractedPaths.python, 'bin', pythonExe),
201+
path.join(pythonRoot, 'bin', pythonExe),
201202
)
202203

203204
const validateResult = await spawn(pythonPath, ['--version'], {
@@ -239,7 +240,7 @@ export async function extractBasicsTools(
239240

240241
logger.success('Basics tools extracted and validated')
241242
// Return the Python directory path for backward compatibility.
242-
return extractedPaths.python
243+
return pythonRoot
243244
} catch (e) {
244245
logger.error('VFS extraction failed')
245246
throw e

packages/cli/src/utils/dlx/vfs-extract.mts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,17 @@ import { isSeaBinary } from '../sea/detect.mts'
7979
const logger = getDefaultLogger()
8080

8181
// External tool names bundled in VFS.
82-
// Currently only includes standalone binaries that are packaged in the VFS tarball.
83-
// npm packages (cdxgen, coana, socket-patch, synp) will be added in future updates.
84-
export const EXTERNAL_TOOLS = [
85-
'sfw',
86-
] as const
82+
// Includes standalone binaries and npm-packaged tools (with dependencies).
83+
export const EXTERNAL_TOOLS = ['cdxgen', 'coana', 'sfw', 'socket-patch', 'synp'] as const
8784

8885
export type ExternalTool = (typeof EXTERNAL_TOOLS)[number]
8986

9087
// Map of npm package tools to their node_modules/ paths.
9188
// These are full npm packages with dependencies and node_modules/ subdirectories.
9289
// Standalone binaries (like sfw) are NOT in this map - they use direct file paths.
93-
const TOOL_NPM_PATHS: Partial<Record<ExternalTool, { packageName: string; binPath: string }>> = {
90+
const TOOL_NPM_PATHS: Partial<
91+
Record<ExternalTool, { packageName: string; binPath: string }>
92+
> = {
9493
cdxgen: {
9594
packageName: '@cyclonedx/cdxgen',
9695
binPath: 'node_modules/@cyclonedx/cdxgen/bin/cdxgen',

packages/cli/src/utils/socket/json.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export interface SocketJson {
7272
repo?: string | undefined
7373
report?: boolean | undefined
7474
branch?: string | undefined
75+
workspace?: string | undefined
7576
}
7677
github?: {
7778
all?: boolean | undefined

packages/cli/test/unit/commands/scan/fetch-create-org-full-scan.test.mts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,36 @@ describe('fetchCreateOrgFullScan', () => {
9090
expect(result.ok).toBe(true)
9191
})
9292

93+
it('passes workspace when provided', async () => {
94+
const { fetchCreateOrgFullScan } = await import(
95+
'../../../../../src/commands/scan/fetch-create-org-full-scan.mts'
96+
)
97+
98+
const { mockSdk } = await setupSdkMockSuccess('createFullScan', {})
99+
100+
const config = {
101+
branchName: 'main',
102+
commitHash: 'abc123',
103+
commitMessage: 'Initial commit',
104+
committers: 'john@example.com',
105+
pullRequest: 42,
106+
repoName: 'test-repo',
107+
workspace: 'test-workspace',
108+
}
109+
110+
await fetchCreateOrgFullScan(['/path/to/package.json'], 'test-org', config)
111+
112+
expect(mockSdk.createFullScan).toHaveBeenCalledWith(
113+
'test-org',
114+
['/path/to/package.json'],
115+
expect.objectContaining({
116+
pathsRelativeTo: process.cwd(),
117+
repo: 'test-repo',
118+
workspace: 'test-workspace',
119+
}),
120+
)
121+
})
122+
93123
it('handles SDK setup failure', async () => {
94124
const { fetchCreateOrgFullScan } = await import(
95125
'../../../../../src/commands/scan/fetch-create-org-full-scan.mts'

0 commit comments

Comments
 (0)