@socketsecurity/cli 1.1.171 → 1.1.173

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
+ ## [1.1.173](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.173) - 2026-09-16
8
+
9
+ ### Changed
10
+ - Updated the Coana CLI to v `15.10.43`.
11
+
12
+ ## [1.1.172](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.172) - 2026-09-16
13
+
14
+ ### Added
15
+ - Added the `--reach-fallback-to-regular-scan` flag to `socket scan create`, keeping the scan moving with regular SCA results when full application reachability analysis fails. The JSON and Markdown output carry a `reachabilityFallback` marker so automation can tell a downgraded scan from a full one.
16
+
17
+ ### Changed
18
+ - Updated the Coana CLI to v `15.10.42`.
19
+
7
20
  ## [1.1.171](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.171) - 2026-09-11
8
21
 
9
22
  ### Changed
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Socket CLI
2
2
 
3
3
  [![Socket Badge](https://socket.dev/api/badge/npm/package/socket)](https://socket.dev/npm/package/socket)
4
- [![Follow @SocketSecurity](https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.171/assets/fleet/badge-follow-x.svg)](https://twitter.com/SocketSecurity)
5
- [![Follow @socket.dev on Bluesky](https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.171/assets/fleet/badge-follow-bluesky.svg)](https://bsky.app/profile/socket.dev)
4
+ [![Follow @SocketSecurity](https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.173/assets/fleet/badge-follow-x.svg)](https://twitter.com/SocketSecurity)
5
+ [![Follow @socket.dev on Bluesky](https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.173/assets/fleet/badge-follow-bluesky.svg)](https://bsky.app/profile/socket.dev)
6
6
 
7
7
  CLI for [Socket.dev](https://socket.dev) — scan dependencies, audit packages, apply security patches, and gate installs from your terminal or CI. This is the 1.x line of the published `socket` package on npm.
8
8
 
@@ -138,8 +138,8 @@ MIT
138
138
  <br/>
139
139
  <div align="center">
140
140
  <picture>
141
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.171/assets/fleet/socket-combomark-dark.svg">
142
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.171/assets/fleet/socket-combomark-light.svg">
143
- <img width="324" height="104" alt="Socket" src="https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.171/assets/fleet/socket-combomark-light.svg">
141
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.173/assets/fleet/socket-combomark-dark.svg">
142
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.173/assets/fleet/socket-combomark-light.svg">
143
+ <img width="324" height="104" alt="Socket" src="https://raw.githubusercontent.com/SocketDev/socket-cli/v1.1.173/assets/fleet/socket-combomark-light.svg">
144
144
  </picture>
145
145
  </div>
package/dist/cli.js CHANGED
@@ -1708,6 +1708,7 @@ async function outputCreateNewScan(result, options) {
1708
1708
  const {
1709
1709
  interactive = false,
1710
1710
  outputKind = 'text',
1711
+ reachabilityFallback,
1711
1712
  spinner = constants.default.spinner
1712
1713
  } = {
1713
1714
  __proto__: null,
@@ -1719,7 +1720,11 @@ async function outputCreateNewScan(result, options) {
1719
1720
  const wasSpinning = !!spinner?.isSpinning;
1720
1721
  spinner?.stop();
1721
1722
  if (outputKind === 'json') {
1722
- logger.logger.log(utils.serializeResultJson(result));
1723
+ const payload = reachabilityFallback ? {
1724
+ ...result,
1725
+ reachabilityFallback
1726
+ } : result;
1727
+ logger.logger.log(utils.serializeResultJson(payload));
1723
1728
  if (wasSpinning) {
1724
1729
  spinner.start();
1725
1730
  }
@@ -1739,6 +1744,10 @@ async function outputCreateNewScan(result, options) {
1739
1744
  if (outputKind === 'markdown') {
1740
1745
  logger.logger.log('# Create New Scan');
1741
1746
  logger.logger.log('');
1747
+ if (reachabilityFallback) {
1748
+ logger.logger.log(`Reachability analysis failed (${reachabilityFallback.message}); this Scan holds regular SCA results only.`);
1749
+ logger.logger.log('');
1750
+ }
1742
1751
  if (result.data.id) {
1743
1752
  logger.logger.log(`A [new Scan](${result.data.html_report_url}) was created with ID: ${result.data.id}`);
1744
1753
  logger.logger.log('');
@@ -7256,6 +7265,7 @@ async function handleCreateNewScan({
7256
7265
  let scanPaths = packagePaths;
7257
7266
  let tier1ReachabilityScanId;
7258
7267
  let reachabilityReport;
7268
+ let reachabilityFallback;
7259
7269
 
7260
7270
  // If reachability is enabled, perform reachability analysis.
7261
7271
  if (reach.runReachabilityAnalysis) {
@@ -7265,6 +7275,11 @@ async function handleCreateNewScan({
7265
7275
  debug.debugDir('inspect', {
7266
7276
  reachabilityOptions: mergedReachabilityOptions
7267
7277
  });
7278
+ const factsSnapshot = await utils.snapshotSocketFacts(packagePaths, {
7279
+ cwd,
7280
+ outputPath: constants.default.DOT_SOCKET_DOT_FACTS_JSON,
7281
+ tmpDir: manifestTmpDir
7282
+ });
7268
7283
  spinner.start();
7269
7284
  const reachResult = await performReachabilityAnalysis({
7270
7285
  branchName,
@@ -7280,27 +7295,39 @@ async function handleCreateNewScan({
7280
7295
  });
7281
7296
  spinner.stop();
7282
7297
  if (!reachResult.ok) {
7283
- await outputCreateNewScan(reachResult, {
7284
- interactive,
7285
- outputKind
7286
- });
7287
- return;
7298
+ if (reach.reachFallbackToRegularScan) {
7299
+ reachabilityFallback = {
7300
+ cause: reachResult.cause,
7301
+ message: reachResult.message
7302
+ };
7303
+ // Restore the pre-analysis facts files: the regular scan must upload
7304
+ // the inputs it would have had without --reach, not partial output.
7305
+ await factsSnapshot.restore();
7306
+ logger.logger.warn(`Reachability analysis failed: ${reachResult.message}${reachResult.cause ? ` — ${reachResult.cause}` : ''}. Falling back to a regular SCA scan without reachability results.`);
7307
+ } else {
7308
+ await outputCreateNewScan(reachResult, {
7309
+ interactive,
7310
+ outputKind
7311
+ });
7312
+ return;
7313
+ }
7314
+ } else {
7315
+ logger.logger.success('Reachability analysis completed successfully');
7316
+ reachabilityReport = reachResult.data?.reachabilityReport;
7317
+
7318
+ // When using only pre-generated SBOMs, build the scan from those inputs —
7319
+ // CycloneDX, SPDX, and Socket facts (`.socket.facts.json`) — matching
7320
+ // Coana's `--use-only-pregenerated-sboms` selection. Otherwise drop any
7321
+ // stray `.socket.facts.json`; coana's fresh reachability report (appended
7322
+ // below) is the authoritative facts file for the scan.
7323
+ const pathsForScan = reach.reachUseOnlyPregeneratedSboms ? filterToPregeneratedSboms(packagePaths, supportedFiles) : packagePaths.filter(p => path.basename(p) !== constants.default.DOT_SOCKET_DOT_FACTS_JSON);
7324
+
7325
+ // Append coana's reachability report, but not twice: a pre-generated facts
7326
+ // input can resolve to the same path coana wrote its report to.
7327
+ const reportPath = reachabilityReport ? path.resolve(cwd, reachabilityReport) : undefined;
7328
+ scanPaths = [...pathsForScan.filter(p => path.resolve(cwd, p) !== reportPath), ...(reachabilityReport ? [reachabilityReport] : [])];
7329
+ tier1ReachabilityScanId = reachResult.data?.tier1ReachabilityScanId;
7288
7330
  }
7289
- logger.logger.success('Reachability analysis completed successfully');
7290
- reachabilityReport = reachResult.data?.reachabilityReport;
7291
-
7292
- // When using only pre-generated SBOMs, build the scan from those inputs —
7293
- // CycloneDX, SPDX, and Socket facts (`.socket.facts.json`) — matching
7294
- // Coana's `--use-only-pregenerated-sboms` selection. Otherwise drop any
7295
- // stray `.socket.facts.json`; coana's fresh reachability report (appended
7296
- // below) is the authoritative facts file for the scan.
7297
- const pathsForScan = reach.reachUseOnlyPregeneratedSboms ? filterToPregeneratedSboms(packagePaths, supportedFiles) : packagePaths.filter(p => path.basename(p) !== constants.default.DOT_SOCKET_DOT_FACTS_JSON);
7298
-
7299
- // Append coana's reachability report, but not twice: a pre-generated facts
7300
- // input can resolve to the same path coana wrote its report to.
7301
- const reportPath = reachabilityReport ? path.resolve(cwd, reachabilityReport) : undefined;
7302
- scanPaths = [...pathsForScan.filter(p => path.resolve(cwd, p) !== reportPath), ...(reachabilityReport ? [reachabilityReport] : [])];
7303
- tier1ReachabilityScanId = reachResult.data?.tier1ReachabilityScanId;
7304
7331
  }
7305
7332
 
7306
7333
  // Brotli-compress any .socket.facts.json paths in scanPaths just before
@@ -7319,7 +7346,7 @@ async function handleCreateNewScan({
7319
7346
  pullRequest,
7320
7347
  repoName,
7321
7348
  branchName,
7322
- scanType: reach.runReachabilityAnalysis ? constants.default.SCAN_TYPE_SOCKET_TIER1 : constants.default.SCAN_TYPE_SOCKET,
7349
+ scanType: reach.runReachabilityAnalysis && !reachabilityFallback ? constants.default.SCAN_TYPE_SOCKET_TIER1 : constants.default.SCAN_TYPE_SOCKET,
7323
7350
  workspace
7324
7351
  }, {
7325
7352
  cwd,
@@ -7333,7 +7360,7 @@ async function handleCreateNewScan({
7333
7360
  const scanId = fullScanCResult.ok ? fullScanCResult.data?.id : undefined;
7334
7361
  if (reach && scanId && tier1ReachabilityScanId) {
7335
7362
  await finalizeTier1Scan(tier1ReachabilityScanId, scanId);
7336
- } else if (reach.runReachabilityAnalysis && scanId && !tier1ReachabilityScanId) {
7363
+ } else if (reach.runReachabilityAnalysis && scanId && !tier1ReachabilityScanId && !reachabilityFallback) {
7337
7364
  // Reachability analysis ran and a scan was created, but no full
7338
7365
  // application reachability scan id was extracted from the facts file.
7339
7366
  // Surface this instead of silently skipping finalize — otherwise the
@@ -7381,14 +7408,16 @@ async function handleCreateNewScan({
7381
7408
  data: fullScanCResult.data
7382
7409
  }, {
7383
7410
  interactive,
7384
- outputKind
7411
+ outputKind,
7412
+ reachabilityFallback
7385
7413
  });
7386
7414
  }
7387
7415
  } else {
7388
7416
  spinner.stop();
7389
7417
  await outputCreateNewScan(fullScanCResult, {
7390
7418
  interactive,
7391
- outputKind
7419
+ outputKind,
7420
+ reachabilityFallback
7392
7421
  });
7393
7422
  }
7394
7423
  });
@@ -7462,6 +7491,7 @@ async function handleCi(autoManifest) {
7462
7491
  reachEcosystems: [],
7463
7492
  reachEnableAnalysisSplitting: false,
7464
7493
  reachExcludePaths: [],
7494
+ reachFallbackToRegularScan: false,
7465
7495
  reachRetainFactsFile: false,
7466
7496
  reachSkipCache: false,
7467
7497
  reachUseOnlyPregeneratedSboms: false,
@@ -19373,6 +19403,11 @@ const reachabilityFlags = {
19373
19403
  hidden: true,
19374
19404
  description: 'Deprecated: use --exclude-paths instead. List of paths to exclude from reachability analysis, as either a comma separated value or as multiple flags.'
19375
19405
  },
19406
+ reachFallbackToRegularScan: {
19407
+ type: 'boolean',
19408
+ default: false,
19409
+ description: 'If reachability analysis fails, continue with a regular SCA scan (without reachability results) instead of halting. By default, the CLI halts on reachability errors.'
19410
+ },
19376
19411
  reachLazyMode: {
19377
19412
  type: 'boolean',
19378
19413
  default: false,
@@ -19668,6 +19703,7 @@ async function run$d(argv, importMeta, {
19668
19703
  reachDisableAnalytics,
19669
19704
  reachDisableExternalToolChecks,
19670
19705
  reachEnableAnalysisSplitting,
19706
+ reachFallbackToRegularScan,
19671
19707
  reachLazyMode: _reachLazyMode,
19672
19708
  reachRetainFactsFile,
19673
19709
  reachSkipCache,
@@ -19926,6 +19962,7 @@ async function run$d(argv, importMeta, {
19926
19962
  reachEcosystems,
19927
19963
  reachEnableAnalysisSplitting: Boolean(reachEnableAnalysisSplitting),
19928
19964
  reachExcludePaths,
19965
+ reachFallbackToRegularScan: Boolean(reachFallbackToRegularScan),
19929
19966
  reachRetainFactsFile: Boolean(reachRetainFactsFile),
19930
19967
  reachSkipCache: Boolean(reachSkipCache),
19931
19968
  reachUseOnlyPregeneratedSboms: Boolean(reachUseOnlyPregeneratedSboms),
@@ -20643,6 +20680,7 @@ async function scanOneRepo(repoSlug, {
20643
20680
  reachEcosystems: [],
20644
20681
  reachEnableAnalysisSplitting: false,
20645
20682
  reachExcludePaths: [],
20683
+ reachFallbackToRegularScan: false,
20646
20684
  reachRetainFactsFile: false,
20647
20685
  reachSkipCache: false,
20648
20686
  reachUseOnlyPregeneratedSboms: false,
@@ -21939,6 +21977,13 @@ const reachabilityFlagsForReach = {
21939
21977
  type: 'boolean',
21940
21978
  default: false,
21941
21979
  description: `${DYNAMIC_SBOM_INFERENCE_DESCRIPTION} The reachability analysis is split per project/module accordingly.`
21980
+ },
21981
+ // Fallback targets scan creation, which this command never performs.
21982
+ reachFallbackToRegularScan: {
21983
+ type: 'boolean',
21984
+ default: false,
21985
+ hidden: true,
21986
+ description: 'No-op: only `socket scan create --reach` falls back to a regular SCA scan on reachability failure.'
21942
21987
  }
21943
21988
  };
21944
21989
  const generalFlags = {
@@ -24093,5 +24138,5 @@ process.on('unhandledRejection', async (reason, promise) => {
24093
24138
  // eslint-disable-next-line n/no-process-exit
24094
24139
  process.exit(1);
24095
24140
  });
24096
- //# debugId=4125e182-5da6-4cc5-ae30-fed3061b33a7
24141
+ //# debugId=7293854f-1543-486e-ba22-c269ec717113
24097
24142
  //# sourceMappingURL=cli.js.map