You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/05/19 10:03:40 UTC

(maven) branch backport-11983-to-4.0.x created (now a45d213586)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a change to branch backport-11983-to-4.0.x
in repository https://gitbox.apache.org/repos/asf/maven.git


      at a45d213586 Add IT for mvn script expanding ${...} in CLI arguments

This branch includes the following new commits:

     new b41303b2b1 Fix mvn script expanding ${...} in CLI arguments
     new a45d213586 Add IT for mvn script expanding ${...} in CLI arguments

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(maven) 01/02: Fix mvn script expanding ${...} in CLI arguments

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch backport-11983-to-4.0.x
in repository https://gitbox.apache.org/repos/asf/maven.git

commit b41303b2b16e117349bd0a6db3639cf1ec45f5b5
Author: Gerd Aschemann <ge...@aschemann.net>
AuthorDate: Fri Apr 24 09:08:46 2026 +0200

    Fix mvn script expanding ${...} in CLI arguments
    
    The eval in the mvn script causes shell expansion of ${...} patterns
    in user-provided arguments. Pass user arguments directly via "$@"
    instead of concatenating them into the eval string. This preserves
    MAVEN_OPTS word splitting while preventing unintended shell expansion.
    
    Fixes #11978
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <no...@anthropic.com>
---
 apache-maven/src/assembly/maven/bin/mvn | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/apache-maven/src/assembly/maven/bin/mvn b/apache-maven/src/assembly/maven/bin/mvn
index 1a8e6a2fdc..914f61a42b 100755
--- a/apache-maven/src/assembly/maven/bin/mvn
+++ b/apache-maven/src/assembly/maven/bin/mvn
@@ -275,7 +275,7 @@ handle_args() {
 handle_args "$@"
 MAVEN_MAIN_CLASS=${MAVEN_MAIN_CLASS:=org.apache.maven.cling.MavenCling}
 
-# Build command string for eval
+# Build base command string for eval (only contains Maven-controlled values)
 cmd="\"$JAVACMD\" \
   $MAVEN_OPTS \
   $MAVEN_DEBUG_OPTS \
@@ -289,14 +289,12 @@ cmd="\"$JAVACMD\" \
   $LAUNCHER_CLASS \
   $MAVEN_ARGS"
 
-# Add remaining arguments with proper quoting
-for arg in "$@"; do
-    cmd="$cmd \"$arg\""
-done
-
 if [ -n "$MAVEN_DEBUG_SCRIPT" ]; then
   echo "[DEBUG] Launching JVM with command:" >&2
-  echo "[DEBUG]   $cmd" >&2
+  echo "[DEBUG]   $cmd" "$@" >&2
 fi
 
-eval exec "$cmd"
+# User arguments ("$@") are passed directly to preserve literal values
+# like ${...} Maven property placeholders without shell expansion.
+# Only the base command uses eval for MAVEN_OPTS word splitting.
+eval exec "$cmd" '"$@"'


(maven) 02/02: Add IT for mvn script expanding ${...} in CLI arguments

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch backport-11983-to-4.0.x
in repository https://gitbox.apache.org/repos/asf/maven.git

commit a45d213586d497057af642e655bace8a86a9c413
Author: Gerd Aschemann <ge...@aschemann.net>
AuthorDate: Sun Apr 26 15:44:34 2026 +0200

    Add IT for mvn script expanding ${...} in CLI arguments
    
    The eval in the mvn script causes shell expansion of ${...} patterns
    in user-provided arguments. This regression test exercises the actual
    launcher script via setForkJvm(true) and verifies that ${...} is not
    expanded by the shell.
    
    Related: #11978
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <no...@anthropic.com>
---
 .../it/MavenITgh11978PlaceholderInCliArgTest.java  | 107 +++++++++++++++++++++
 .../gh-11978-placeholder-in-cli-arg/pom.xml        |  58 +++++++++++
 2 files changed, 165 insertions(+)

diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11978PlaceholderInCliArgTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11978PlaceholderInCliArgTest.java
new file mode 100644
index 0000000000..eac9f09dd3
--- /dev/null
+++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11978PlaceholderInCliArgTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.it;
+
+import java.nio.file.Path;
+import java.util.Properties;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * This is a test set for <a href="https://github.com/apache/maven/issues/11978">gh-11978</a>.
+ *
+ * Verifies that the launcher script does not expand <code>${...}</code> patterns
+ * in CLI arguments. Regression test for the {@code eval exec} shell expansion
+ * that broke any argument containing Maven property placeholders.
+ *
+ * <h2>Real-world scenario</h2>
+ *
+ * <p>This bug was originally surfaced by maven-surefire-plugin integration tests.
+ * Surefire allows users to declare system properties for the forked test JVM with
+ * placeholders that surefire substitutes <em>at fork time</em>, e.g.
+ * {@code -DtestProperty=testValue_${surefire.threadNumber}_${surefire.forkNumber}}.
+ * The intended flow is:
+ * <ol>
+ *   <li>The user invokes {@code mvn} with the literal placeholder on the CLI.</li>
+ *   <li>The launcher script must pass the literal {@code ${...}} verbatim to
+ *       the JVM as a system property value.</li>
+ *   <li>The surefire plugin reads the system property, performs <em>its own</em>
+ *       interpolation when forking each test JVM, replacing
+ *       {@code ${surefire.threadNumber}} and {@code ${surefire.forkNumber}}
+ *       with the actual fork/thread numbers.</li>
+ *   <li>Each forked test JVM thus sees a unique substituted value.</li>
+ * </ol>
+ *
+ * <p>The bug broke step 2: the launcher script's {@code eval exec} re-parsed
+ * the command string and invoked shell variable expansion on {@code ${...}}.
+ * Names containing dots (such as {@code surefire.threadNumber}) are invalid
+ * shell variable names, so the shell aborted with {@code bad substitution}
+ * before Maven even started, breaking all surefire forked-test ITs that relied
+ * on this pattern.
+ *
+ * <h2>Test design</h2>
+ *
+ * <p>The placeholder name contains dots, mirroring surefire's real usage and
+ * deliberately producing an invalid shell variable name. Without the fix:
+ * <ul>
+ *   <li>The shell's {@code eval exec} aborts with {@code bad substitution}.</li>
+ *   <li>The build fails immediately and {@link Verifier#verifyErrorFreeLog()}
+ *       catches it.</li>
+ * </ul>
+ * With the fix:
+ * <ul>
+ *   <li>The literal {@code ${...}} arrives at Maven as a system property value.</li>
+ *   <li>Maven's recursive property interpolation resolves the unknown placeholder
+ *       to an empty string when reading {@code ${test.placeholder}} from the POM.</li>
+ *   <li>The resulting value is {@code -value__end-}.</li>
+ * </ul>
+ *
+ * <p>Note: this test cannot easily replicate surefire's late-binding interpolation
+ * (step 3 above) because Maven's standard property interpolation does not
+ * recursively resolve POM properties for placeholders embedded inside a system
+ * property value. Surefire performs that substitution in its own plugin code at
+ * fork time. The signal that proves the fix works is the absence of a
+ * {@code bad substitution} shell error, not the resolved value itself.
+ */
+class MavenITgh11978PlaceholderInCliArgTest extends AbstractMavenIntegrationTestCase {
+
+    @Test
+    void testIt() throws Exception {
+        Path basedir = extractResources("/gh-11978-placeholder-in-cli-arg")
+                .getAbsoluteFile()
+                .toPath();
+
+        Verifier verifier = newVerifier(basedir.toString());
+        verifier.setForkJvm(true); // NOTE: We want to go through the launcher script
+        // The placeholder name contains dots, which is invalid as a shell variable name.
+        // Without the fix, the shell's `eval exec` aborts with "bad substitution".
+        // With the fix, the literal ${...} arrives at Maven.
+        verifier.addCliArgument("-Dtest.placeholder=value_${some.maven.placeholder}_end");
+        verifier.addCliArgument("validate");
+        verifier.execute();
+        verifier.verifyErrorFreeLog(); // key check: fails immediately on shell crash
+
+        // Sanity check: the value flowed through Maven, which resolves the unknown
+        // ${some.maven.placeholder} to empty during recursive interpolation.
+        Properties props = verifier.loadProperties("target/pom.properties");
+        assertEquals("-value__end-", props.getProperty("project.properties.pom.placeholder"));
+    }
+}
diff --git a/its/core-it-suite/src/test/resources/gh-11978-placeholder-in-cli-arg/pom.xml b/its/core-it-suite/src/test/resources/gh-11978-placeholder-in-cli-arg/pom.xml
new file mode 100644
index 0000000000..b55ef8a120
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/gh-11978-placeholder-in-cli-arg/pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.its.gh11978</groupId>
+  <artifactId>test</artifactId>
+  <version>1.0</version>
+
+  <name>Maven Integration Test :: GH-11978</name>
+  <description>Verify that the launcher script does not expand ${...} placeholders in CLI arguments.</description>
+
+  <properties>
+    <pom.placeholder>-${test.placeholder}-</pom.placeholder>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.its.plugins</groupId>
+        <artifactId>maven-it-plugin-expression</artifactId>
+        <version>2.1-SNAPSHOT</version>
+        <executions>
+          <execution>
+            <id>test</id>
+            <goals>
+              <goal>eval</goal>
+            </goals>
+            <phase>validate</phase>
+            <configuration>
+              <outputFile>target/pom.properties</outputFile>
+              <expressions>
+                <expression>project/properties</expression>
+              </expressions>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>