diff --git a/CHANGELOG.md b/CHANGELOG.md index eaebd3e3c4..f06c3518c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [1.1.144](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.144) - 2026-07-23 + +### Fixed +- `--reach-ecosystems` now rejects ecosystems the reachability engine cannot analyze, failing fast at the CLI with a clear message listing the supported ecosystems instead of erroring partway through a scan. + ## [1.1.143](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.143) - 2026-07-10 ### Changed diff --git a/package.json b/package.json index 50bc833bda..22e8547aa1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "socket", - "version": "1.1.143", + "version": "1.1.144", "description": "CLI for Socket.dev", "homepage": "https://github.com/SocketDev/socket-cli", "license": "MIT", diff --git a/src/commands/scan/cmd-scan-create.mts b/src/commands/scan/cmd-scan-create.mts index 6f00ebb95b..3de7991f44 100644 --- a/src/commands/scan/cmd-scan-create.mts +++ b/src/commands/scan/cmd-scan-create.mts @@ -1,7 +1,6 @@ import { existsSync } from 'node:fs' import path from 'node:path' -import { joinAnd } from '@socketsecurity/registry/lib/arrays' import { logger } from '@socketsecurity/registry/lib/logger' import { assertValidExcludePaths } from './exclude-paths.mts' @@ -20,7 +19,7 @@ import { commonFlags, outputFlags } from '../../flags.mts' import { checkCommandInput } from '../../utils/check-input.mts' import { cmdFlagValueToArray } from '../../utils/cmd.mts' import { determineOrgSlug } from '../../utils/determine-org-slug.mts' -import { getEcosystemChoicesForMeow } from '../../utils/ecosystem.mts' +import { parseReachEcosystems } from '../../utils/ecosystem.mts' import { getOutputKind } from '../../utils/get-output-kind.mts' import { detectDefaultBranch, @@ -39,7 +38,6 @@ import { detectManifestActions } from '../manifest/detect-manifest-actions.mts' import type { REPORT_LEVEL } from './types.mts' import type { MeowFlags } from '../../flags.mts' -import type { PURL_Type } from '../../utils/ecosystem.mts' import type { CliCommandConfig, CliCommandContext, @@ -308,18 +306,10 @@ async function run( reachVersion: string | undefined } - // Validate ecosystem values. - const reachEcosystems: PURL_Type[] = [] - const reachEcosystemsRaw = cmdFlagValueToArray(cli.flags['reachEcosystems']) - const validEcosystems = getEcosystemChoicesForMeow() - for (const ecosystem of reachEcosystemsRaw) { - if (!validEcosystems.includes(ecosystem)) { - throw new Error( - `Invalid ecosystem: "${ecosystem}". Valid values are: ${joinAnd(validEcosystems)}`, - ) - } - reachEcosystems.push(ecosystem as PURL_Type) - } + // Validate ecosystem values against the reachability-supported set. + const reachEcosystems = parseReachEcosystems( + cmdFlagValueToArray(cli.flags['reachEcosystems']), + ) const dryRun = !!cli.flags['dryRun'] diff --git a/src/commands/scan/cmd-scan-create.test.mts b/src/commands/scan/cmd-scan-create.test.mts index a02b1ead25..2693871f33 100644 --- a/src/commands/scan/cmd-scan-create.test.mts +++ b/src/commands/scan/cmd-scan-create.test.mts @@ -67,7 +67,7 @@ describe('socket scan create', async () => { --reach-detailed-analysis-log-file A log file with detailed analysis logs is written to root of each analyzed workspace. --reach-disable-analytics Disable reachability analytics sharing with Socket. Also disables caching-based optimizations. --reach-disable-external-tool-checks Disable external tool checks during reachability analysis. - --reach-ecosystems List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Defaults to all ecosystems. + --reach-ecosystems List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Supported: cargo, composer, gem, golang, maven, npm, nuget, pypi. Defaults to all supported ecosystems. --reach-enable-analysis-splitting Allow the reachability analysis to partition CVEs into buckets that are processed in separate analysis runs. May improve accuracy, but not recommended by default. --reach-retain-facts-file Keep the \`.socket.facts.json\` reachability report that the analysis writes to the scan directory instead of deleting it after a successful scan. IMPORTANT: you must delete this file before running a fresh full application reachability scan. A stale \`.socket.facts.json\` left in place is picked up as a pre-generated input and silently overrides fresh analysis, so the new scan results will not be reliable. --reach-skip-cache Skip caching-based optimizations. By default, the reachability analysis will use cached configurations from previous runs to speed up the analysis. diff --git a/src/commands/scan/cmd-scan-reach.mts b/src/commands/scan/cmd-scan-reach.mts index 5bd4e3b410..1c11faddb8 100644 --- a/src/commands/scan/cmd-scan-reach.mts +++ b/src/commands/scan/cmd-scan-reach.mts @@ -1,6 +1,5 @@ import path from 'node:path' -import { joinAnd } from '@socketsecurity/registry/lib/arrays' import { logger } from '@socketsecurity/registry/lib/logger' import { assertValidExcludePaths } from './exclude-paths.mts' @@ -13,7 +12,7 @@ import { commonFlags, outputFlags } from '../../flags.mts' import { checkCommandInput } from '../../utils/check-input.mts' import { cmdFlagValueToArray } from '../../utils/cmd.mts' import { determineOrgSlug } from '../../utils/determine-org-slug.mts' -import { getEcosystemChoicesForMeow } from '../../utils/ecosystem.mts' +import { parseReachEcosystems } from '../../utils/ecosystem.mts' import { getOutputKind } from '../../utils/get-output-kind.mts' import { meowOrExit } from '../../utils/meow-with-subcommands.mts' import { @@ -23,7 +22,6 @@ import { import { hasDefaultApiToken } from '../../utils/sdk.mts' import type { MeowFlags } from '../../flags.mts' -import type { PURL_Type } from '../../utils/ecosystem.mts' import type { CliCommandConfig, CliCommandContext, @@ -176,17 +174,8 @@ async function run( const reachExcludePaths = cmdFlagValueToArray(cli.flags['reachExcludePaths']) assertValidExcludePaths(excludePaths) - // Validate ecosystem values. - const reachEcosystems: PURL_Type[] = [] - const validEcosystems = getEcosystemChoicesForMeow() - for (const ecosystem of reachEcosystemsRaw) { - if (!validEcosystems.includes(ecosystem)) { - throw new Error( - `Invalid ecosystem: "${ecosystem}". Valid values are: ${joinAnd(validEcosystems)}`, - ) - } - reachEcosystems.push(ecosystem as PURL_Type) - } + // Validate ecosystem values against the reachability-supported set. + const reachEcosystems = parseReachEcosystems(reachEcosystemsRaw) const processCwd = process.cwd() const cwd = diff --git a/src/commands/scan/cmd-scan-reach.test.mts b/src/commands/scan/cmd-scan-reach.test.mts index 223821336c..21d925bdf2 100644 --- a/src/commands/scan/cmd-scan-reach.test.mts +++ b/src/commands/scan/cmd-scan-reach.test.mts @@ -49,7 +49,7 @@ describe('socket scan reach', async () => { --reach-detailed-analysis-log-file A log file with detailed analysis logs is written to root of each analyzed workspace. --reach-disable-analytics Disable reachability analytics sharing with Socket. Also disables caching-based optimizations. --reach-disable-external-tool-checks Disable external tool checks during reachability analysis. - --reach-ecosystems List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Defaults to all ecosystems. + --reach-ecosystems List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Supported: cargo, composer, gem, golang, maven, npm, nuget, pypi. Defaults to all supported ecosystems. --reach-enable-analysis-splitting Allow the reachability analysis to partition CVEs into buckets that are processed in separate analysis runs. May improve accuracy, but not recommended by default. --reach-retain-facts-file Keep the \`.socket.facts.json\` reachability report that the analysis writes to the scan directory instead of deleting it after a successful scan. IMPORTANT: you must delete this file before running a fresh full application reachability scan. A stale \`.socket.facts.json\` left in place is picked up as a pre-generated input and silently overrides fresh analysis, so the new scan results will not be reliable. --reach-skip-cache Skip caching-based optimizations. By default, the reachability analysis will use cached configurations from previous runs to speed up the analysis. @@ -291,6 +291,27 @@ describe('socket scan reach', async () => { }, ) + cmdit( + [ + 'scan', + 'reach', + '--reach-ecosystems', + 'conda', + '--org', + 'fakeOrg', + FLAG_CONFIG, + '{"apiToken":"fakeToken"}', + ], + 'should reject a purl type that lacks reachability support', + async cmd => { + const { code, stderr, stdout } = await spawnSocketCli(binCliPath, cmd) + const output = stdout + stderr + expect(output).toContain('Invalid ecosystem: "conda"') + expect(output).toContain('maven') + expect(code, 'should exit with non-zero code').not.toBe(0) + }, + ) + cmdit( [ 'scan', diff --git a/src/commands/scan/reachability-flags.mts b/src/commands/scan/reachability-flags.mts index 1b50af689c..9f4dc6e891 100644 --- a/src/commands/scan/reachability-flags.mts +++ b/src/commands/scan/reachability-flags.mts @@ -1,4 +1,5 @@ import constants from '../../constants.mts' +import { getReachabilityEcosystemChoices } from '../../utils/ecosystem.mts' import type { MeowFlags } from '../../flags.mts' @@ -88,8 +89,7 @@ export const reachabilityFlags: MeowFlags = { reachEcosystems: { type: 'string', isMultiple: true, - description: - 'List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Defaults to all ecosystems.', + description: `List of ecosystems to conduct reachability analysis on, as either a comma separated value or as multiple flags. Supported: ${getReachabilityEcosystemChoices().join(', ')}. Defaults to all supported ecosystems.`, }, reachExcludePaths: { type: 'string', diff --git a/src/utils/ecosystem.mts b/src/utils/ecosystem.mts index 8afa35b53e..c514c21961 100644 --- a/src/utils/ecosystem.mts +++ b/src/utils/ecosystem.mts @@ -22,7 +22,10 @@ * - Ensures type safety for ecosystem operations */ +import { joinAnd } from '@socketsecurity/registry/lib/arrays' + import { NPM } from '../constants.mts' +import { InputError } from './errors.mts' import type { EcosystemString } from '@socketsecurity/registry' import type { components } from '@socketsecurity/sdk/types/api' @@ -87,10 +90,29 @@ export type _Check_ALL_ECOSYSTEMS_has_no_extras = export const ALL_SUPPORTED_ECOSYSTEMS = new Set(ALL_ECOSYSTEMS) +// Purl types accepted by Coana's reachability `--purl-types` gate +// (@coana-tech/cli `getAdvisoryEcosystemFromPurlType`), narrower than +// ALL_ECOSYSTEMS. Values outside this set are rejected by the engine at scan +// time, so we validate up front. Keep in sync when bumping @coana-tech/cli. +export const REACHABILITY_SUPPORTED_ECOSYSTEMS = [ + 'cargo', + 'composer', + 'gem', + 'golang', + 'maven', + NPM, + 'nuget', + 'pypi', +] as const satisfies readonly PURL_Type[] + export function getEcosystemChoicesForMeow(): string[] { return [...ALL_ECOSYSTEMS] } +export function getReachabilityEcosystemChoices(): string[] { + return [...REACHABILITY_SUPPORTED_ECOSYSTEMS] +} + export function isValidEcosystem(value: string): value is PURL_Type { return ALL_SUPPORTED_ECOSYSTEMS.has(value) } @@ -108,3 +130,17 @@ export function parseEcosystems( return values.filter(isValidEcosystem) } + +export function parseReachEcosystems(raw: readonly string[]): PURL_Type[] { + const choices = getReachabilityEcosystemChoices() + const result: PURL_Type[] = [] + for (const ecosystem of raw) { + if (!choices.includes(ecosystem)) { + throw new InputError( + `Invalid ecosystem: "${ecosystem}". Valid values are: ${joinAnd(choices)}`, + ) + } + result.push(ecosystem as PURL_Type) + } + return result +}