Skip to content

Vendored Maven reactor ignores user properties set in .mvn/maven.config as --define=k=v or -D k=v, so a 1.11.0 build is silently downgraded to 1.10.0-socket.* with no warning #535

Description

[agent] Found by the scheduled Maven bug-hunt routine (ledger #318).

Summary

The reactor planner reads user properties from an existing .mvn/maven.config so that a -Dct.version=1.11.0 override beats a pom's <ct.version>1.10.0</ct.version>. With the compact -Dk=v spelling, that works: the planner emits conflicting_literal_version and doesn't pin. But cli_properties only recognises tokens that start with -D and contain =:

fn cli_properties(config: &str) -> BTreeMap<String, String> {
config
.split_whitespace()
.filter_map(|t| t.strip_prefix("-D")?.split_once('='))
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect()
}

Two other spellings that Maven itself honours are therefore missed:

  • --define=ct.version=1.11.0 (the long option). Maven 3.6.3, 3.8.8, 3.9.11 and 4.0.0-rc-7 all apply it.
  • -D ct.version=1.11.0 (option and value as separate tokens). Maven 3.6.3, 3.8.8 and 3.9.11 apply it; 4.0.0-rc-7 ignores it.

The planner then interpolates ${ct.version} from the pom's <properties> (1.10.0), rewrites the dependency version to the literal 1.10.0-socket.<hex>, and reports applied: 1 with no warning. The build that resolved 1.11.0 before vendoring now resolves 1.10.0-socket.*: a silent downgrade.

This is the same failure family as #459 (profile <properties>) and #488 (BOM / external parent), but the trigger here is different: the planner misparses the user-property source it already tries to honour.

Impact

  • A project that pins a newer, already fixed version through .mvn/maven.config is silently downgraded to the older base plus the patch. Every fix in 1.11.0 that's outside the patch is lost.
  • vendor exits 0 with applied: 1 and no conflicting_literal_version warning, so nothing tells the user.
  • The rewritten literal replaces ${ct.version} in the pom, so a later bump of the property in maven.config no longer takes effect either.

Repro

A reactor with an aggregator root, corp-parent/ and modules a and b (the e2e_vendor_jvm_build::maven_reactor fixture). Module a:

<properties><ct.version>1.10.0</ct.version></properties>
<dependencies><dependency>
  <groupId>org.apache.commons</groupId><artifactId>commons-text</artifactId>
  <version>${ct.version}</version>
</dependency></dependencies>
printf -- '--define=ct.version=1.11.0\n' > .mvn/maven.config
mvn -B package org.apache.maven.plugins:maven-dependency-plugin:3.5.0:build-classpath -Dmdep.outputFile=target/cp.txt
#   a/target/cp.txt → commons-text-1.11.0.jar
# stage the commons-text 1.10.0 patch manifest (as the capstone does), then
socket-patch vendor --json --offline
#   applied: 1; warnings: only maven_f_outside_root / maven_mirror_of_all (no conflicting_literal_version)
#   a/pom.xml: <version>${ct.version}</version> → <version>1.10.0-socket.1d3c1fd2</version>
#   .mvn/maven.config keeps --define=ct.version=1.11.0 and gains the two socket-patch lines
mvn -B package ...build-classpath...
#   a/target/cp.txt → .socket/vendor/maven2/.../commons-text-1.10.0-socket.1d3c1fd2.jar   ← downgraded

Control: the same project with -Dct.version=1.11.0 gives conflicting_literal_version, no pin, and the build stays on 1.11.0 (3.6.3 / 3.8.8 / 3.9.11 / 4.0.0-rc-7).

Expected vs actual

  • Expected: docs/design/maven-vendoring.md: "Range selectors, unresolved properties, … conflicting explicit versions … produce specific warnings; the backend does not silently claim those unsupported declarations are patched." The planner's own rule ("User properties win over model properties, as in Maven", lookup) should hold for every user-property spelling that Maven accepts in maven.config. Failing that, it should warn when a maven.config token it can't parse could define a property.
  • Actual: --define= and -D k=v are skipped, and the module's resolved version is silently replaced by the patched base.

Matrix (Linux, JDK 21, main 61cfb9b)

Maven --define=ct.version=1.11.0 -D ct.version=1.11.0 -Dct.version=1.11.0 (control)
3.6.3 fail: 1.11.0 → 1.10.0-socket.* fail: 1.11.0 → 1.10.0-socket.* pass (warned, stays 1.11.0)
3.8.8 fail fail pass
3.9.11 fail (reproduced 2×) fail pass
4.0.0-rc-7 fail (reproduced 2×) n/a: Maven 4 itself ignores this form (pre-vendor build is already 1.10.0) pass

macOS and Windows weren't probed. The parsing is OS-independent.

Related: --define ct.version=1.11.0 on one line is rejected by 3.9.11 and 4.0.0-rc-7 themselves ("Unrecognized option"), so it isn't part of this bug. A quoted -Dct.version="1.11.0" makes every Maven line fail to build.

First bad commit

2463257 (#277, the v5 consolidation that added the reactor planner and cli_properties). It isn't in any release yet (latest release 4.0.0).

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