Repository navigation
Vendored Maven on a project with both pom.xml and build.gradle reports success with no Gradle warning, the Gradle build keeps the unpatched jar, and VEX attests not_affected #395
Description
[agent] Found by the scheduled Gradle bug-hunt routine (ledger #319).
Summary
vendor_gradle_unsupported only fires when a project has a Gradle build script and no pom.xml. When a project ships both (a Maven → Gradle migration, or a repo that publishes with both), scan --mode vendored / vendor wires only the Maven <repository> and reports status: success with no Gradle-related warning. A real gradle build of the same checkout still resolves the pristine commons-text-1.10.0.jar from Maven Central, while socket-patch vex attests not_affected … (vendored).
Hosted mode already handles this shape: the rewriter emits redirect_gradle_manual_snippet whenever a build.gradle* / settings.gradle* is present, pom or not (patch/redirect/mod.rs:6680, "a project may ship both"). Vendored mode is silent in the same case.
Impact
If Gradle is the build that ships, the dependency goes out unpatched after a green scan --mode vendored, and the VEX document says the vulnerability is mitigated. Nothing in the output mentions Gradle. The only warning, vendor_maven_local_cache_shadow, is about ~/.m2.
Repro (Linux, Gradle 8.14.3 / JDK 21, main f6b7fb9)
The sandbox can't reach the Socket API, so I used a local mock of /v0/orgs/<org>/patches/{batch,by-package,view}. Its view is keyed by the jar member META-INF/NOTICE.txt with blobContent, in the same shape as e2e_vendor_maven_build.rs. MAVEN_REPO_LOCAL points at an m2 seeded with commons-text 1.10.0, because discovery can't see the Gradle cache (#349).
mkdir app && cd app
cat > settings.gradle <<'EOF'
rootProject.name = 'app'
EOF
cat > build.gradle <<'EOF'
plugins { id 'java' }
repositories { mavenCentral() }
dependencies { implementation 'org.apache.commons:commons-text:1.10.0' }
tasks.register('cp', Copy) { from configurations.runtimeClasspath; into 'build/cp' }
EOF
cat > pom.xml <<'EOF'
<project xmlns="http://maven.apache.org/POM/4.0.0"><modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId><artifactId>app</artifactId><version>1.0.0</version>
<dependencies><dependency><groupId>org.apache.commons</groupId><artifactId>commons-text</artifactId><version>1.10.0</version></dependency></dependencies>
</project>
EOF
MAVEN_REPO_LOCAL=$M2 socket-patch scan --mode vendored --vendor-source build --json --yes \
--api-url http://127.0.0.1:18099 --org test-org --api-token fake
# exit 0, status success, vendor events: applied + vendor_maven_local_cache_shadow; pom.xml gets socket-patch-vendor-<uuid>
gradle -q cp && unzip -p build/cp/commons-text-1.10.0.jar META-INF/NOTICE.txt | grep -c SOCKET-PATCH
# 0 -> Gradle consumed the unpatched Central jar (fresh GRADLE_USER_HOME too)
mvn -B -Dmaven.repo.local=$(mktemp -d) dependency:copy-dependencies -DoutputDirectory=target/mcp
unzip -p target/mcp/commons-text-1.10.0.jar META-INF/NOTICE.txt | grep -c SOCKET-PATCH
# 1 -> Maven on the same tree is patched
MAVEN_REPO_LOCAL=$M2 socket-patch vex --json --output doc.vex.json --product pkg:maven/com.example/app@1.0.0 ...
# statement: not_affected, "Patched via Socket patch 4d5e6f70-… (vendored)"It reproduced 3 times from scratch, each with a fresh project dir and a fresh GRADLE_USER_HOME.
Expected vs actual
- Expected: docs/ecosystems.md (the Maven row) and the
maven_repo.rsmodule docs justifyvendor_gradle_unsupportedby saying the vendored<repository>is something "Gradle does not consume". That holds just as much when apom.xmlsits next to the Gradle scripts. So vendored mode should at least warn, as hosted mode does withredirect_gradle_manual_snippet, that the Gradle build isn't covered. It could also refuse, or keep VEX from attesting for the Gradle build. - Actual: it reports success silently, and the Gradle build stays unpatched.
Matrix
| OS | Gradle | Mixed pom + Gradle, vendored | Gradle-only, vendored |
|---|---|---|---|
| Linux | 8.14.3 (JDK 21) | fail: success, no warning, Gradle unpatched, VEX attests | pass: vendor_gradle_unsupported, nothing written |
| macOS / Windows | — | not probed; the check is a pure file-presence test, so it's OS-independent | — |
The Gradle version doesn't matter here: Gradle never reads pom.xml repositories on any major.
Suspect code
crates/socket-patch-core/src/vendor/maven_repo.rs:246-262:project_has_gradleis consulted only in thepom.xml-missing branch.release/v5-prerelease(after feat(v5): implement vendored Maven reactors and Gradle builds #287) has the same gap:vendor/jvm/mod.rsdetect()returnsShape::Other(the legacy single-POM path) as soon as apom.xmlexists, so Gradle wiring never runs for a mixed root.
Activity
mikolalysenko commentedon Sep 30, 2026
[agent] Triaged as priority:p3 (Gradle/Maven vendored). No duplicate found; related to #349 (Gradle cache not crawled) but a separate defect:
vendor_gradle_unsupportedonly fires without a pom.xml.Generated by Claude Code
gradle: run 2 ledger (#395, #396)
mikolalysenko commentedon Oct 1, 2026
[agent] Re-triage on main
2463257(#277, the v5 consolidation that added the Gradle 6.8+ JVM vendoring backend): still reproduces, on Gradle 8.14.3 and 9.8.0 (Linux, JDK 21), 2/2 runs.I used the same tree as before: root
pom.xml(single module, literalcommons-text:1.10.0), plussettings.gradleand a Groovybuild.gradlewithrepositories { mavenCentral() }and the same dependency. Then I ranvendor --jsonagainst thee2e_vendor_jvm_buildpatch-service fixture.status: success,applied: 1. The only warnings arevendor_maven_local_cache_shadowandvendor_prebuilt_downloaded. There's no Gradle warning.pom.xmlgets the legacysocket-patch-vendor-<uuid>file://repository and.socket/vendor/maven/<uuid>/.settings.gradleis untouched: there's noapply from: '.socket/gradle/socket-patch.settings.gradle'and nogradle-index.tsv.gradle printCpresolves~/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-text/1.10.0/…/commons-text-1.10.0.jar, which is unpatched (the marker is absent fromMETA-INF/NOTICE.txt).vex --offlinestill emitsnot_affected/inline_mitigations_already_exist, "Patched via Socket patch … (vendored)".What's new: main now ships a Gradle backend that handles this exact
build.gradlecorrectly when there's nopom.xml(I verified that in the same run). Routing is the problem.crates/socket-patch-core/src/vendor/jvm/mod.rs:220(detect) returns early as soon as apom.xmlexists:Shape::Other, which means the legacy single-POM path, orShape::MavenReactor. It never checks for Gradle files, so the Gradle backend isn't reached, and no warning or refusal tells the user. The same early return also covers a Maven reactor root that has abuild.gradlebeside it.Generated by Claude Code
mikolalysenko commentedon Oct 2, 2026
[agent] Claiming this issue as part of the full Gradle support campaign (agent / hosted / vendored modes, tested on Gradle 6.9/7.6/8.x/9.x on Linux, macOS and Windows). Branch: feat/gradle-support. Claim-ID: 2026-10-02T13:56:32Z-gradle21
Generated by Claude Code
Full Gradle support in agent, hosted and vendored modes (#646)
sbt, Mill and scala-cli support in agent, hosted and vendored modes (#…