Skip to content

Commit feb99e5

Browse files
committed
fix(cli): replace broken --dry-run with meaningful preview output
The --dry-run flag was completely broken across all 43+ commands - it just exited immediately with "[DryRun]: Bailing now" without showing users what would happen. This made the flag useless for its intended purpose. Changes: - Add new dry-run output utilities in src/utils/dry-run/output.mts - Fix all read-only commands to show "Would fetch <resource>" message - Fix all write commands to show detailed preview of actions - Fix critical commands (fix, optimize, scan create) with comprehensive previews Read-only commands now explain they're non-destructive: [DryRun]: Would fetch analytics data This is a read-only operation that does not modify any data. Write commands now show what would happen: [DryRun]: Would upload CI scan Details: organizationSlug: "my-org" branchName: "main" targets: ["."] Critical commands (fix, optimize) show detailed action plans: [DryRun]: Analyze and compute fixes for 3 vulnerabilities Actions that would be performed: - [fetch] Scan project dependencies - [modify] Update package manifest files - [execute] Run package manager to install Commands updated: - analytics, audit-log, config/*, organization/*, package/*, repository/* - scan/create, scan/del, scan/diff, scan/github, scan/list, scan/metadata - scan/reach, scan/report, scan/setup, scan/view, threat-feed - fix, optimize, ci, login, logout, oops, wrapper - npm, npx, pnpm, yarn, raw-npm, raw-npx, sfw, pycli - manifest/auto, manifest/cdxgen, manifest/conda, manifest/gradle - manifest/kotlin, manifest/scala, manifest/setup - install/completion, uninstall/completion
1 parent 25e1fcf commit feb99e5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+591
-258
lines changed

packages/cli/src/commands/analytics/cmd-analytics.mts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import { getDefaultLogger } from '@socketsecurity/lib/logger'
22

33
import { handleAnalytics } from './handle-analytics.mts'
4-
import {
5-
DRY_RUN_BAILING_NOW,
6-
FLAG_JSON,
7-
FLAG_MARKDOWN,
8-
} from '../../constants/cli.mts'
4+
import { FLAG_JSON, FLAG_MARKDOWN } from '../../constants/cli.mts'
5+
import { outputDryRunFetch } from '../../utils/dry-run/output.mts'
96
import { V1_MIGRATION_GUIDE_URL } from '../../constants/socket.mts'
107
import { commonFlags, outputFlags } from '../../flags.mts'
118
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
@@ -187,7 +184,7 @@ async function run(
187184
}
188185

189186
if (dryRun) {
190-
logger.log(DRY_RUN_BAILING_NOW)
187+
outputDryRunFetch('analytics data')
191188
return
192189
}
193190

packages/cli/src/commands/audit-log/cmd-audit-log.mts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import { getDefaultLogger } from '@socketsecurity/lib/logger'
22

33
import { handleAuditLog } from './handle-audit-log.mts'
4-
import {
5-
DRY_RUN_BAILING_NOW,
6-
FLAG_JSON,
7-
FLAG_MARKDOWN,
8-
} from '../../constants/cli.mts'
4+
import { FLAG_JSON, FLAG_MARKDOWN } from '../../constants/cli.mts'
5+
import { outputDryRunFetch } from '../../utils/dry-run/output.mts'
96
import { V1_MIGRATION_GUIDE_URL } from '../../constants/socket.mjs'
107
import { commonFlags, outputFlags } from '../../flags.mts'
118
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
@@ -182,8 +179,7 @@ async function run(
182179
}
183180

184181
if (dryRun) {
185-
const logger = getDefaultLogger()
186-
logger.log(DRY_RUN_BAILING_NOW)
182+
outputDryRunFetch('audit log entries')
187183
return
188184
}
189185

packages/cli/src/commands/ci/cmd-ci.mts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { getDefaultLogger } from '@socketsecurity/lib/logger'
22

3+
import { getDefaultOrgSlug } from './fetch-default-org-slug.mts'
34
import { handleCi } from './handle-ci.mts'
4-
import { DRY_RUN_BAILING_NOW } from '../../constants/cli.mts'
55
import { commonFlags } from '../../flags.mts'
66
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
7+
import { outputDryRunUpload } from '../../utils/dry-run/output.mts'
8+
import {
9+
detectDefaultBranch,
10+
getRepoName,
11+
gitBranch,
12+
} from '../../utils/git/operations.mjs'
713
import { getFlagListOutput } from '../../utils/output/formatting.mts'
814

915
import type {
@@ -70,11 +76,25 @@ async function run(
7076
})
7177

7278
const dryRun = !!cli.flags['dryRun']
79+
const autoManifest = Boolean(cli.flags['autoManifest'])
7380

7481
if (dryRun) {
75-
logger.log(DRY_RUN_BAILING_NOW)
82+
const orgSlugCResult = await getDefaultOrgSlug()
83+
const cwd = process.cwd()
84+
const branchName = (await gitBranch(cwd)) || (await detectDefaultBranch(cwd))
85+
const repoName = await getRepoName(cwd)
86+
87+
outputDryRunUpload('CI scan', {
88+
autoManifest,
89+
branchName: branchName || '(default)',
90+
cwd,
91+
organizationSlug: orgSlugCResult.ok ? orgSlugCResult.data : '(from API token)',
92+
repoName: repoName || '(auto-detected)',
93+
report: true,
94+
targets: ['.'],
95+
})
7696
return
7797
}
7898

79-
await handleCi(Boolean(cli.flags['autoManifest']))
99+
await handleCi(autoManifest)
80100
}

packages/cli/src/commands/config/cmd-config-auto.mts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
import { getDefaultLogger } from '@socketsecurity/lib/logger'
2-
31
import { handleConfigAuto } from './handle-config-auto.mts'
4-
import {
5-
DRY_RUN_BAILING_NOW,
6-
FLAG_JSON,
7-
FLAG_MARKDOWN,
8-
} from '../../constants/cli.mts'
2+
import { FLAG_JSON, FLAG_MARKDOWN } from '../../constants/cli.mts'
3+
import { outputDryRunWrite } from '../../utils/dry-run/output.mts'
94
import { commonFlags, outputFlags } from '../../flags.mts'
105
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
116
import {
@@ -22,8 +17,6 @@ import type {
2217
} from '../../utils/cli/with-subcommands.mjs'
2318
import type { LocalConfig } from '../../utils/config.mts'
2419

25-
const logger = getDefaultLogger()
26-
2720
// Flags interface for type safety.
2821
interface ConfigAutoFlags {
2922
json: boolean
@@ -109,7 +102,15 @@ ${getSupportedConfigEntries()
109102
}
110103

111104
if (dryRun) {
112-
logger.log(DRY_RUN_BAILING_NOW)
105+
const configPath = `${process.env['HOME']}/.config/socket/config.json`
106+
outputDryRunWrite(
107+
configPath,
108+
`auto-discover and set config value for "${key}"`,
109+
[
110+
`Discover the correct value for config key: ${key}`,
111+
`Update config file with discovered value`,
112+
],
113+
)
113114
return
114115
}
115116

packages/cli/src/commands/config/cmd-config-list.mts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import { getDefaultLogger } from '@socketsecurity/lib/logger'
22

33
import { outputConfigList } from './output-config-list.mts'
4-
import {
5-
DRY_RUN_BAILING_NOW,
6-
FLAG_JSON,
7-
FLAG_MARKDOWN,
8-
} from '../../constants/cli.mjs'
4+
import { FLAG_JSON, FLAG_MARKDOWN } from '../../constants/cli.mjs'
5+
import { outputDryRunFetch } from '../../utils/dry-run/output.mts'
96
import { commonFlags, outputFlags } from '../../flags.mts'
107
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
118
import { getFlagListOutput } from '../../utils/output/formatting.mts'
@@ -79,7 +76,7 @@ async function run(
7976
}
8077

8178
if (dryRun) {
82-
logger.log(DRY_RUN_BAILING_NOW)
79+
outputDryRunFetch('configuration settings')
8380
return
8481
}
8582

packages/cli/src/commands/config/config-command-factory.mts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
import { getDefaultLogger } from '@socketsecurity/lib/logger'
2-
3-
import {
4-
DRY_RUN_BAILING_NOW,
5-
FLAG_JSON,
6-
FLAG_MARKDOWN,
7-
} from '../../constants/cli.mjs'
1+
import { FLAG_JSON, FLAG_MARKDOWN } from '../../constants/cli.mjs'
2+
import { outputDryRunWrite } from '../../utils/dry-run/output.mts'
83
import { commonFlags, outputFlags } from '../../flags.mts'
94
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
105
import {
@@ -23,8 +18,6 @@ import type {
2318
} from '../../utils/cli/with-subcommands.mjs'
2419
import type { LocalConfig } from '../../utils/config.mts'
2520

26-
const logger = getDefaultLogger()
27-
2821
type ConfigCommandSpec = {
2922
commandName: string
3023
description: string
@@ -137,7 +130,17 @@ ${spec.helpExamples.map(ex => ` $ ${command} ${ex}`).join('\n')}
137130
}
138131

139132
if (dryRun) {
140-
logger.log(DRY_RUN_BAILING_NOW)
133+
const configPath = `${process.env['HOME']}/.config/socket/config.json`
134+
const changes = spec.needsValue
135+
? [`Set "${key}" to: ${value}`]
136+
: [`Remove "${key}" from config`]
137+
outputDryRunWrite(
138+
configPath,
139+
spec.needsValue
140+
? `set config value for "${key}"`
141+
: `unset config value for "${key}"`,
142+
changes,
143+
)
141144
return
142145
}
143146

packages/cli/src/commands/fix/cmd-fix.mts

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import terminalLink from 'terminal-link'
44

55
import { arrayUnique, joinAnd, joinOr } from '@socketsecurity/lib/arrays'
66
import { getDefaultLogger } from '@socketsecurity/lib/logger'
7+
import { pluralize } from '@socketsecurity/lib/words'
78

89
import { handleFix } from './handle-fix.mts'
9-
import { DRY_RUN_NOT_SAVING, FLAG_ID } from '../../constants/cli.mts'
10+
import { FLAG_ID } from '../../constants/cli.mts'
1011
import { ERROR_UNABLE_RESOLVE_ORG } from '../../constants/errors.mts'
1112
import * as constants from '../../constants.mts'
1213
import { commonFlags, outputFlags } from '../../flags.mts'
1314
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
15+
import { outputDryRunPreview } from '../../utils/dry-run/output.mts'
1416
import { getEcosystemChoicesForMeow } from '../../utils/ecosystem/types.mts'
1517
import {
1618
getFlagApiRequirementsOutput,
@@ -22,6 +24,8 @@ import { RangeStyles } from '../../utils/semver.mts'
2224
import { checkCommandInput } from '../../utils/validation/check-input.mts'
2325
import { getDefaultOrgSlug } from '../ci/fetch-default-org-slug.mts'
2426

27+
import type { DryRunAction } from '../../utils/dry-run/output.mts'
28+
2529
import type { MeowFlag, MeowFlags } from '../../flags.mts'
2630
import type {
2731
CliCommandConfig,
@@ -395,11 +399,6 @@ async function run(
395399
return
396400
}
397401

398-
if (dryRun) {
399-
logger.log(DRY_RUN_NOT_SAVING)
400-
return
401-
}
402-
403402
const orgSlugCResult = await getDefaultOrgSlug()
404403
if (!orgSlugCResult.ok) {
405404
process.exitCode = orgSlugCResult.code ?? 1
@@ -421,6 +420,52 @@ async function run(
421420
const includePatterns = cmdFlagValueToArray(include)
422421
const excludePatterns = cmdFlagValueToArray(exclude)
423422

423+
if (dryRun) {
424+
const actions: DryRunAction[] = [
425+
{
426+
type: 'fetch',
427+
description: 'Scan project dependencies for vulnerabilities',
428+
target: cwd,
429+
},
430+
{
431+
type: 'fetch',
432+
description: 'Analyze vulnerability fix options',
433+
},
434+
]
435+
436+
if (applyFixes) {
437+
actions.push({
438+
type: 'modify',
439+
description: 'Update package manifest files with fixes',
440+
target: 'package.json and lock files',
441+
})
442+
}
443+
444+
if (spinner) {
445+
actions.push({
446+
type: 'execute',
447+
description: 'Run package manager to install updated dependencies',
448+
})
449+
}
450+
451+
const targetDescription = all
452+
? 'all vulnerabilities'
453+
: ghsas.length
454+
? `${ghsas.length} specified ${pluralize('vulnerability', { count: ghsas.length })}`
455+
: 'discovered vulnerabilities'
456+
457+
const fixModeDescription = applyFixes
458+
? 'compute and apply fixes'
459+
: 'compute fixes only (not applying)'
460+
461+
outputDryRunPreview({
462+
summary: `Analyze and ${fixModeDescription} for ${targetDescription}`,
463+
actions,
464+
wouldSucceed: true,
465+
})
466+
return
467+
}
468+
424469
await handleFix({
425470
all,
426471
applyFixes,

packages/cli/src/commands/install/cmd-install-completion.mts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import { getDefaultLogger } from '@socketsecurity/lib/logger'
2-
31
import { handleInstallCompletion } from './handle-install-completion.mts'
4-
import { DRY_RUN_BAILING_NOW } from '../../constants/cli.mts'
2+
import { outputDryRunWrite } from '../../utils/dry-run/output.mts'
53
import { commonFlags } from '../../flags.mts'
64
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
75
import { getFlagListOutput } from '../../utils/output/formatting.mts'
@@ -67,14 +65,20 @@ async function run(
6765
})
6866

6967
const dryRun = !!cli.flags['dryRun']
68+
const targetName = cli.input[0] || 'socket'
7069

7170
if (dryRun) {
72-
const logger = getDefaultLogger()
73-
logger.log(DRY_RUN_BAILING_NOW)
71+
const bashRcPath = `${process.env['HOME']}/.bashrc`
72+
outputDryRunWrite(
73+
bashRcPath,
74+
`install bash completion for "${targetName}"`,
75+
[
76+
'Add completion script source command to ~/.bashrc',
77+
'Enable tab completion in current shell',
78+
],
79+
)
7480
return
7581
}
7682

77-
const targetName = cli.input[0] || 'socket'
78-
7983
await handleInstallCompletion(String(targetName))
8084
}

packages/cli/src/commands/login/cmd-login.mts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import isInteractive from '@socketregistry/is-interactive/index.cjs'
2-
import { getDefaultLogger } from '@socketsecurity/lib/logger'
32

43
import { attemptLogin } from './attempt-login.mts'
5-
import { DRY_RUN_BAILING_NOW } from '../../constants/cli.mts'
4+
import { outputDryRunWrite } from '../../utils/dry-run/output.mts'
65
import { commonFlags } from '../../flags.mts'
76
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
87
import { InputError } from '../../utils/error/errors.mjs'
@@ -16,8 +15,6 @@ import type {
1615
CliCommandContext,
1716
} from '../../utils/cli/with-subcommands.mjs'
1817

19-
const logger = getDefaultLogger()
20-
2118
// Flags interface for type safety.
2219
interface LoginFlags {
2320
apiBaseUrl?: string | undefined
@@ -86,7 +83,15 @@ async function run(
8683
const dryRun = !!cli.flags['dryRun']
8784

8885
if (dryRun) {
89-
logger.log(DRY_RUN_BAILING_NOW)
86+
const configPath = `${process.env['HOME']}/.config/socket/config.json`
87+
const changes = [
88+
'Prompt for Socket API token',
89+
'Verify token with Socket API',
90+
'Save API token to config',
91+
'Optionally set default organization',
92+
'Optionally install bash completion',
93+
]
94+
outputDryRunWrite(configPath, 'authenticate with Socket API', changes)
9095
return
9196
}
9297

packages/cli/src/commands/logout/cmd-logout.mts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getDefaultLogger } from '@socketsecurity/lib/logger'
22

3-
import { DRY_RUN_BAILING_NOW } from '../../constants/cli.mts'
3+
import { outputDryRunDelete } from '../../utils/dry-run/output.mts'
44
import {
55
CONFIG_KEY_API_BASE_URL,
66
CONFIG_KEY_API_PROXY,
@@ -83,7 +83,8 @@ async function run(
8383
const dryRun = !!cli.flags['dryRun']
8484

8585
if (dryRun) {
86-
logger.log(DRY_RUN_BAILING_NOW)
86+
const configPath = `${process.env['HOME']}/.config/socket/config.json`
87+
outputDryRunDelete('Socket API credentials', configPath)
8788
return
8889
}
8990

0 commit comments

Comments
 (0)