Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Changed
- **Bazel diagnostics** — `socket manifest bazel --verbose` now emits bounded subprocess traces with argv, cwd, duration, exit status, output sizes, and failure stderr tails to make customer log-only triage safer and faster.

## [1.1.109](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.109) - 2026-05-28

### Added
- **`socket fix --exclude-paths`** — Skip matching paths from the scan entirely: manifests under these paths are not uploaded, and fixes are not applied to workspaces under them. Use this to skip directories the current user cannot read (e.g. a postgres `pgdata` directory inside the repo) so they do not abort manifest collection. The pre-existing `--exclude` flag keeps its previous fix-application-only semantic but is now hidden in `--help` in favor of `--exclude-paths`.

## [1.1.108](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.108) - 2026-05-28

### Changed
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "socket",
"version": "1.1.108",
"version": "1.1.109",
"description": "CLI for Socket.dev",
"homepage": "https://github.com/SocketDev/socket-cli",
"license": "MIT AND OFL-1.1",
Expand Down
2 changes: 1 addition & 1 deletion src/commands/fix/cmd-fix.integration.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ describe('socket fix', async () => {
--debug Enable debug logging in the Coana-based Socket Fix CLI invocation.
--disable-external-tool-checks Disable external tool checks during fix analysis.
--ecosystems Limit fix analysis to specific ecosystems. Accepts space- or comma-separated values and is case-insensitive. Defaults to all ecosystems.
--exclude Exclude workspaces matching these glob patterns. Can be provided as comma separated values or as multiple flags
--exclude-paths Skip matching paths from the scan entirely: manifests under these paths are not uploaded, and fixes are not applied to workspaces under them. Patterns are anchored micromatch globs matched relative to the target directory (CWD); \`data/postgres/pgdata\` matches that exact path, \`**/pgdata\` matches at any depth. Use this to skip directories the current user cannot read so they do not abort manifest collection. Negation patterns (\`!path\`) are not supported. Accepts a comma-separated value or multiple flags.
--fix-version Override the version of @coana-tech/cli used for fix analysis. Default: <coana-version>.
--id Provide a list of vulnerability identifiers to compute fixes for:
- GHSA IDs (https://docs.github.com/en/code-security/security-advisories/working-with-global-security-advisories-from-the-github-advisory-database/about-the-github-advisory-database#about-ghsa-ids) (e.g., GHSA-xxxx-xxxx-xxxx)
Expand Down
32 changes: 29 additions & 3 deletions src/commands/fix/cmd-fix.mts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
} from '../../utils/package-manager.mts'
import { RangeStyles } from '../../utils/semver.mts'
import { getDefaultOrgSlug } from '../ci/fetch-default-org-slug.mts'
import { assertValidExcludePaths } from '../scan/exclude-paths.mts'

import type { MeowFlag, MeowFlags } from '../../flags.mts'
import type { PURL_Type } from '../../utils/ecosystem.mts'
Expand Down Expand Up @@ -82,6 +83,18 @@ const generalFlags: MeowFlags = {
description:
'Exclude workspaces matching these glob patterns. Can be provided as comma separated values or as multiple flags',
isMultiple: true,
// Hidden in favor of --exclude-paths, which covers both manifest
// discovery and workspace filtering. --exclude is preserved for
// backwards compatibility with the narrower (fix-application only)
// semantic.
hidden: true,
},
excludePaths: {
type: 'string',
default: [],
description:
'Skip matching paths from the scan entirely: manifests under these paths are not uploaded, and fixes are not applied to workspaces under them. Patterns are anchored micromatch globs matched relative to the target directory (CWD); `data/postgres/pgdata` matches that exact path, `**/pgdata` matches at any depth. Use this to skip directories the current user cannot read so they do not abort manifest collection. Negation patterns (`!path`) are not supported. Accepts a comma-separated value or multiple flags.',
isMultiple: true,
hidden: false,
},
include: {
Expand Down Expand Up @@ -314,6 +327,7 @@ async function run(
disableExternalToolChecks,
ecosystems,
exclude,
excludePaths,
fixVersion,
include,
json,
Expand All @@ -339,6 +353,7 @@ async function run(
disableExternalToolChecks: boolean
ecosystems: string[]
exclude: string[]
excludePaths: string[]
fixVersion: string | undefined
include: string[]
json: boolean
Expand Down Expand Up @@ -464,6 +479,19 @@ async function run(
return
}

const includePatterns = cmdFlagValueToArray(include)
const excludePatterns = cmdFlagValueToArray(exclude)
const excludePathsPatterns = cmdFlagValueToArray(excludePaths)
// Validate before the network round-trip so a bad pattern doesn't waste
// an org-slug API call.
try {
assertValidExcludePaths(excludePathsPatterns)
} catch (e) {
logger.fail((e as Error).message)
process.exitCode = 1
return
}

if (dryRun) {
logger.log(constants.DRY_RUN_NOT_SAVING)
return
Expand All @@ -482,9 +510,6 @@ async function run(

const { spinner } = constants

const includePatterns = cmdFlagValueToArray(include)
const excludePatterns = cmdFlagValueToArray(exclude)

await handleFix({
all,
applyFixes,
Expand All @@ -496,6 +521,7 @@ async function run(
disableMajorUpdates,
ecosystems: validatedEcosystems,
exclude: excludePatterns,
excludePaths: excludePathsPatterns,
ghsas,
include: includePatterns,
minimumReleaseAge,
Expand Down
24 changes: 22 additions & 2 deletions src/commands/fix/coana-fix.mts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
} from '../../utils/github.mts'
import { getPackageFilesForScan } from '../../utils/path-resolve.mts'
import { setupSdk } from '../../utils/sdk.mts'
import { excludePathToScanIgnores } from '../scan/exclude-paths.mts'
import { fetchSupportedScanFileNames } from '../scan/fetch-supported-scan-file-names.mts'

import type { FixConfig } from './types.mts'
Expand Down Expand Up @@ -129,6 +130,7 @@ export async function coanaFix(
disableMajorUpdates,
ecosystems,
exclude,
excludePaths,
ghsas,
include,
minimumReleaseAge,
Expand Down Expand Up @@ -171,7 +173,21 @@ export async function coanaFix(
? socketYmlResult.data?.parsed
: undefined

// Expand user-supplied `--exclude-paths` patterns into the fast-glob ignore
// form so manifest discovery skips them. Without this an unreadable
// subdirectory (e.g. a postgres `pgdata` owned by another uid) would crash
// `socket fix` before coana is even invoked.
const additionalIgnores = excludePaths.length
? excludePaths.flatMap(excludePathToScanIgnores)
: undefined
// Forward --exclude-paths to coana's workspace filter too, so a workspace
// matching the pattern is also skipped during fix application even when
// its manifest somehow made it into the upload (e.g. picked up via a
// sibling manifest's references). --exclude stays separate as a hidden
// legacy escape hatch for the narrower "fix-application only" semantic.
const coanaExcludePatterns = [...exclude, ...excludePaths]
const scanFilepaths = await getPackageFilesForScan(['.'], supportedFiles, {
additionalIgnores,
config: socketConfig,
cwd,
})
Expand Down Expand Up @@ -289,7 +305,9 @@ export async function coanaFix(
? ['--minimum-release-age', minimumReleaseAge]
: []),
...(include.length ? ['--include', ...include] : []),
...(exclude.length ? ['--exclude', ...exclude] : []),
...(coanaExcludePatterns.length
? ['--exclude', ...coanaExcludePatterns]
: []),
...(ecosystems.length ? ['--purl-types', ...ecosystems] : []),
...(packageManagers.length
? ['--package-managers', ...packageManagers]
Expand Down Expand Up @@ -451,7 +469,9 @@ export async function coanaFix(
? ['--minimum-release-age', minimumReleaseAge]
: []),
...(include.length ? ['--include', ...include] : []),
...(exclude.length ? ['--exclude', ...exclude] : []),
...(coanaExcludePatterns.length
? ['--exclude', ...coanaExcludePatterns]
: []),
...(ecosystems.length ? ['--purl-types', ...ecosystems] : []),
...(packageManagers.length
? ['--package-managers', ...packageManagers]
Expand Down
60 changes: 60 additions & 0 deletions src/commands/fix/handle-fix-limit.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ describe('socket fix --pr-limit behavior verification', () => {
disableMajorUpdates: false,
ecosystems: [],
exclude: [],
excludePaths: [],
ghsas: [],
include: [],
minSatisfying: false,
Expand Down Expand Up @@ -448,4 +449,63 @@ describe('socket fix --pr-limit behavior verification', () => {
expect(ghsaArgs).toEqual(['GHSA-1111-1111-1111'])
})
})

describe('--exclude-paths flag', () => {
it('passes excludePaths to getPackageFilesForScan as anchored ignore patterns', async () => {
mockSpawnCoanaDlx.mockResolvedValue({ ok: true, data: 'fix applied' })

await coanaFix({
...baseConfig,
excludePaths: ['data/postgres/pgdata', '**/.cache'],
ghsas: ['GHSA-1111-1111-1111'],
})

expect(mockGetPackageFilesForScan).toHaveBeenCalledTimes(1)
const [, , opts] = mockGetPackageFilesForScan.mock.calls[0] ?? []
// excludePathToScanIgnores emits both the entry itself and a /** sibling
// unless the user already passed a /** suffix.
expect(opts.additionalIgnores).toEqual([
'data/postgres/pgdata',
'data/postgres/pgdata/**',
'**/.cache',
'**/.cache/**',
])
})

it('omits additionalIgnores when excludePaths is empty', async () => {
mockSpawnCoanaDlx.mockResolvedValue({ ok: true, data: 'fix applied' })

await coanaFix({
...baseConfig,
excludePaths: [],
ghsas: ['GHSA-1111-1111-1111'],
})

expect(mockGetPackageFilesForScan).toHaveBeenCalledTimes(1)
const [, , opts] = mockGetPackageFilesForScan.mock.calls[0] ?? []
expect(opts.additionalIgnores).toBeUndefined()
})

it('forwards excludePaths to coana --exclude alongside --exclude values', async () => {
mockSpawnCoanaDlx.mockResolvedValue({ ok: true, data: 'fix applied' })

await coanaFix({
...baseConfig,
exclude: ['legacy-workspace'],
excludePaths: ['data/postgres/pgdata'],
ghsas: ['GHSA-1111-1111-1111'],
})

expect(mockSpawnCoanaDlx).toHaveBeenCalledTimes(1)
const callArgs = mockSpawnCoanaDlx.mock.calls[0]?.[0] as string[]
const excludeIndex = callArgs.indexOf('--exclude')
expect(excludeIndex).toBeGreaterThan(-1)
// --exclude is followed by every pattern from both sources, in order:
// legacy --exclude entries first, then --exclude-paths entries.
expect(callArgs.slice(excludeIndex + 1, excludeIndex + 3)).toEqual([
'legacy-workspace',
'data/postgres/pgdata',
])
})
})
})
3 changes: 3 additions & 0 deletions src/commands/fix/handle-fix.mts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export async function handleFix({
disableMajorUpdates,
ecosystems,
exclude,
excludePaths,
ghsas,
include,
minSatisfying,
Expand Down Expand Up @@ -152,6 +153,7 @@ export async function handleFix({
disableMajorUpdates,
ecosystems,
exclude,
excludePaths,
ghsas,
include,
minSatisfying,
Expand Down Expand Up @@ -179,6 +181,7 @@ export async function handleFix({
disableMajorUpdates,
ecosystems,
exclude,
excludePaths,
// Convert mixed CVE/GHSA/PURL inputs to GHSA IDs only.
ghsas: await convertIdsToGhsas(ghsas, { silence }),
include,
Expand Down
1 change: 1 addition & 0 deletions src/commands/fix/types.mts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type FixConfig = {
disableMajorUpdates: boolean
ecosystems: PURL_Type[]
exclude: string[]
excludePaths: string[]
ghsas: string[]
include: string[]
minimumReleaseAge: string
Expand Down
Loading