Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙️ Pengaturan Proxy Target

Skip to content

Fix Maven 4 implicit subprojects in vendor (#622) - #1807

Merged
Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-maven4-implicit-subprojects
Oct 29, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-maven4-implicit-subprojects

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #622

Summary

socket-patch vendor now plans a Maven 4 implicit-subproject reactor as a reactor. Before, a 4.1.0 pom-packaged root with no <subprojects> was planned as a reactor of one. The child module that declares the patched library kept the base version, so a warm ~/.m2 build used Central's unpatched jar, while vendor, vendor --check and vex all reported success.

Root cause

Reactor::discover (vendor/jvm/maven_reactor.rs) built the reactor only from declared <modules>/<subprojects>. Maven 4 also discovers subprojects. Checked against the Maven 4.0.0-rc-7 source (DefaultModelBuilder, "subprojects discovery") and real mvn validate runs, the rule is:

  • the model version is not 4.0.0 (<modelVersion>, else the POM namespace)
  • the packaging is literally pom
  • there is no non-empty top-level <subprojects>/<modules> (an empty <subprojects/> and profile-only modules still discover)
  • maven.project.discoverSubprojects is unset or true (Java Boolean.parseBoolean: no or empty turns it off)

When all four hold, every direct subdirectory holding a pom.xml is a subproject, hidden directories included, recursively.

Change

  • discovers_subprojects and implicit_subprojects mirror that rule. Reactor::discover adds the discovered names to the declared module refs, so nested-.mvn refusals, parent resolution, pins and rewrites all apply unchanged.
  • Every reactor entry point now takes the directory listing its caller already had (ProjectReader::list): plan*, unplan, wired*, attestable_checked, contains_module (the not-build-root guard) and external_poms_needed. So vendor, --check, vex and revert all see the same reactor.
  • The existence probe goes through the listing, not a read (see review below).

Test evidence

  • New unit tests in maven_reactor.rs:
  • Red→green: with discovery forced off, the first three fail (3 FAILED); with the fix they pass. cargo test -p socket-patch-core --lib vendor::jvm: 246 passed.
  • New e2e e2e_vendor_jvm_build::maven_reactor_implicit_subprojects_warm_and_offline_build_and_revert. It runs under the existing --ignored maven_reactor filter and skips below Maven 4. Locally on real Maven 4.0.0-rc-7 it passes: warm build, modules a and b resolve commons-text-1.10.0-socket.1d3c1fd2.jar; vex not_affected; --check ok; fresh offline build patched; revert byte-exact. With discovery forced off it fails: a/pom.xml keeps 1.10.0. The existing maven_reactor_vendor_fresh_checkout_offline_build_and_byte_exact_revert also passes on Maven 4.
  • cargo fmt --all -- --check and cargo clippy --workspace --all-features -- -D warnings are clean.
  • cargo test -p socket-patch-core -p socket-patch-cli --all-features --lib: cli 936 passed; core 6927 passed, 4 failed. All 4 are untouched permission tests that can't fail as root, which this container runs as: copy_tree::relax_loop_must_not_traverse_symlinked_root, vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry, pypi_poetry::wire_write_failure_... and pypi_requirements::wire_failure_rolls_back_.... The full workspace run (all integration binaries) filled this container's disk, so the integration suites are left to CI.

Per-issue checklist:

/code-review high

  • Fixed: .git/pom.xml probe recorded a reader error (it would break vex and --check in any git checkout). The probe now goes through the listing, with a regression test.
  • Fixed: double read of each discovered pom (same change).
  • Fixed: duplicate in-memory list helper. list_of moved to jvm::testing.
  • Not fixed, follow-up Hosted Maven and VEX treat a Maven 4 implicit-subproject root as one pom #1809: hosted redirect, hosted VEX, the sbt ambiguity guard, MavenShape and maven_scope still use declares_modules. This behavior predates this PR (hosted mode never knew about implicit subprojects), and fixing it needs child directories in the hosted file view.
  • Not fixed: an opt-out passed via the command line or MAVEN_ARGS isn't visible to vendor, which only reads .mvn/maven.config (the same limit as every other property this planner reads).
  • Fixed (also raised by Bugbot): a directory symlinked outside the checkout (e.g. target/) was refused on the probe alone. ProjectReader::list now peeks at it (files only, no escape recorded). A pom found there is still refused when read. Covered by maven_4_subproject_discovery_through_an_outbound_symlink, which fails on the previous head.

https://claude.ai/code/session_011f9aeRPZFozQNtGWwCm2ks


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
Maven 4 builds every child directory holding a pom.xml of a 4.1.0
pom-packaged root that lists no <subprojects>. vendor planned such a
root as a reactor of one, so the modules that use the patched library
kept the base version and a warm ~/.m2 build used Central's unpatched
jar, while vendor, vendor --check and vex all reported success.

The reactor walk now discovers those subprojects the way Maven 4 does
(model version, pom packaging, the maven.project.discoverSubprojects
opt-out), and every reactor entry point (plan, check, vex, revert, the
not-build-root guard) gets the directory listing it needs.

Fixes #622

Assisted-by: Claude Code:claude-opus-5-5
Discovery read each subdirectory's pom.xml to test that it exists. In a
git checkout that read went through .git/, which the project reader
refuses and records as a read error, so vex and vendor --check would
fail on every Maven 4 project that relies on discovery. Test for the
pom through the directory listing instead, which lists a refused
directory as empty, and share the in-memory listing helper between the
gradle and maven test modules.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Discovery lists every child directory to see whether it holds a
pom.xml. A directory symlinked outside the checkout, such as a target/
on another disk, was recorded as an escape on that listing alone, so
vendor refused an otherwise valid Maven 4 project. The project reader
now only peeks at such a directory (files, no subdirectories) without
recording the escape. A pom found there still becomes a module, and
reading it still refuses the build as one that leaves the checkout.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 0889de0. Configure here.

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 29, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Labeled Ready for review by the burn-down agent.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does. Fixes #622. Maven 4 (model 4.1.0) builds every direct subdirectory that has a pom.xml as a subproject when a pom-packaged parent declares no <subprojects>/<modules>. Vendor only saw declared modules, so those subprojects were left unpatched. Reactor::discover now follows Maven 4's discovery rule, including the .mvn/maven.config opt-out maven.project.discoverSubprojects. All reactor entry points (plan, unplan, wired, attestable, VEX, --check) now take a listing function, so they all see the same reactor.

Risk: low–medium. I checked the discovery gate line by line against Maven 4.0.0-rc-7 DefaultModelBuilder and it matches: namespace inference only without <modelVersion>, raw packaging, hidden directories included, empty <subprojects/> still discovers. The medium part: ProjectReader::list is shared with Gradle, and a directory symlinked outside the checkout is now listed shallowly (its subdirectories are skipped) instead of recording an escape. Reading any of its files still records the escape, so I see no bad outcome.

Look here

  • maven_reactor.rs:1499-1525:`` the opt-out plus merging discovered modules
  • maven_reactor.rs:2013-2058:``` discovers_subprojects / `implicit_subprojects`
  • apply.rs:208-258: outbound-symlink peek in ProjectReader::list (shared with Gradle)
  • maven_reactor.rs:5461-5659:```` new unit tests
  • crates/socket-patch-cli/tests/e2e_vendor_jvm_build.rs: new Maven 4 rc-7 e2e (warm, offline build, revert)

Verified

  • cargo test -p socket-patch-core --lib vendor::jvm: 247 passed; filter maven: 312 passed.
  • With discovery forced off, all 5 new maven_4_* tests fail, so they exercise the change.
  • cargo clippy -p socket-patch-core -- -D warnings is clean. The --all-targets errors are all in files this PR doesn't touch.
  • The e2e needs Maven 4, so it was not run locally; CI's rc-7 job covers it.
  • ci-ok and clippy are green on 0889de0, Bugbot threads are resolved, and CHANGELOG.md is untouched.

Changes I made: none.

Open questions (non-blocking)

  • An in-checkout symlink to an ancestor (loop -> .) under a 4.1.0 pom-packaged root makes discovery recurse without end. The same hang already exists on main via a declared <module>loop</module>, and Maven 4 can't build such a tree either. A depth cap would make it a refusal, which is worth a follow-up.
  • The opt-out is read only from .mvn/maven.config, not .mvn/maven-user.properties / ~/.m2/maven-user.properties. If one of those disables discovery, we would rewrite poms Maven doesn't build (harmless).
  • Hosted redirect and VEX still only see declared modules, as tracked in Hosted Maven and VEX treat a Maven 4 implicit-subproject root as one pom #1809.

Auto-merge (squash) is armed, so approving sends this straight to the merge queue.


Generated by Claude Code

Merged via the queue into main with commit 8ae6c83 Oct 29, 2026
50 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-maven4-implicit-subprojects branch October 29, 2026 13:40
Mikola Lysenko (mikolalysenko) pushed a commit that referenced this pull request Oct 29, 2026
main now discovers Maven 4 implicit subprojects by listing directories
(#1807), so wired_checked takes a lister. The nothing_wired check
passes the same lister the plan used, so it sees the same reactor.

Assisted-by: Claude Code:claude-opus-5-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

3 participants