Skip to content

Vendored Gradle exits 0 when the project's .gitignore excludes *.jar, so the commit silently drops the patched jar and every fresh checkout fails to build #620

Description

[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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions