Skip to content

Commit d2bb2f4

Browse files
committed
feat(manifest): generate JVM Socket facts natively + single-run reachability sidecar (1.1.132, Coana 15.6.3)
Move the JVM build-tool resolution scripts (Gradle init script, sbt plugin, Maven core extension) and the TypeScript SBOM assembler into socket-cli, so `socket manifest` and `--auto-manifest` generate `.socket.facts.json` natively instead of delegating to the Coana CLI's `manifest` command. On `socket scan create --reach --auto-manifest` the build tool now runs exactly once and emits both the SBOM and a resolved-paths sidecar, passed to `coana run --compute-artifacts-sidecar`. Coana no longer re-resolves the build at reach time, eliminating the divergence that broke dynamically-versioned projects (git-derived versions, CI build numbers, timestamps). Build-tool binary selection prefers the project's wrapper (./gradlew, ./mvnw) and falls back to gradle/mvn on PATH. Bumps @coana-tech/cli to 15.6.3, which ships `--compute-artifacts-sidecar`.
1 parent 94484ea commit d2bb2f4

68 files changed

Lines changed: 5053 additions & 417 deletions

File tree

Some content is hidden

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

.config/rollup.dist.config.mjs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,38 @@ async function copyInitGradle() {
7979
await fs.copyFile(filepath, destPath)
8080
}
8181

82+
// Copy the JVM build-tool resolution assets (Gradle init script, sbt plugin,
83+
// Maven extension jar) into dist/manifest-scripts, where run.mts resolves them
84+
// at runtime. The Maven jar is compiled by maven-extension/build-jar.sh (run in
85+
// CI / local dev) and is absent from a fresh checkout — copy it only if present;
86+
// run.mts surfaces a build hint when it's missing.
87+
async function copyManifestScripts() {
88+
const srcDir = path.join(constants.srcPath, 'commands/manifest/scripts')
89+
const destDir = path.join(constants.distPath, 'manifest-scripts')
90+
await fs.mkdir(path.join(destDir, 'maven-extension'), { recursive: true })
91+
await Promise.all([
92+
fs.copyFile(
93+
path.join(srcDir, 'socket-facts.init.gradle'),
94+
path.join(destDir, 'socket-facts.init.gradle'),
95+
),
96+
fs.copyFile(
97+
path.join(srcDir, 'socket-facts.plugin.scala'),
98+
path.join(destDir, 'socket-facts.plugin.scala'),
99+
),
100+
])
101+
const jarPath = path.join(
102+
srcDir,
103+
'maven-extension',
104+
'coana-maven-extension.jar',
105+
)
106+
if (existsSync(jarPath)) {
107+
await fs.copyFile(
108+
jarPath,
109+
path.join(destDir, 'maven-extension', 'coana-maven-extension.jar'),
110+
)
111+
}
112+
}
113+
82114
async function copyBashCompletion() {
83115
const filepath = path.join(
84116
constants.srcPath,
@@ -464,6 +496,7 @@ export default async () => {
464496
async writeBundle() {
465497
await Promise.all([
466498
copyInitGradle(),
499+
copyManifestScripts(),
467500
copyBashCompletion(),
468501
updatePackageJson(),
469502
// Remove dist/vendor.js.map file.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Maven extension jar
2+
3+
# Builds (and smoke-tests) the Maven manifest extension jar in CI, separately
4+
# from release. Uses only allowlisted actions — notably NOT actions/setup-java
5+
# (the org allowlist forbids it), so it relies on a JDK pre-installed on the
6+
# runner via JAVA_HOME_17_X64, the same approach provenance.yml uses to build
7+
# the jar at release. Runs on changes to the extension and on demand.
8+
9+
on:
10+
pull_request:
11+
paths:
12+
- 'src/commands/manifest/scripts/maven-extension/**'
13+
- 'src/commands/manifest/scripts/test/maven-compat/**'
14+
- '.github/workflows/maven-extension-jar.yml'
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
build:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25+
with:
26+
persist-credentials: false
27+
- name: Build the Maven extension jar (pre-installed JDK; no setup-java)
28+
run: |
29+
if [ -n "${JAVA_HOME_17_X64:-}" ]; then
30+
export JAVA_HOME="$JAVA_HOME_17_X64"
31+
fi
32+
java -version
33+
bash src/commands/manifest/scripts/maven-extension/build-jar.sh
34+
- name: Verify the jar was produced
35+
run: test -f src/commands/manifest/scripts/maven-extension/coana-maven-extension.jar
36+
- name: Smoke-test the extension on Maven 3.9.9
37+
run: |
38+
if [ -n "${JAVA_HOME_17_X64:-}" ]; then
39+
export JAVA_HOME="$JAVA_HOME_17_X64"
40+
fi
41+
ver=3.9.9
42+
curl -fsSL "https://archive.apache.org/dist/maven/maven-3/$ver/binaries/apache-maven-$ver-bin.zip" -o maven.zip
43+
unzip -q maven.zip
44+
bash src/commands/manifest/scripts/test/maven-compat/smoke-test.sh \
45+
"$PWD/apache-maven-$ver/bin/mvn" \
46+
"$PWD/src/commands/manifest/scripts/maven-extension/coana-maven-extension.jar"

.github/workflows/provenance.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,18 @@ jobs:
204204
- name: Install dependencies
205205
run: pnpm install --loglevel error
206206

207+
# Compile the Maven manifest extension jar so the dist build bundles it
208+
# into dist/manifest-scripts (the jar is never committed; it ships only in
209+
# the published package). The org action allowlist forbids actions/setup-java,
210+
# so use a JDK pre-installed on the runner image (JAVA_HOME_17_X64), falling
211+
# back to the runner's default `java`. build-jar.sh uses the Maven wrapper.
212+
- name: Build Maven manifest extension jar
213+
run: |
214+
if [ -n "${JAVA_HOME_17_X64:-}" ]; then
215+
export JAVA_HOME="$JAVA_HOME_17_X64"
216+
fi
217+
pnpm run build:maven-extension
218+
207219
- run: INLINED_SOCKET_CLI_PUBLISHED_BUILD=1 pnpm run build:dist
208220
- name: Publish socket
209221
id: publish_socket

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ 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.132](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.132) - 2026-06-30
8+
9+
### Changed
10+
- More reliable reachability for Gradle, sbt, and Maven projects with dynamic versions (git versions, CI build numbers, timestamps): the build is resolved once and its artifact paths reused, avoiding spurious "failed to install" errors.
11+
- `socket manifest` and `--auto-manifest` now prefer your project's build-tool wrapper (`./gradlew`, `./mvnw`) when present, falling back to `gradle`/`mvn` on PATH.
12+
- Updated the Coana CLI to v `15.6.3`.
13+
714
## [1.1.131](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.131) - 2026-06-29
815

916
### Changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "socket",
3-
"version": "1.1.131",
3+
"version": "1.1.132",
44
"description": "CLI for Socket.dev",
55
"homepage": "https://github.com/SocketDev/socket-cli",
66
"license": "MIT",
@@ -36,6 +36,7 @@
3636
"build:dist": "pnpm build:dist:src && pnpm build:dist:types",
3737
"build:dist:src": "run-p -c clean:dist clean:external && dotenvx -q run -f .env.local -- rollup -c .config/rollup.dist.config.mjs",
3838
"build:dist:types": "pnpm clean:dist:types && tsgo --project tsconfig.dts.json",
39+
"build:maven-extension": "bash src/commands/manifest/scripts/maven-extension/build-jar.sh",
3940
"build:sea": "node src/sea/build-sea.mts",
4041
"build:sea:internal:bootstrap": "rollup -c .config/rollup.sea.config.mjs",
4142
"check": "pnpm check:lint && pnpm check:tsc",
@@ -96,7 +97,7 @@
9697
"@babel/preset-typescript": "7.27.1",
9798
"@babel/runtime": "7.28.4",
9899
"@biomejs/biome": "2.2.4",
99-
"@coana-tech/cli": "15.6.2",
100+
"@coana-tech/cli": "15.6.3",
100101
"@cyclonedx/cdxgen": "12.1.2",
101102
"@dotenvx/dotenvx": "1.49.0",
102103
"@eslint/compat": "1.3.2",

pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

socket.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@ version: 2
22

33
projectIgnorePaths:
44
- "test/fixtures/"
5+
# Build-tooling and test fixtures for the JVM manifest scripts, not socket-cli's
6+
# own supply chain: the Maven extension's build pom and the compat-test
7+
# projects' pom.xml / build.gradle / build.sbt.
8+
- "src/commands/manifest/scripts/maven-extension/"
9+
- "src/commands/manifest/scripts/test/"

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { logger } from '@socketsecurity/registry/lib/logger'
66
import { convertGradleToFacts } from './convert-gradle-to-facts.mts'
77
import { convertGradleToMaven } from './convert_gradle_to_maven.mts'
88
import { parseBuildToolOpts } from './parse-build-tool-opts.mts'
9+
import { resolveBuildToolBin } from './scripts/build-tool.mts'
910
import constants, { REQUIREMENTS_TXT, SOCKET_JSON } from '../../constants.mts'
1011
import { commonFlags } from '../../flags.mts'
1112
import { checkCommandInput } from '../../utils/check-input.mts'
@@ -28,7 +29,8 @@ const config: CliCommandConfig = {
2829
...commonFlags,
2930
bin: {
3031
type: 'string',
31-
description: 'Location of gradlew binary to use, default: CWD/gradlew',
32+
description:
33+
'Location of the gradle binary to use, default: ./gradlew if present, else gradle on PATH',
3234
},
3335
facts: {
3436
type: 'boolean',
@@ -156,7 +158,8 @@ async function run(
156158
bin = sockJson.defaults?.manifest?.gradle?.bin
157159
logger.info(`Using default --bin from ${SOCKET_JSON}:`, bin)
158160
} else {
159-
bin = path.join(cwd, 'gradlew')
161+
// Prefer the project's ./gradlew wrapper, else `gradle` on PATH.
162+
bin = resolveBuildToolBin('gradle', cwd)
160163
}
161164
}
162165
if (!gradleOpts) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe('socket manifest gradle', async () => {
2323
$ socket manifest gradle [options] [CWD=.]
2424
2525
Options
26-
--bin Location of gradlew binary to use, default: CWD/gradlew
26+
--bin Location of the gradle binary to use, default: ./gradlew if present, else gradle on PATH
2727
--exclude-configs When generating facts: comma-separated glob patterns; Gradle configurations matching any pattern are skipped (applied after --include-configs)
2828
--facts Emit a Socket facts JSON file (\`.socket.facts.json\`) describing the resolved dependency graph. This is the default; pass \`--pom\` to generate \`pom.xml\` files instead
2929
--gradle-opts Additional options to pass on to ./gradlew, see \`./gradlew --help\`

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { logger } from '@socketsecurity/registry/lib/logger'
66
import { convertGradleToFacts } from './convert-gradle-to-facts.mts'
77
import { convertGradleToMaven } from './convert_gradle_to_maven.mts'
88
import { parseBuildToolOpts } from './parse-build-tool-opts.mts'
9+
import { resolveBuildToolBin } from './scripts/build-tool.mts'
910
import constants, { REQUIREMENTS_TXT, SOCKET_JSON } from '../../constants.mts'
1011
import { commonFlags } from '../../flags.mts'
1112
import { checkCommandInput } from '../../utils/check-input.mts'
@@ -33,7 +34,8 @@ const config: CliCommandConfig = {
3334
...commonFlags,
3435
bin: {
3536
type: 'string',
36-
description: 'Location of gradlew binary to use, default: CWD/gradlew',
37+
description:
38+
'Location of the gradle binary to use, default: ./gradlew if present, else gradle on PATH',
3739
},
3840
facts: {
3941
type: 'boolean',
@@ -161,7 +163,8 @@ async function run(
161163
bin = sockJson.defaults?.manifest?.gradle?.bin
162164
logger.info(`Using default --bin from ${SOCKET_JSON}:`, bin)
163165
} else {
164-
bin = path.join(cwd, 'gradlew')
166+
// Prefer the project's ./gradlew wrapper, else `gradle` on PATH.
167+
bin = resolveBuildToolBin('gradle', cwd)
165168
}
166169
}
167170
if (!gradleOpts) {

0 commit comments

Comments
 (0)