[agent] Found by the scheduled Gradle bug-hunt routine (ledger #319).
Summary
GitHub's standard Java.gitignore template (which many Gradle repos start from) ignores *.jar. When a project like that runs socket-patch vendor, the patched jar lands in .socket/vendor/gradle/<g>/<a>/<v>/<a>-<v>.jar, and that path is git-ignored. vendor still exits 0 with status: success and no warning, and vendor --check on the working tree passes too. The local build uses the patched jar, so everything looks fine to the person who ran it. Then git add .socket settings.gradle / git add -A quietly skips the ignored jar, and every other checkout (CI, teammates) fails at configuration time:
> socket-patch: vendored file missing: …/.socket/vendor/gradle/org/apache/commons/commons-text/1.10.0/commons-text-1.10.0.jar. Restore it from git or re-run `socket-patch vendor`.
npm and vlt vendoring already handle this exact case. npm_dir.rs runs git check-ignore over the payload and refuses with vendor_artifact_gitignored (npm_dir.rs:673, vlt_lock.rs:764), and the vlt layout writes a .gitignore with !* to re-include the payload against project ignores (docs/ecosystems.md, vlt "Vendored: directory artifacts"). The Gradle tree writes a .gitattributes (gradle.rs:32) so that autocrlf checkouts stay byte-exact, but it has no ignore check and no re-include .gitignore.
Impact
It fails closed: the build errors, and on the fresh clone vendor --check exits 1 and vex omits the purl with vendor_artifact_missing, so there's no false attestation. But the person running vendor gets a success, and the breakage only shows up after the push, on someone else's machine or in CI. The error message tells them to "re-run socket-patch vendor", which rebuilds the jar locally, but the next commit drops it again.
Repro (Linux, main 045d7ec)
mkdir proj && cd proj
printf '*.jar\n.gradle\n**/build/\n!gradle/wrapper/gradle-wrapper.jar\n' > .gitignore # github/gitignore Java + Gradle excerpt
echo "rootProject.name='p'" > settings.gradle
cat > build.gradle <<'EOF'
plugins { id 'java' }
repositories { mavenCentral() }
dependencies { implementation 'org.apache.commons:commons-text:1.10.0' }
tasks.register('printCp') { doLast { configurations.runtimeClasspath.files.each { println "CP " + it } } }
EOF
git init -q && git add -A && git commit -qm init
# stage a vendored-mode record for pkg:maven/org.apache.commons/commons-text@1.10.0 in .socket/manifest.json
socket-patch vendor --json # exit 0, "status":"success", applied 1, no warnings
socket-patch vendor --check --json # exit 0
git status --porcelain --ignored | grep '!!'
# !! .socket/vendor/gradle/org/apache/commons/commons-text/1.10.0/commons-text-1.10.0.jar
gradle -q printCp | grep commons-text # CP …/.socket/vendor/gradle/…/commons-text-1.10.0.jar (patched, locally)
git add .socket settings.gradle && git commit -qm vendor
git ls-files .socket | grep -c '\.jar$' # 0, the jar was never committed
cd .. && git clone -q proj fresh && cd fresh
gradle -q printCp # FAILURE: socket-patch: vendored file missing: …commons-text-1.10.0.jar
(The routine ran this through the repo's fixture server, prebuilt_common::prepare_command, with a NOTICE-marker patch, and pointed mavenCentral at a seeded file:// m2 because Central rate-limits the sandbox.) It reproduced 2 out of 2 times from clean directories.
Expected vs actual
- Expected: a vendored artifact the project's own ignore rules exclude should be caught when
vendor runs, as npm and vlt already do (vendor_artifact_gitignored). Either refuse, or write a .socket/vendor/gradle/.gitignore that re-includes the tree (!*), the same way the vlt layout does. README describes vendored mode as committing the patched artifact so fresh checkouts build patched with no network access. That only holds if the artifact can actually be committed.
- Actual:
vendor and vendor --check both exit 0 with no warning, and the jar can't be committed with a normal git add.
Matrix
| OS |
Gradle (JDK) |
DSL |
vendor |
vendor --check (pre-commit) |
jar committed |
fresh-clone build |
| Linux |
8.14.3 (21) |
Groovy |
exit 0, no warning ❌ |
exit 0 ❌ |
no |
fails loudly |
| Linux |
9.8.0 (21) |
Kotlin |
exit 0, no warning ❌ |
exit 0 ❌ |
no |
fails loudly |
| Linux |
8.14.3 (21) |
Groovy, no *.jar rule (control) |
exit 0 |
exit 0 |
yes |
patched (existing capstone) |
| macOS / Windows, Gradle 6 / 7 |
untested. This is git check-ignore semantics, so it should be OS- and version-independent. |
|
|
|
|
|
First bad
Vendored Gradle is new in v5 (#287, 2463257). v4.0.0 has no Gradle vendoring.
Suspect code
crates/socket-patch-core/src/vendor/jvm/mod.rs:439 (vendor) / crates/socket-patch-core/src/vendor/jvm/apply.rs:269 (write_plan): there's no gitignore_probe over the planned tree, unlike npm_dir.rs:673.
crates/socket-patch-core/src/vendor/jvm/gradle.rs:32: the tree gets GITATTRIBUTES_REL but no re-include .gitignore.
- The vendored Maven reactor tree (
.socket/vendor/maven2/, apply.rs:939) looks like it has the same gap. I didn't test it, since that's outside this routine's package manager, so I've handed it to the Maven routine.
No probe run: the sandbox git proxy can't delete probe branches.
[agent] Found by the scheduled Gradle bug-hunt routine (ledger #319).
Summary
GitHub's standard
Java.gitignoretemplate (which many Gradle repos start from) ignores*.jar. When a project like that runssocket-patch vendor, the patched jar lands in.socket/vendor/gradle/<g>/<a>/<v>/<a>-<v>.jar, and that path is git-ignored.vendorstill exits 0 withstatus: successand no warning, andvendor --checkon the working tree passes too. The local build uses the patched jar, so everything looks fine to the person who ran it. Thengit add .socket settings.gradle/git add -Aquietly skips the ignored jar, and every other checkout (CI, teammates) fails at configuration time:npm and vlt vendoring already handle this exact case.
npm_dir.rsrunsgit check-ignoreover the payload and refuses withvendor_artifact_gitignored(npm_dir.rs:673,vlt_lock.rs:764), and the vlt layout writes a.gitignorewith!*to re-include the payload against project ignores (docs/ecosystems.md, vlt "Vendored: directory artifacts"). The Gradle tree writes a.gitattributes(gradle.rs:32) so thatautocrlfcheckouts stay byte-exact, but it has no ignore check and no re-include.gitignore.Impact
It fails closed: the build errors, and on the fresh clone
vendor --checkexits 1 andvexomits the purl withvendor_artifact_missing, so there's no false attestation. But the person runningvendorgets a success, and the breakage only shows up after the push, on someone else's machine or in CI. The error message tells them to "re-runsocket-patch vendor", which rebuilds the jar locally, but the next commit drops it again.Repro (Linux, main
045d7ec)(The routine ran this through the repo's fixture server,
prebuilt_common::prepare_command, with a NOTICE-marker patch, and pointedmavenCentralat a seededfile://m2 because Central rate-limits the sandbox.) It reproduced 2 out of 2 times from clean directories.Expected vs actual
vendorruns, as npm and vlt already do (vendor_artifact_gitignored). Either refuse, or write a.socket/vendor/gradle/.gitignorethat re-includes the tree (!*), the same way the vlt layout does. README describes vendored mode as committing the patched artifact so fresh checkouts build patched with no network access. That only holds if the artifact can actually be committed.vendorandvendor --checkboth exit 0 with no warning, and the jar can't be committed with a normalgit add.Matrix
*.jarrule (control)git check-ignoresemantics, so it should be OS- and version-independent.First bad
Vendored Gradle is new in v5 (#287,
2463257). v4.0.0 has no Gradle vendoring.Suspect code
crates/socket-patch-core/src/vendor/jvm/mod.rs:439(vendor) /crates/socket-patch-core/src/vendor/jvm/apply.rs:269(write_plan): there's nogitignore_probeover the planned tree, unlikenpm_dir.rs:673.crates/socket-patch-core/src/vendor/jvm/gradle.rs:32: the tree getsGITATTRIBUTES_RELbut no re-include.gitignore..socket/vendor/maven2/,apply.rs:939) looks like it has the same gap. I didn't test it, since that's outside this routine's package manager, so I've handed it to the Maven routine.No probe run: the sandbox git proxy can't delete probe branches.