Skip to content

Commit aee3509

Browse files
committed
fix(manifest): correct 1.1.125 changelog label; quote-aware build-tool opts
Address review feedback on the maven PR: - CHANGELOG: the new section is the 1.1.125 release (per package.json after the v1.x merge), so relabel its heading `1.1.124` -> `1.1.125` (the link target was already v1.1.125). - `--gradle-opts` / `--sbt-opts` / `--maven-opts` were split on every space, shredding a value with a spaced path (e.g. `-s "my settings.xml"`) into separate tokens. Introduce a shared quote-aware tokenizer (`parseBuildToolOpts`) honoring single/double quotes and use it across all manifest opts sites (gradle/kotlin/scala/maven + auto-manifest) so the fix is consistent rather than a maven-only divergence. Unquoted input tokenizes exactly as before.
1 parent c55d324 commit aee3509

8 files changed

Lines changed: 111 additions & 32 deletions

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66

7-
## [1.1.124](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.125) - 2026-06-19
7+
## [1.1.125](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.125) - 2026-06-19
88

99
### Added
1010
- New `socket manifest maven` command generates a Socket facts file (`.socket.facts.json`) directly from a Maven `pom.xml` project. Like the Gradle and sbt generators, it auto-detects your project, plugs into `socket manifest auto` and the `socket manifest setup` configurator, and accepts `--maven-opts` to pass options through to Maven (e.g. `--maven-opts="-P release -s settings.xml"`), plus `--bin` to point at a wrapper such as `./mvnw`.

src/commands/manifest/cmd-manifest-gradle.mts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { logger } from '@socketsecurity/registry/lib/logger'
55

66
import { convertGradleToFacts } from './convert-gradle-to-facts.mts'
77
import { convertGradleToMaven } from './convert_gradle_to_maven.mts'
8+
import { parseBuildToolOpts } from './parse-build-tool-opts.mts'
89
import constants, { REQUIREMENTS_TXT, SOCKET_JSON } from '../../constants.mts'
910
import { commonFlags } from '../../flags.mts'
1011
import { checkCommandInput } from '../../utils/check-input.mts'
@@ -280,10 +281,7 @@ async function run(
280281
return
281282
}
282283

283-
const parsedGradleOpts = String(gradleOpts || '')
284-
.split(' ')
285-
.map(s => s.trim())
286-
.filter(Boolean)
284+
const parsedGradleOpts = parseBuildToolOpts(String(gradleOpts || ''))
287285

288286
if (facts) {
289287
await convertGradleToFacts({

src/commands/manifest/cmd-manifest-kotlin.mts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { logger } from '@socketsecurity/registry/lib/logger'
55

66
import { convertGradleToFacts } from './convert-gradle-to-facts.mts'
77
import { convertGradleToMaven } from './convert_gradle_to_maven.mts'
8+
import { parseBuildToolOpts } from './parse-build-tool-opts.mts'
89
import constants, { REQUIREMENTS_TXT, SOCKET_JSON } from '../../constants.mts'
910
import { commonFlags } from '../../flags.mts'
1011
import { checkCommandInput } from '../../utils/check-input.mts'
@@ -283,10 +284,7 @@ async function run(
283284
return
284285
}
285286

286-
const parsedGradleOpts = String(gradleOpts || '')
287-
.split(' ')
288-
.map(s => s.trim())
289-
.filter(Boolean)
287+
const parsedGradleOpts = parseBuildToolOpts(String(gradleOpts || ''))
290288

291289
if (facts) {
292290
await convertGradleToFacts({

src/commands/manifest/cmd-manifest-maven.mts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { debugFn } from '@socketsecurity/registry/lib/debug'
44
import { logger } from '@socketsecurity/registry/lib/logger'
55

66
import { convertMavenToFacts } from './convert-maven-to-facts.mts'
7+
import { parseBuildToolOpts } from './parse-build-tool-opts.mts'
78
import constants, { SOCKET_JSON } from '../../constants.mts'
89
import { commonFlags } from '../../flags.mts'
910
import { checkCommandInput } from '../../utils/check-input.mts'
@@ -218,10 +219,7 @@ async function run(
218219
return
219220
}
220221

221-
const parsedMavenOpts = String(mavenOpts || '')
222-
.split(' ')
223-
.map(s => s.trim())
224-
.filter(Boolean)
222+
const parsedMavenOpts = parseBuildToolOpts(String(mavenOpts || ''))
225223

226224
await convertMavenToFacts({
227225
bin: String(bin),

src/commands/manifest/cmd-manifest-scala.mts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { logger } from '@socketsecurity/registry/lib/logger'
55

66
import { convertSbtToFacts } from './convert-sbt-to-facts.mts'
77
import { convertSbtToMaven } from './convert_sbt_to_maven.mts'
8+
import { parseBuildToolOpts } from './parse-build-tool-opts.mts'
89
import constants, { REQUIREMENTS_TXT, SOCKET_JSON } from '../../constants.mts'
910
import { commonFlags } from '../../flags.mts'
1011
import { checkCommandInput } from '../../utils/check-input.mts'
@@ -337,10 +338,7 @@ async function run(
337338
return
338339
}
339340

340-
const parsedSbtOpts = String(sbtOpts || '')
341-
.split(' ')
342-
.map(s => s.trim())
343-
.filter(Boolean)
341+
const parsedSbtOpts = parseBuildToolOpts(String(sbtOpts || ''))
344342

345343
if (facts) {
346344
await convertSbtToFacts({

src/commands/manifest/generate_auto_manifest.mts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { convertSbtToFacts } from './convert-sbt-to-facts.mts'
99
import { convertGradleToMaven } from './convert_gradle_to_maven.mts'
1010
import { convertSbtToMaven } from './convert_sbt_to_maven.mts'
1111
import { handleManifestConda } from './handle-manifest-conda.mts'
12+
import { parseBuildToolOpts } from './parse-build-tool-opts.mts'
1213
import { REQUIREMENTS_TXT, SOCKET_JSON } from '../../constants.mts'
1314
import { readOrDefaultSocketJson } from '../../utils/socket-json.mts'
1415

@@ -45,11 +46,7 @@ export async function generateAutoManifest({
4546
// Note: `sbt` is more likely to be resolved against PATH env.
4647
bin: sockJson.defaults?.manifest?.sbt?.bin ?? 'sbt',
4748
cwd,
48-
sbtOpts:
49-
sockJson.defaults?.manifest?.sbt?.sbtOpts
50-
?.split(' ')
51-
.map(s => s.trim())
52-
.filter(Boolean) ?? [],
49+
sbtOpts: parseBuildToolOpts(sockJson.defaults?.manifest?.sbt?.sbtOpts),
5350
verbose: Boolean(sockJson.defaults?.manifest?.sbt?.verbose),
5451
}
5552
// Socket facts is the default; opt into pom generation with
@@ -83,11 +80,9 @@ export async function generateAutoManifest({
8380
: path.join(cwd, 'gradlew'),
8481
cwd,
8582
verbose: Boolean(sockJson.defaults?.manifest?.gradle?.verbose),
86-
gradleOpts:
87-
sockJson.defaults?.manifest?.gradle?.gradleOpts
88-
?.split(' ')
89-
.map(s => s.trim())
90-
.filter(Boolean) ?? [],
83+
gradleOpts: parseBuildToolOpts(
84+
sockJson.defaults?.manifest?.gradle?.gradleOpts,
85+
),
9186
}
9287
// Socket facts is the default; opt into pom generation with
9388
// `defaults.manifest.gradle.facts: false` in socket.json.
@@ -124,11 +119,9 @@ export async function generateAutoManifest({
124119
sockJson.defaults?.manifest?.maven?.ignoreUnresolved,
125120
),
126121
includeConfigs: sockJson.defaults?.manifest?.maven?.includeConfigs ?? '',
127-
mavenOpts:
128-
sockJson.defaults?.manifest?.maven?.mavenOpts
129-
?.split(' ')
130-
.map(s => s.trim())
131-
.filter(Boolean) ?? [],
122+
mavenOpts: parseBuildToolOpts(
123+
sockJson.defaults?.manifest?.maven?.mavenOpts,
124+
),
132125
verbose: Boolean(sockJson.defaults?.manifest?.maven?.verbose),
133126
})
134127
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Tokenizes a build-tool options string (e.g. the value of `--gradle-opts`,
2+
// `--sbt-opts`, `--maven-opts`) into individual argv tokens. Splits on
3+
// whitespace but honors single and double quotes so a value containing spaces,
4+
// such as a settings path (`-s "my settings.xml"`), survives as one token
5+
// instead of being shredded into three. Quotes are consumed (not emitted), and
6+
// quoting is intra-token aware (`-Dkey="a b"` -> `-Dkey=a b`). For unquoted
7+
// input this is equivalent to the previous whitespace split.
8+
export function parseBuildToolOpts(opts: string | undefined): string[] {
9+
if (!opts) {
10+
return []
11+
}
12+
const tokens: string[] = []
13+
let current = ''
14+
let hasToken = false
15+
let inSingle = false
16+
let inDouble = false
17+
for (let i = 0; i < opts.length; i += 1) {
18+
const ch = opts[i]
19+
if (inSingle) {
20+
if (ch === "'") {
21+
inSingle = false
22+
} else {
23+
current += ch
24+
}
25+
} else if (inDouble) {
26+
if (ch === '"') {
27+
inDouble = false
28+
} else {
29+
current += ch
30+
}
31+
} else if (ch === "'") {
32+
inSingle = true
33+
hasToken = true
34+
} else if (ch === '"') {
35+
inDouble = true
36+
hasToken = true
37+
} else if (ch === ' ' || ch === '\t') {
38+
if (hasToken) {
39+
tokens.push(current)
40+
current = ''
41+
hasToken = false
42+
}
43+
} else {
44+
current += ch
45+
hasToken = true
46+
}
47+
}
48+
if (hasToken) {
49+
tokens.push(current)
50+
}
51+
return tokens
52+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { describe, expect, it } from 'vitest'
2+
3+
import { parseBuildToolOpts } from './parse-build-tool-opts.mts'
4+
5+
describe('parseBuildToolOpts', () => {
6+
it('returns an empty array for empty/undefined input', () => {
7+
expect(parseBuildToolOpts(undefined)).toEqual([])
8+
expect(parseBuildToolOpts('')).toEqual([])
9+
expect(parseBuildToolOpts(' ')).toEqual([])
10+
})
11+
12+
it('splits a plain space-separated string (parity with the old split)', () => {
13+
expect(parseBuildToolOpts('-P release -s settings.xml')).toEqual([
14+
'-P',
15+
'release',
16+
'-s',
17+
'settings.xml',
18+
])
19+
})
20+
21+
it('collapses runs of whitespace and trims', () => {
22+
expect(parseBuildToolOpts(' -P release ')).toEqual(['-P', 'release'])
23+
})
24+
25+
it('keeps a double-quoted value with spaces as one token', () => {
26+
expect(parseBuildToolOpts('-s "my settings.xml"')).toEqual([
27+
'-s',
28+
'my settings.xml',
29+
])
30+
})
31+
32+
it('keeps a single-quoted value with spaces as one token', () => {
33+
expect(parseBuildToolOpts("-s 'my settings.xml'")).toEqual([
34+
'-s',
35+
'my settings.xml',
36+
])
37+
})
38+
39+
it('handles quotes inside a token', () => {
40+
expect(parseBuildToolOpts('-Dprop="a b"')).toEqual(['-Dprop=a b'])
41+
})
42+
})

0 commit comments

Comments
 (0)