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

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


The following commit(s) were added to refs/heads/maven-4.0.x by this push:
     new 8f7bdee4c4 [maven-4.0.x] Fix mvn script expanding ${...} in CLI 
arguments (#12095)
8f7bdee4c4 is described below

commit 8f7bdee4c4afee3f2e5174d1ade839ef16dca0c7
Author: Guillaume Nodet <[email protected]>
AuthorDate: Wed May 20 06:18:16 2026 +0200

    [maven-4.0.x] Fix mvn script expanding ${...} in CLI arguments (#12095)
    
    * 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) <[email protected]>
    
    * 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) <[email protected]>
    
    * Fix IT compilation: add required version range constructor for 4.0.x
    
    * Apply review suggestions from #11983
    
    - Use printf in mvn debug output so each user arg is shown
      individually quoted, preserving boundary information.
    - Trim IT Javadoc to match codebase style.
    - Reword assertion comments to make primary/secondary priority
      explicit.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    ---------
    
    Co-authored-by: Gerd Aschemann <[email protected]>
    Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
---
 apache-maven/src/assembly/maven/bin/mvn            | 14 +++--
 .../it/MavenITgh11978PlaceholderInCliArgTest.java  | 63 ++++++++++++++++++++++
 .../gh-11978-placeholder-in-cli-arg/pom.xml        | 58 ++++++++++++++++++++
 3 files changed, 127 insertions(+), 8 deletions(-)

diff --git a/apache-maven/src/assembly/maven/bin/mvn 
b/apache-maven/src/assembly/maven/bin/mvn
index 1a8e6a2fdc..04b149010b 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
+  printf '[DEBUG]   %s' "$cmd" >&2; printf ' "%s"' "$@" >&2; echo >&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" '"$@"'
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..b62259e18b
--- /dev/null
+++ 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11978PlaceholderInCliArgTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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>.
+ *
+ * <p>Verifies that the launcher script does not expand {@code ${...}} patterns
+ * in CLI arguments. The placeholder name intentionally contains dots (invalid 
as a
+ * shell variable name) so without the fix, {@code eval exec} aborts with
+ * {@code bad substitution} before Maven even starts.
+ */
+class MavenITgh11978PlaceholderInCliArgTest extends 
AbstractMavenIntegrationTestCase {
+
+    MavenITgh11978PlaceholderInCliArgTest() {
+        super("[4.0.0-rc-1,)");
+    }
+
+    @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(); // primary check: shell crash produces 
non-zero exit
+
+        // Secondary: verify the literal placeholder flowed through Maven.
+        // Maven resolves the unknown ${some.maven.placeholder} to empty.
+        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>

Reply via email to