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

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


The following commit(s) were added to refs/heads/maven-3.10.x by this push:
     new e2c2b82736 Update to Resolver 2.0.21 (#12504)
e2c2b82736 is described below

commit e2c2b82736762a0fa250a1940a73241cf32fbb98
Author: Tamas Cservenak <[email protected]>
AuthorDate: Sun Jul 19 20:06:04 2026 +0200

    Update to Resolver 2.0.21 (#12504)
    
    ## Pull request overview
    
    Updates Maven’s embedded Resolver integration to the targeted 2.0.21 line 
and wires in additional validation to catch malformed/uninterpolated 
coordinates and invalid metadata version/path components earlier in the 
resolution pipeline.
    
    **Changes:**
    - Bumps the Maven Resolver version property to 2.0.21-SNAPSHOT.
    - Introduces a validating metadata reader and switches multiple metadata 
read paths to use it.
    - Adds a Resolver `Validator` + `ValidatorFactory` to reject 
placeholder-containing coordinates and validate artifact/metadata components.
---
 .../metadata/DefaultRepositoryMetadataManager.java |  4 +-
 .../metadata/AbstractRepositoryMetadata.java       |  4 +-
 .../metadata/io/DefaultMetadataReader.java         |  6 +-
 .../maven/internal/aether/MavenValidator.java      | 91 ++++++++++++++++++++++
 .../internal/aether/MavenValidatorFactory.java     | 37 +++++++++
 .../internal/DefaultVersionRangeResolver.java      |  7 +-
 .../internal/DefaultVersionResolver.java           |  7 +-
 .../maven/repository/internal/MavenMetadata.java   |  4 +-
 .../metadata/ValidatingMetadataXpp3Reader.java     | 75 ++++++++++++++++++
 pom.xml                                            |  2 +-
 10 files changed, 221 insertions(+), 16 deletions(-)

diff --git 
a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
 
b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
index 54ca354e2b..14f73e1290 100644
--- 
a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
+++ 
b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
@@ -33,8 +33,8 @@
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
 import org.apache.maven.artifact.repository.RepositoryRequest;
-import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
 import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
+import 
org.apache.maven.repository.internal.metadata.ValidatingMetadataXpp3Reader;
 import org.apache.maven.repository.legacy.UpdateCheckManager;
 import org.apache.maven.repository.legacy.WagonManager;
 import org.apache.maven.wagon.ResourceDoesNotExistException;
@@ -270,7 +270,7 @@ protected Metadata readMetadata(File mappingFile) throws 
RepositoryMetadataReadE
         Metadata result;
 
         try (Reader reader = ReaderFactory.newXmlReader(mappingFile)) {
-            MetadataXpp3Reader mappingReader = new MetadataXpp3Reader();
+            ValidatingMetadataXpp3Reader mappingReader = new 
ValidatingMetadataXpp3Reader();
 
             result = mappingReader.read(reader, false);
         } catch (FileNotFoundException e) {
diff --git 
a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java
 
b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java
index 82bd9fea5a..2b97665f5d 100644
--- 
a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java
+++ 
b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java
@@ -27,8 +27,8 @@
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
-import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
 import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
+import 
org.apache.maven.repository.internal.metadata.ValidatingMetadataXpp3Reader;
 import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.WriterFactory;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
@@ -64,7 +64,7 @@ public void storeInLocalRepository(ArtifactRepository 
localRepository, ArtifactR
 
     protected void updateRepositoryMetadata(ArtifactRepository 
localRepository, ArtifactRepository remoteRepository)
             throws IOException, XmlPullParserException {
-        MetadataXpp3Reader mappingReader = new MetadataXpp3Reader();
+        ValidatingMetadataXpp3Reader mappingReader = new 
ValidatingMetadataXpp3Reader();
 
         Metadata metadata = null;
 
diff --git 
a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader.java
 
b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader.java
index 9ecc7c6dac..f1ad14f522 100644
--- 
a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader.java
+++ 
b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader.java
@@ -29,7 +29,7 @@
 import java.util.Objects;
 
 import org.apache.maven.artifact.repository.metadata.Metadata;
-import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
+import 
org.apache.maven.repository.internal.metadata.ValidatingMetadataXpp3Reader;
 import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
@@ -54,7 +54,7 @@ public Metadata read(Reader input, Map<String, ?> options) 
throws IOException {
         Objects.requireNonNull(input, "input cannot be null");
 
         try (Reader in = input) {
-            return new MetadataXpp3Reader().read(in, isStrict(options));
+            return new ValidatingMetadataXpp3Reader().read(in, 
isStrict(options));
         } catch (XmlPullParserException e) {
             throw new MetadataParseException(e.getMessage(), 
e.getLineNumber(), e.getColumnNumber(), e);
         }
@@ -64,7 +64,7 @@ public Metadata read(InputStream input, Map<String, ?> 
options) throws IOExcepti
         Objects.requireNonNull(input, "input cannot be null");
 
         try (InputStream in = input) {
-            return new MetadataXpp3Reader().read(in, isStrict(options));
+            return new ValidatingMetadataXpp3Reader().read(in, 
isStrict(options));
         } catch (XmlPullParserException e) {
             throw new MetadataParseException(e.getMessage(), 
e.getLineNumber(), e.getColumnNumber(), e);
         }
diff --git 
a/maven-core/src/main/java/org/apache/maven/internal/aether/MavenValidator.java 
b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenValidator.java
new file mode 100644
index 0000000000..4369d18a55
--- /dev/null
+++ 
b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenValidator.java
@@ -0,0 +1,91 @@
+/*
+ * 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.internal.aether;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.spi.validator.Validator;
+import org.eclipse.aether.util.PathUtils;
+
+/**
+ * Simplest Maven specific validator that is meant to prevent un-interpolated
+ * elements enter resolver; if it does, is most likely some bug.
+ * <p>
+ * Note: {@link org.eclipse.aether.repository.RemoteRepository} is not 
validated here,
+ * see <a href="https://github.com/apache/maven/issues/7398";>GH-7398</a> for 
details,
+ * and to keep very same behavior as Maven 3 did so far. If you want more, 
upgrade to Maven 4 ;)
+ */
+public class MavenValidator implements Validator {
+    protected boolean containsPlaceholder(String value) {
+        return value != null && value.contains("${");
+    }
+
+    @Override
+    public void validateArtifact(Artifact artifact) throws 
IllegalArgumentException {
+        if (containsPlaceholder(artifact.getGroupId())
+                || containsPlaceholder(artifact.getArtifactId())
+                || containsPlaceholder(artifact.getVersion())
+                || containsPlaceholder(artifact.getClassifier())
+                || containsPlaceholder(artifact.getExtension())) {
+            throw new IllegalArgumentException("Not fully interpolated 
artifact " + artifact);
+        }
+        PathUtils.validateArtifactComponents(artifact);
+    }
+
+    @Override
+    public void validateMetadata(Metadata metadata) throws 
IllegalArgumentException {
+        if (containsPlaceholder(metadata.getGroupId())
+                || containsPlaceholder(metadata.getArtifactId())
+                || containsPlaceholder(metadata.getVersion())
+                || containsPlaceholder(metadata.getType())) {
+            throw new IllegalArgumentException("Not fully interpolated 
metadata " + metadata);
+        }
+        PathUtils.validateMetadataComponents(metadata);
+    }
+
+    @Override
+    public void validateDependency(Dependency dependency) throws 
IllegalArgumentException {
+        Artifact artifact = dependency.getArtifact();
+        if (containsPlaceholder(artifact.getGroupId())
+                || containsPlaceholder(artifact.getArtifactId())
+                || containsPlaceholder(artifact.getVersion())
+                || containsPlaceholder(artifact.getClassifier())
+                || containsPlaceholder(artifact.getExtension())
+                || containsPlaceholder(dependency.getScope())
+                || dependency.getExclusions().stream()
+                        .anyMatch(e -> containsPlaceholder(e.getGroupId())
+                                || containsPlaceholder(e.getArtifactId())
+                                || containsPlaceholder(e.getClassifier())
+                                || containsPlaceholder(e.getExtension()))) {
+            throw new IllegalArgumentException("Not fully interpolated 
dependency " + dependency);
+        }
+        PathUtils.validateArtifactComponents(artifact);
+    }
+
+    @Override
+    public void validateLocalRepository(LocalRepository localRepository) 
throws IllegalArgumentException {
+        if (containsPlaceholder(localRepository.getBasePath().toString())
+                || containsPlaceholder(localRepository.getContentType())
+                || containsPlaceholder(localRepository.getId())) {
+            throw new IllegalArgumentException("Not fully interpolated local 
repository " + localRepository);
+        }
+    }
+}
diff --git 
a/maven-core/src/main/java/org/apache/maven/internal/aether/MavenValidatorFactory.java
 
b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenValidatorFactory.java
new file mode 100644
index 0000000000..83a48104c3
--- /dev/null
+++ 
b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenValidatorFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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.internal.aether;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.spi.validator.Validator;
+import org.eclipse.aether.spi.validator.ValidatorFactory;
+
+@Named
+@Singleton
+public class MavenValidatorFactory implements ValidatorFactory {
+    private final MavenValidator instance = new MavenValidator();
+
+    @Override
+    public Validator newInstance(RepositorySystemSession 
repositorySystemSession) {
+        return instance;
+    }
+}
diff --git 
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java
 
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java
index 23b7bc84b5..9542bece89 100644
--- 
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java
+++ 
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java
@@ -34,7 +34,7 @@
 
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.repository.metadata.Versioning;
-import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
+import 
org.apache.maven.repository.internal.metadata.ValidatingMetadataXpp3Reader;
 import org.eclipse.aether.RepositoryEvent;
 import org.eclipse.aether.RepositoryEvent.EventType;
 import org.eclipse.aether.RepositorySystemSession;
@@ -274,8 +274,9 @@ private Versioning readVersions(
 
                     if (metadata.getFile() != null && 
metadata.getFile().exists()) {
                         try (InputStream in = new 
FileInputStream(metadata.getFile())) {
-                            versioning =
-                                    new MetadataXpp3Reader().read(in, 
false).getVersioning();
+                            versioning = new ValidatingMetadataXpp3Reader()
+                                    .read(in, false)
+                                    .getVersioning();
                         }
                     }
                 }
diff --git 
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java
 
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java
index cccbd9f5ff..b3b5fe70ca 100644
--- 
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java
+++ 
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java
@@ -36,7 +36,7 @@
 import org.apache.maven.artifact.repository.metadata.Snapshot;
 import org.apache.maven.artifact.repository.metadata.SnapshotVersion;
 import org.apache.maven.artifact.repository.metadata.Versioning;
-import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
+import 
org.apache.maven.repository.internal.metadata.ValidatingMetadataXpp3Reader;
 import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.RepositoryCache;
 import org.eclipse.aether.RepositoryEvent;
@@ -278,8 +278,9 @@ private Versioning readVersions(
 
                     if (metadata.getFile() != null && 
metadata.getFile().exists()) {
                         try (InputStream in = new 
FileInputStream(metadata.getFile())) {
-                            versioning =
-                                    new MetadataXpp3Reader().read(in, 
false).getVersioning();
+                            versioning = new ValidatingMetadataXpp3Reader()
+                                    .read(in, false)
+                                    .getVersioning();
 
                             /*
                             NOTE: Users occasionally misuse the id "local" for 
remote repos which screws up the metadata
diff --git 
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java
 
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java
index 6588b32fa5..12cc79bb08 100644
--- 
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java
+++ 
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java
@@ -28,8 +28,8 @@
 import java.util.Map;
 
 import org.apache.maven.artifact.repository.metadata.Metadata;
-import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
 import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
+import 
org.apache.maven.repository.internal.metadata.ValidatingMetadataXpp3Reader;
 import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.WriterFactory;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
@@ -99,7 +99,7 @@ static Metadata read(File metadataFile) throws 
RepositoryException {
         }
 
         try (Reader reader = ReaderFactory.newXmlReader(metadataFile)) {
-            return new MetadataXpp3Reader().read(reader, false);
+            return new ValidatingMetadataXpp3Reader().read(reader, false);
         } catch (IOException e) {
             throw new RepositoryException("Could not read metadata " + 
metadataFile + ": " + e.getMessage(), e);
         } catch (XmlPullParserException e) {
diff --git 
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/metadata/ValidatingMetadataXpp3Reader.java
 
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/metadata/ValidatingMetadataXpp3Reader.java
new file mode 100644
index 0000000000..338befe1be
--- /dev/null
+++ 
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/metadata/ValidatingMetadataXpp3Reader.java
@@ -0,0 +1,75 @@
+/*
+ * 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.repository.internal.metadata;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.maven.artifact.repository.metadata.Metadata;
+import org.apache.maven.artifact.repository.metadata.Versioning;
+import 
org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.eclipse.aether.util.PathUtils;
+
+/**
+ * Validating metadata reader.
+ *
+ * @since 3.10.0
+ */
+public final class ValidatingMetadataXpp3Reader {
+    private final MetadataXpp3Reader mr = new MetadataXpp3Reader();
+
+    /**
+     * Delegates to {@link MetadataXpp3Reader#read(Reader, boolean)}
+     */
+    public Metadata read(Reader reader, boolean strict) throws IOException, 
XmlPullParserException {
+        return validate(mr.read(reader, strict));
+    }
+
+    /**
+     * Delegates to {@link MetadataXpp3Reader#read(InputStream, boolean)}
+     */
+    public Metadata read(InputStream in, boolean strict) throws IOException, 
XmlPullParserException {
+        return validate(mr.read(in, strict));
+    }
+
+    /**
+     * Validates {@link Metadata}.
+     */
+    public static Metadata validate(Metadata metadata) {
+        if (metadata != null) {
+            PathUtils.validatePathComponent(metadata.getVersion(), "version");
+            Versioning versioning = metadata.getVersioning();
+            if (versioning != null) {
+                PathUtils.validatePathComponent(versioning.getLatest(), 
"versioning/latest");
+                PathUtils.validatePathComponent(versioning.getRelease(), 
"versioning/release");
+                for (int i = 0; i < versioning.getVersions().size(); i++) {
+                    
PathUtils.validatePathComponent(versioning.getVersions().get(i), 
"versioning/versions[" + i + "]");
+                }
+                for (int i = 0; i < versioning.getSnapshotVersions().size(); 
i++) {
+                    PathUtils.validatePathComponent(
+                            
versioning.getSnapshotVersions().get(i).getVersion(),
+                            "versioning/snapshotVersions[" + i + "]/version");
+                }
+            }
+        }
+        return metadata;
+    }
+}
diff --git a/pom.xml b/pom.xml
index 07fd63400b..88367df3db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -144,7 +144,7 @@ under the License.
     <securityDispatcherVersion>2.0</securityDispatcherVersion>
     <cipherVersion>2.0</cipherVersion>
     <jxpathVersion>1.4.0</jxpathVersion>
-    <resolverVersion>2.0.20</resolverVersion>
+    <resolverVersion>2.0.21-SNAPSHOT</resolverVersion>
     <slf4jVersion>2.0.18</slf4jVersion>
     <xmlunitVersion>2.12.0</xmlunitVersion>
     <powermockVersion>2.0.9</powermockVersion>

Reply via email to