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

cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 50aecc7432 [MNG-8419][MNG-8424] Too aggressive warning for pre-Maven4 
passwords (#1970)
50aecc7432 is described below

commit 50aecc74328d451dd82a92b7e378a217f45a6033
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Thu Dec 12 17:43:08 2024 +0100

    [MNG-8419][MNG-8424] Too aggressive warning for pre-Maven4 passwords (#1970)
    
    Toned down the Maven4 sec dispatcher messages. Also, IF maven3 passwords 
detected AND there was `.mvn/extensions.xml` the warnings were doubled.
    
    Examples:
    
    Failure to start Maven (due non-decryptable passwords):
    ```
    $ mvn clean
    [ERROR] Error executing Maven.
    [ERROR] Error building settings
     * FATAL: Could not decrypt password (fix the corrupted password or remove 
it, if unused) {xL6L/HbmrY++sNkphnq3fguYepTpM04WlIXb8nB1pk=}
     * WARNING: Detected 2 pre-Maven 4 legacy encrypted password(s) - configure 
password encryption with the help of mvnenc for increased security.
    $
    ```
    
    Warning at start (due Maven3 passwords):
    ```
    $ mvn clean
    [INFO]
    [INFO] Some problems were encountered while building the effective settings 
(use -X to see details)
    [INFO]
    [INFO] Scanning for projects...
    [INFO] 
--------------------------------------------------------------------------------------------------------------------------
    [INFO] Reactor Build Order:
    [INFO]
    [INFO] Apache Maven
    ...
    ```
    
    ---
    
    https://issues.apache.org/jira/browse/MNG-8424
    https://issues.apache.org/jira/browse/MNG-8419
---
 .../maven/api/services/MavenBuilderException.java  | 68 ++++++++++++++++++++++
 .../api/services/SettingsBuilderException.java     | 13 +----
 .../api/services/ToolchainsBuilderException.java   | 13 +----
 .../apache/maven/cling/invoker/LookupInvoker.java  | 27 ++++++---
 .../invoker/PlexusContainerCapsuleFactory.java     |  4 +-
 .../internal/impl/DefaultSettingsBuilder.java      | 26 +++++----
 .../maven/it/MavenITmng3748BadSettingsXmlTest.java |  4 ++
 .../it/MavenITmng8379SettingsDecryptTest.java      |  6 +-
 8 files changed, 118 insertions(+), 43 deletions(-)

diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenBuilderException.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenBuilderException.java
new file mode 100644
index 0000000000..1af8ab3355
--- /dev/null
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenBuilderException.java
@@ -0,0 +1,68 @@
+/*
+ * 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.api.services;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Base class for all maven exceptions carrying {@link BuilderProblem}s.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public abstract class MavenBuilderException extends MavenException {
+
+    private final List<BuilderProblem> problems;
+
+    public MavenBuilderException(String message, Throwable cause) {
+        super(message, cause);
+        problems = List.of();
+    }
+
+    public MavenBuilderException(String message, List<BuilderProblem> 
problems) {
+        super(buildMessage(message, problems), null);
+        this.problems = problems;
+    }
+
+    /**
+     * Formats message out of problems: problems are sorted (in natural order 
of {@link BuilderProblem.Severity})
+     * and then a list is built. These exceptions are usually thrown in 
"fatal" cases (and usually prevent Maven
+     * from starting), and these exceptions may end up very early on output.
+     */
+    protected static String buildMessage(String message, List<BuilderProblem> 
problems) {
+        StringBuilder msg = new StringBuilder(message);
+        ArrayList<BuilderProblem> sorted = new ArrayList<>(problems);
+        sorted.sort(Comparator.comparing(BuilderProblem::getSeverity));
+        for (BuilderProblem problem : sorted) {
+            msg.append("\n * ")
+                    .append(problem.getSeverity().name())
+                    .append(": ")
+                    .append(problem.getMessage());
+        }
+        return msg.toString();
+    }
+
+    public List<BuilderProblem> getProblems() {
+        return problems;
+    }
+}
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
index a8576b145e..c324a9250a 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
@@ -20,7 +20,6 @@ package org.apache.maven.api.services;
 
 import java.io.Serial;
 import java.util.List;
-import java.util.stream.Collectors;
 
 import org.apache.maven.api.annotations.Experimental;
 
@@ -30,28 +29,20 @@ import org.apache.maven.api.annotations.Experimental;
  * @since 4.0.0
  */
 @Experimental
-public class SettingsBuilderException extends MavenException {
+public class SettingsBuilderException extends MavenBuilderException {
 
     @Serial
     private static final long serialVersionUID = 4714858598345418083L;
 
-    private final List<BuilderProblem> problems;
-
     /**
      * @param message the message to give
      * @param e the {@link Exception}
      */
     public SettingsBuilderException(String message, Exception e) {
         super(message, e);
-        this.problems = List.of();
     }
 
     public SettingsBuilderException(String message, List<BuilderProblem> 
problems) {
-        super(message + ": " + 
problems.stream().map(BuilderProblem::toString).collect(Collectors.joining(", 
")), null);
-        this.problems = List.copyOf(problems);
-    }
-
-    public List<BuilderProblem> getProblems() {
-        return problems;
+        super(message, problems);
     }
 }
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
index b6e429dfda..89a2c8ffef 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
@@ -20,7 +20,6 @@ package org.apache.maven.api.services;
 
 import java.io.Serial;
 import java.util.List;
-import java.util.stream.Collectors;
 
 import org.apache.maven.api.annotations.Experimental;
 
@@ -30,28 +29,20 @@ import org.apache.maven.api.annotations.Experimental;
  * @since 4.0.0
  */
 @Experimental
-public class ToolchainsBuilderException extends MavenException {
+public class ToolchainsBuilderException extends MavenBuilderException {
 
     @Serial
     private static final long serialVersionUID = 7899871809665729349L;
 
-    private final List<BuilderProblem> problems;
-
     /**
      * @param message the message to give
      * @param e the {@link Exception}
      */
     public ToolchainsBuilderException(String message, Exception e) {
         super(message, e);
-        this.problems = List.of();
     }
 
     public ToolchainsBuilderException(String message, List<BuilderProblem> 
problems) {
-        super(message + ": " + 
problems.stream().map(BuilderProblem::toString).collect(Collectors.joining(", 
")), null);
-        this.problems = List.copyOf(problems);
-    }
-
-    public List<BuilderProblem> getProblems() {
-        return problems;
+        super(message, problems);
     }
 }
diff --git 
a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
 
b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
index 48c4c56c0a..348492f069 100644
--- 
a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
+++ 
b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
@@ -465,10 +465,18 @@ public abstract class LookupInvoker<C extends 
LookupContext> implements Invoker
     }
 
     protected void settings(C context) throws Exception {
-        settings(context, context.lookup.lookup(SettingsBuilder.class));
+        settings(context, true, context.lookup.lookup(SettingsBuilder.class));
     }
 
-    protected void settings(C context, SettingsBuilder settingsBuilder) throws 
Exception {
+    /**
+     * This method is invoked twice during "normal" LookupInvoker level 
startup: once when (if present) extensions
+     * are loaded up during Plexus DI creation, and once afterward as "normal" 
boot procedure.
+     * <p>
+     * If there are Maven3 passwords presents in settings, this results in 
doubled warnings emitted. So Plexus DI
+     * creation call keeps "emitSettingsWarnings" false. If there are fatal 
issues, it will anyway "die" at that
+     * spot before warnings would be emitted.
+     */
+    protected void settings(C context, boolean emitSettingsWarnings, 
SettingsBuilder settingsBuilder) throws Exception {
         Options mavenOptions = context.invokerRequest.options();
 
         Path userSettingsFile = null;
@@ -557,14 +565,17 @@ public abstract class LookupInvoker<C extends 
LookupContext> implements Invoker
         context.interactive = mayDisableInteractiveMode(context, 
context.effectiveSettings.isInteractiveMode());
         context.localRepositoryPath = localRepositoryPath(context);
 
-        if (!settingsResult.getProblems().isEmpty()) {
-            context.logger.warn("");
-            context.logger.warn("Some problems were encountered while building 
the effective settings");
+        if (emitSettingsWarnings && !settingsResult.getProblems().isEmpty()) {
+            context.logger.info("");
+            context.logger.info(
+                    "Some problems were encountered while building the 
effective settings (use -X to see details)");
 
-            for (BuilderProblem problem : settingsResult.getProblems()) {
-                context.logger.warn(problem.getMessage() + " @ " + 
problem.getLocation());
+            if (context.invokerRequest.options().verbose().orElse(false)) {
+                for (BuilderProblem problem : settingsResult.getProblems()) {
+                    context.logger.warn(problem.getMessage() + " @ " + 
problem.getLocation());
+                }
             }
-            context.logger.warn("");
+            context.logger.info("");
         }
     }
 
diff --git 
a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java
 
b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java
index 9b4d5a40a1..2f38469843 100644
--- 
a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java
+++ 
b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java
@@ -75,7 +75,7 @@ public class PlexusContainerCapsuleFactory<C extends 
LookupContext> implements C
             return new PlexusContainerCapsule(
                     context, Thread.currentThread().getContextClassLoader(), 
container(invoker, context));
         } catch (Exception e) {
-            throw new InvokerException("Failed to create plexus container 
capsule", e);
+            throw new InvokerException("Failed to create Plexus DI Container", 
e);
         }
     }
 
@@ -279,7 +279,7 @@ public class PlexusContainerCapsuleFactory<C extends 
LookupContext> implements C
             
container.getLoggerManager().setThresholds(toPlexusLoggingLevel(context.loggerLevel));
             
Thread.currentThread().setContextClassLoader(container.getContainerRealm());
 
-            invoker.settings(context, container.lookup(SettingsBuilder.class));
+            invoker.settings(context, false, 
container.lookup(SettingsBuilder.class));
 
             MavenExecutionRequest mer = new DefaultMavenExecutionRequest();
             invoker.populateRequest(context, new DefaultLookup(container), 
mer);
diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java
 
b/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java
index fd1bbfc072..e542689f61 100644
--- 
a/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java
+++ 
b/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java
@@ -29,6 +29,7 @@ import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
@@ -273,18 +274,12 @@ public class DefaultSettingsBuilder implements 
SettingsBuilder {
             return settings;
         }
         SecDispatcher secDispatcher = new DefaultSecDispatcher(dispatchers, 
getSecuritySettings(request.getSession()));
+        final AtomicInteger preMaven4Passwords = new AtomicInteger(0);
         Function<String, String> decryptFunction = str -> {
             if (str != null && !str.isEmpty() && !str.contains("${") && 
secDispatcher.isAnyEncryptedString(str)) {
                 if (secDispatcher.isLegacyEncryptedString(str)) {
                     // add a problem
-                    problems.add(new DefaultBuilderProblem(
-                            settingsSource.getLocation(),
-                            -1,
-                            -1,
-                            null,
-                            "Pre-Maven 4 legacy encrypted password detected "
-                                    + " - configure password encryption with 
the help of mvnenc to be compatible with Maven 4.",
-                            BuilderProblem.Severity.WARNING));
+                    preMaven4Passwords.incrementAndGet();
                 }
                 try {
                     return secDispatcher.decrypt(str);
@@ -295,12 +290,23 @@ public class DefaultSettingsBuilder implements 
SettingsBuilder {
                             -1,
                             e,
                             "Could not decrypt password (fix the corrupted 
password or remove it, if unused) " + str,
-                            BuilderProblem.Severity.ERROR));
+                            BuilderProblem.Severity.FATAL));
                 }
             }
             return str;
         };
-        return new SettingsTransformer(decryptFunction).visit(settings);
+        Settings result = new 
SettingsTransformer(decryptFunction).visit(settings);
+        if (preMaven4Passwords.get() > 0) {
+            problems.add(new DefaultBuilderProblem(
+                    settingsSource.getLocation(),
+                    -1,
+                    -1,
+                    null,
+                    "Detected " + preMaven4Passwords.get() + " pre-Maven 4 
legacy encrypted password(s) "
+                            + "- configure password encryption with the help 
of mvnenc for increased security.",
+                    BuilderProblem.Severity.WARNING));
+        }
+        return result;
     }
 
     private Path getSecuritySettings(ProtoSession session) {
diff --git 
a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng3748BadSettingsXmlTest.java
 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng3748BadSettingsXmlTest.java
index 235d634cc6..8dac9578b6 100644
--- 
a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng3748BadSettingsXmlTest.java
+++ 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng3748BadSettingsXmlTest.java
@@ -21,6 +21,7 @@ package org.apache.maven.it;
 import java.io.File;
 import java.util.List;
 
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -33,7 +34,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
  *
  * @author jdcasey
  *
+ * NOTE (cstamas): this IT was written to test that settings.xml is STRICT, 
while later changes modified
+ * this very IT into the opposite: to test that parsing is LENIENT.
  */
+@Disabled("This is archaic test; we should strive to make settings.xml parsing 
strict again")
 public class MavenITmng3748BadSettingsXmlTest extends 
AbstractMavenIntegrationTestCase {
 
     public MavenITmng3748BadSettingsXmlTest() {
diff --git 
a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8379SettingsDecryptTest.java
 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8379SettingsDecryptTest.java
index a615d6f2fc..fbc80d4d92 100644
--- 
a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8379SettingsDecryptTest.java
+++ 
b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8379SettingsDecryptTest.java
@@ -47,7 +47,8 @@ class MavenITmng8379SettingsDecryptTest extends 
AbstractMavenIntegrationTestCase
         verifier.verifyErrorFreeLog();
 
         // there is a warning and all fields decrypted
-        verifier.verifyTextInLog("[WARNING] Pre-Maven 4 legacy encrypted 
password detected");
+        verifier.verifyTextInLog(
+                "[INFO] Some problems were encountered while building the 
effective settings (use -X to see details)");
         verifier.verifyTextInLog("<password>testtest</password>");
         verifier.verifyTextInLog("<value>testtest</value>");
     }
@@ -69,6 +70,9 @@ class MavenITmng8379SettingsDecryptTest extends 
AbstractMavenIntegrationTestCase
         verifier.verifyErrorFreeLog();
 
         // there is no warning and all fields decrypted
+        verifier.verifyTextNotInLog("[WARNING]");
+        verifier.verifyTextNotInLog(
+                "[INFO] Some problems were encountered while building the 
effective settings (use -X to see details)");
         verifier.verifyTextInLog("<password>testtest</password>");
         verifier.verifyTextInLog("<value>secretHeader</value>");
     }

Reply via email to