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 58cd69a6ca Introduce RepositoryAwareRequest interface to consolidate 
repository handling (#11238) (#11244)
58cd69a6ca is described below

commit 58cd69a6cac9168dd42c0b41d6aa90d472dba07e
Author: Guillaume Nodet <[email protected]>
AuthorDate: Fri Oct 10 10:51:58 2025 +0200

    Introduce RepositoryAwareRequest interface to consolidate repository 
handling (#11238) (#11244)
    
    This change introduces a new RepositoryAwareRequest interface that 
consolidates
    repository handling across multiple Maven service request types, addressing
    issues with duplicate repositories being passed to resolvers.
    
    Key changes:
    
    * Add RepositoryAwareRequest interface with repository validation:
      - Provides getRepositories() method and validate() logic
      - Prevents duplicate repositories and null entries
      - Consolidates common repository functionality
    
    * Refactor service request interfaces to extend RepositoryAwareRequest:
      - ArtifactResolverRequest, DependencyResolverRequest, ModelBuilderRequest
      - ProjectBuilderRequest, VersionRangeResolverRequest, 
VersionResolverRequest
      - Apply repository validation in all implementations
    
    * Fix repository leakage in DefaultProjectBuilder:
      - Store project-specific repositories in BuildSession
      - Implement proper repository merging based on strategy
      - Prevent cross-contamination between sibling projects
    
    * Update resolvers to use toResolvingRepositories() for consistent handling
    
    * Add RepositoryLeakageTest to verify proper isolation between projects
    
    This eliminates duplicate repositories being sent to resolvers and ensures
    consistent repository handling across all Maven service requests.
    
    (cherry picked from commit f6343606dea8ddda99c01c14890d541c7585fcef)
    
    Co-authored-by: Tamas Cservenak <[email protected]>
---
 .../api/services/ArtifactResolverRequest.java      |   7 +-
 .../api/services/DependencyResolverRequest.java    |   7 +-
 .../maven/api/services/ModelBuilderRequest.java    |   7 +-
 .../maven/api/services/ProjectBuilderRequest.java  |   4 +-
 .../maven/api/services/RepositoryAwareRequest.java | 117 +++++++++++
 .../api/services/VersionRangeResolverRequest.java  |   7 +-
 .../maven/api/services/VersionResolverRequest.java |   7 +-
 .../maven/project/DefaultProjectBuilder.java       |  48 ++++-
 .../maven/project/RepositoryLeakageTest.java       | 214 +++++++++++++++++++++
 .../org/apache/maven/impl/AbstractSession.java     |   6 +
 .../apache/maven/impl/DefaultArtifactResolver.java |   2 +-
 .../maven/impl/DefaultDependencyResolver.java      |   2 +-
 .../maven/impl/DefaultVersionRangeResolver.java    |   2 +-
 .../apache/maven/impl/DefaultVersionResolver.java  |   2 +-
 .../org/apache/maven/impl/InternalSession.java     |   2 +
 15 files changed, 398 insertions(+), 36 deletions(-)

diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
index fb012fab30..7e832a95e4 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
@@ -40,14 +40,11 @@
  */
 @Experimental
 @Immutable
-public interface ArtifactResolverRequest extends Request<Session> {
+public interface ArtifactResolverRequest extends RepositoryAwareRequest {
 
     @Nonnull
     Collection<? extends ArtifactCoordinates> getCoordinates();
 
-    @Nullable
-    List<RemoteRepository> getRepositories();
-
     @Nonnull
     static ArtifactResolverRequestBuilder builder() {
         return new ArtifactResolverRequestBuilder();
@@ -127,7 +124,7 @@ private static class DefaultArtifactResolverRequest extends 
BaseRequest<Session>
                     @Nonnull List<RemoteRepository> repositories) {
                 super(session, trace);
                 this.coordinates = List.copyOf(requireNonNull(coordinates, 
"coordinates cannot be null"));
-                this.repositories = repositories;
+                this.repositories = validate(repositories);
             }
 
             @Nonnull
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
index e9b3ab956b..5be250824d 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
@@ -55,7 +55,7 @@
  */
 @Experimental
 @Immutable
-public interface DependencyResolverRequest extends Request<Session> {
+public interface DependencyResolverRequest extends RepositoryAwareRequest {
 
     enum RequestType {
         COLLECT,
@@ -119,9 +119,6 @@ enum RequestType {
     @Nullable
     Version getTargetVersion();
 
-    @Nullable
-    List<RemoteRepository> getRepositories();
-
     @Nonnull
     static DependencyResolverRequestBuilder builder() {
         return new DependencyResolverRequestBuilder();
@@ -479,7 +476,7 @@ public String toString() {
                 this.pathScope = requireNonNull(pathScope, "pathScope cannot 
be null");
                 this.pathTypeFilter = (pathTypeFilter != null) ? 
pathTypeFilter : DEFAULT_FILTER;
                 this.targetVersion = targetVersion;
-                this.repositories = repositories;
+                this.repositories = validate(repositories);
                 if (verbose && requestType != RequestType.COLLECT) {
                     throw new IllegalArgumentException("verbose cannot only be 
true when collecting dependencies");
                 }
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
index 14141a6d0c..826ffe8fc4 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
@@ -43,7 +43,7 @@
  */
 @Experimental
 @Immutable
-public interface ModelBuilderRequest extends Request<Session> {
+public interface ModelBuilderRequest extends RepositoryAwareRequest {
 
     /**
      * The possible request types for building a model.
@@ -133,9 +133,6 @@ enum RepositoryMerging {
     @Nonnull
     RepositoryMerging getRepositoryMerging();
 
-    @Nullable
-    List<RemoteRepository> getRepositories();
-
     @Nullable
     ModelTransformer getLifecycleBindingsInjector();
 
@@ -338,7 +335,7 @@ private static class DefaultModelBuilderRequest extends 
BaseRequest<Session> imp
                         systemProperties != null ? 
Map.copyOf(systemProperties) : session.getSystemProperties();
                 this.userProperties = userProperties != null ? 
Map.copyOf(userProperties) : session.getUserProperties();
                 this.repositoryMerging = repositoryMerging;
-                this.repositories = repositories != null ? 
List.copyOf(repositories) : null;
+                this.repositories = repositories != null ? 
List.copyOf(validate(repositories)) : null;
                 this.lifecycleBindingsInjector = lifecycleBindingsInjector;
             }
 
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
index 82129b4f1b..307ee19559 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
@@ -43,7 +43,7 @@
  */
 @Experimental
 @Immutable
-public interface ProjectBuilderRequest extends Request<Session> {
+public interface ProjectBuilderRequest extends RepositoryAwareRequest {
 
     /**
      * Gets the path to the project to build.
@@ -265,7 +265,7 @@ private static class DefaultProjectBuilderRequest extends 
BaseRequest<Session>
                 this.allowStubModel = allowStubModel;
                 this.recursive = recursive;
                 this.processPlugins = processPlugins;
-                this.repositories = repositories;
+                this.repositories = validate(repositories);
             }
 
             @Nonnull
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryAwareRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryAwareRequest.java
new file mode 100644
index 0000000000..f948ecdea4
--- /dev/null
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryAwareRequest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.HashSet;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * Base interface for service requests that involve remote repository 
operations.
+ * This interface provides common functionality for requests that need to 
specify
+ * and validate remote repositories for artifact resolution, dependency 
collection,
+ * model building, and other Maven operations.
+ *
+ * <p>Implementations of this interface can specify a list of remote 
repositories
+ * to be used during the operation. If no repositories are specified (null),
+ * the session's default remote repositories will be used. The repositories
+ * are validated to ensure they don't contain duplicates or null entries.
+ *
+ * <p>Remote repositories are used for:
+ * <ul>
+ *   <li>Resolving artifacts and their metadata</li>
+ *   <li>Downloading parent POMs and dependency POMs</li>
+ *   <li>Retrieving version information and ranges</li>
+ *   <li>Accessing plugin artifacts and their dependencies</li>
+ * </ul>
+ *
+ * <p>Repository validation ensures data integrity by:
+ * <ul>
+ *   <li>Preventing duplicate repositories that could cause confusion</li>
+ *   <li>Rejecting null repository entries that would cause failures</li>
+ *   <li>Maintaining consistent repository ordering for reproducible 
builds</li>
+ * </ul>
+ *
+ * @since 4.0.0
+ * @see RemoteRepository
+ * @see Session#getRemoteRepositories()
+ */
+@Experimental
+@Immutable
+public interface RepositoryAwareRequest extends Request<Session> {
+
+    /**
+     * Returns the list of remote repositories to be used for this request.
+     *
+     * <p>If this method returns {@code null}, the session's default remote 
repositories
+     * will be used. If a non-null list is returned, it will be used instead 
of the
+     * session's repositories, allowing for request-specific repository 
configuration.
+     *
+     * <p>The returned list should not contain duplicate repositories (based 
on their
+     * equality) or null entries, as these will cause validation failures when 
the
+     * request is processed.
+     *
+     * @return the list of remote repositories to use, or {@code null} to use 
session defaults
+     * @see Session#getRemoteRepositories()
+     */
+    @Nullable
+    List<RemoteRepository> getRepositories();
+
+    /**
+     * Validates a list of remote repositories to ensure data integrity.
+     *
+     * <p>This method performs the following validations:
+     * <ul>
+     *   <li>Allows null input (returns null)</li>
+     *   <li>Ensures no duplicate repositories exist in the list</li>
+     *   <li>Ensures no null repository entries exist in the list</li>
+     * </ul>
+     *
+     * <p>Duplicate detection is based on the {@code 
RemoteRepository#equals(Object)}
+     * method, which typically compares repository IDs and URLs.
+     *
+     * @param repositories the list of repositories to validate, may be {@code 
null}
+     * @return the same list if validation passes, or {@code null} if input 
was {@code null}
+     * @throws IllegalArgumentException if the list contains duplicate 
repositories
+     * @throws IllegalArgumentException if the list contains null repository 
entries
+     */
+    default List<RemoteRepository> validate(List<RemoteRepository> 
repositories) {
+        if (repositories == null) {
+            return null;
+        }
+        HashSet<RemoteRepository> set = new HashSet<>(repositories);
+        if (repositories.size() != set.size()) {
+            throw new IllegalArgumentException(
+                    "Repository list contains duplicate entries. Each 
repository must be unique based on its ID and URL. "
+                            + "Found " + repositories.size() + " repositories 
but only " + set.size()
+                            + " unique entries.");
+        }
+        if (repositories.stream().anyMatch(Objects::isNull)) {
+            throw new IllegalArgumentException(
+                    "Repository list contains null entries. All repository 
entries must be non-null RemoteRepository instances.");
+        }
+        return repositories;
+    }
+}
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
index 52abe9e89a..2f69c574a3 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
@@ -36,14 +36,11 @@
  * @since 4.0.0
  */
 @Experimental
-public interface VersionRangeResolverRequest extends Request<Session> {
+public interface VersionRangeResolverRequest extends RepositoryAwareRequest {
 
     @Nonnull
     ArtifactCoordinates getArtifactCoordinates();
 
-    @Nullable
-    List<RemoteRepository> getRepositories();
-
     @Nonnull
     static VersionRangeResolverRequest build(
             @Nonnull Session session, @Nonnull ArtifactCoordinates 
artifactCoordinates) {
@@ -111,7 +108,7 @@ private static class DefaultVersionResolverRequest extends 
BaseRequest<Session>
                     @Nullable List<RemoteRepository> repositories) {
                 super(session, trace);
                 this.artifactCoordinates = artifactCoordinates;
-                this.repositories = repositories;
+                this.repositories = validate(repositories);
             }
 
             @Nonnull
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
index c8dee58a8f..b510dcc2de 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
@@ -36,14 +36,11 @@
  * @since 4.0.0
  */
 @Experimental
-public interface VersionResolverRequest extends Request<Session> {
+public interface VersionResolverRequest extends RepositoryAwareRequest {
 
     @Nonnull
     ArtifactCoordinates getArtifactCoordinates();
 
-    @Nullable
-    List<RemoteRepository> getRepositories();
-
     @Nonnull
     static VersionResolverRequest build(@Nonnull Session session, @Nonnull 
ArtifactCoordinates artifactCoordinates) {
         return builder()
@@ -113,7 +110,7 @@ private static class DefaultVersionResolverRequest extends 
BaseRequest<Session>
                     @Nullable List<RemoteRepository> repositories) {
                 super(session, trace);
                 this.artifactCoordinates = artifactCoordinates;
-                this.repositories = repositories;
+                this.repositories = validate(repositories);
             }
 
             @Nonnull
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
 
b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
index a14dfaabe1..47f252cd52 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
@@ -182,7 +182,7 @@ public ProjectBuildingResult build(Artifact artifact, 
ProjectBuildingRequest req
     public ProjectBuildingResult build(Artifact artifact, boolean 
allowStubModel, ProjectBuildingRequest request)
             throws ProjectBuildingException {
         try (BuildSession bs = new BuildSession(request)) {
-            return bs.build(false, artifact, allowStubModel);
+            return bs.build(false, artifact, allowStubModel, 
request.getRemoteRepositories());
         }
     }
 
@@ -316,6 +316,18 @@ class BuildSession implements AutoCloseable {
         private final ModelBuilder.ModelBuilderSession modelBuilderSession;
         private final Map<String, MavenProject> projectIndex = new 
ConcurrentHashMap<>(256);
 
+        // Store computed repositories per project to avoid leakage between 
projects
+        private final Map<String, List<ArtifactRepository>> 
projectRepositories = new ConcurrentHashMap<>();
+
+        /**
+         * Get the effective repositories for a project. If project-specific 
repositories
+         * have been computed and stored, use those; otherwise fall back to 
request repositories.
+         */
+        private List<ArtifactRepository> getEffectiveRepositories(String 
projectId) {
+            List<ArtifactRepository> stored = 
projectRepositories.get(projectId);
+            return stored != null ? stored : request.getRemoteRepositories();
+        }
+
         BuildSession(ProjectBuildingRequest request) {
             this.request = request;
             InternalSession session = 
InternalSession.from(request.getRepositorySession());
@@ -427,7 +439,8 @@ ProjectBuildingResult build(boolean parent, Path pomFile, 
ModelSource modelSourc
             }
         }
 
-        ProjectBuildingResult build(boolean parent, Artifact artifact, boolean 
allowStubModel)
+        ProjectBuildingResult build(
+                boolean parent, Artifact artifact, boolean allowStubModel, 
List<ArtifactRepository> repositories)
                 throws ProjectBuildingException {
             org.eclipse.aether.artifact.Artifact pomArtifact = 
RepositoryUtils.toArtifact(artifact);
             pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact);
@@ -436,9 +449,10 @@ ProjectBuildingResult build(boolean parent, Artifact 
artifact, boolean allowStub
 
             try {
                 ArtifactCoordinates coordinates = 
session.createArtifactCoordinates(session.getArtifact(pomArtifact));
+                // Use provided repositories if available, otherwise fall back 
to request repositories
                 ArtifactResolverRequest req = ArtifactResolverRequest.builder()
                         .session(session)
-                        .repositories(request.getRemoteRepositories().stream()
+                        .repositories(repositories.stream()
                                 .map(RepositoryUtils::toRepo)
                                 .map(session::getRemoteRepository)
                                 .toList())
@@ -844,7 +858,30 @@ private void initParent(MavenProject project, 
ModelBuilderResult result) {
                     // remote repositories with those found in the pom.xml, 
along with the existing externally
                     // defined repositories.
                     //
-                    
request.getRemoteRepositories().addAll(project.getRemoteArtifactRepositories());
+                    // Compute merged repositories for this project and store 
in session
+                    // instead of mutating the shared request to avoid leakage 
between projects
+                    List<ArtifactRepository> mergedRepositories;
+                    switch (request.getRepositoryMerging()) {
+                        case POM_DOMINANT -> {
+                            LinkedHashSet<ArtifactRepository> reposes =
+                                    new 
LinkedHashSet<>(project.getRemoteArtifactRepositories());
+                            reposes.addAll(request.getRemoteRepositories());
+                            mergedRepositories = List.copyOf(reposes);
+                        }
+                        case REQUEST_DOMINANT -> {
+                            LinkedHashSet<ArtifactRepository> reposes =
+                                    new 
LinkedHashSet<>(request.getRemoteRepositories());
+                            
reposes.addAll(project.getRemoteArtifactRepositories());
+                            mergedRepositories = List.copyOf(reposes);
+                        }
+                        default -> throw new IllegalArgumentException(
+                                "Unsupported repository merging: " + 
request.getRepositoryMerging());
+                    }
+
+                    // Store the computed repositories for this project in 
BuildSession storage
+                    // to avoid mutating the shared request and causing 
leakage between projects
+                    projectRepositories.put(project.getId(), 
mergedRepositories);
+
                     Path parentPomFile = parentModel.getPomFile();
                     if (parentPomFile != null) {
                         project.setParentFile(parentPomFile.toFile());
@@ -864,7 +901,8 @@ private void initParent(MavenProject project, 
ModelBuilderResult result) {
                     } else {
                         Artifact parentArtifact = project.getParentArtifact();
                         try {
-                            parent = build(true, parentArtifact, 
false).getProject();
+                            parent = build(true, parentArtifact, false, 
getEffectiveRepositories(project.getId()))
+                                    .getProject();
                         } catch (ProjectBuildingException e) {
                             // MNG-4488 where let invalid parents slide on by
                             if (logger.isDebugEnabled()) {
diff --git 
a/impl/maven-core/src/test/java/org/apache/maven/project/RepositoryLeakageTest.java
 
b/impl/maven-core/src/test/java/org/apache/maven/project/RepositoryLeakageTest.java
new file mode 100644
index 0000000000..b5ff18f872
--- /dev/null
+++ 
b/impl/maven-core/src/test/java/org/apache/maven/project/RepositoryLeakageTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.project;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Test to verify that repositories from one project don't leak to sibling 
projects.
+ */
+@PlexusTest
+public class RepositoryLeakageTest extends AbstractMavenProjectTestCase {
+
+    @Test
+    @SuppressWarnings("checkstyle:MethodLength")
+    public void testRepositoryLeakageBetweenSiblings() throws Exception {
+        // Create a temporary directory structure for our test
+        Path tempDir = Files.createTempDirectory("maven-repo-leakage-test");
+
+        try {
+            // Create parent POM
+            Path parentPom = tempDir.resolve("pom.xml");
+            Files.writeString(
+                    parentPom,
+                    """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <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>test</groupId>
+                    <artifactId>parent</artifactId>
+                    <version>1.0</version>
+                    <packaging>pom</packaging>
+
+                    <modules>
+                        <module>child1</module>
+                        <module>child2</module>
+                    </modules>
+                </project>
+                """);
+
+            // Create child1 with specific repository
+            Path child1Dir = tempDir.resolve("child1");
+            Files.createDirectories(child1Dir);
+            Path child1Pom = child1Dir.resolve("pom.xml");
+            Files.writeString(
+                    child1Pom,
+                    """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <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>
+                    <parent>
+                        <groupId>test</groupId>
+                        <artifactId>parent</artifactId>
+                        <version>1.0</version>
+                    </parent>
+                    <artifactId>child1</artifactId>
+
+                    <repositories>
+                        <repository>
+                            <id>child1-repo</id>
+                            <url>https://child1.example.com/repo</url>
+                        </repository>
+                    </repositories>
+                </project>
+                """);
+
+            // Create child2 with different repository
+            Path child2Dir = tempDir.resolve("child2");
+            Files.createDirectories(child2Dir);
+            Path child2Pom = child2Dir.resolve("pom.xml");
+            Files.writeString(
+                    child2Pom,
+                    """
+                <?xml version="1.0" encoding="UTF-8"?>
+                <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>
+                    <parent>
+                        <groupId>test</groupId>
+                        <artifactId>parent</artifactId>
+                        <version>1.0</version>
+                    </parent>
+                    <artifactId>child2</artifactId>
+
+                    <repositories>
+                        <repository>
+                            <id>child2-repo</id>
+                            <url>https://child2.example.com/repo</url>
+                        </repository>
+                    </repositories>
+                </project>
+                """);
+
+            // Create a shared ProjectBuildingRequest
+            ProjectBuildingRequest sharedRequest = newBuildingRequest();
+
+            // Build child1 first
+            ProjectBuildingResult result1 = 
projectBuilder.build(child1Pom.toFile(), sharedRequest);
+            MavenProject child1Project = result1.getProject();
+
+            // Capture repositories after building child1
+
+            // Build child2 using the same shared request
+            ProjectBuildingResult result2 = 
projectBuilder.build(child2Pom.toFile(), sharedRequest);
+            MavenProject child2Project = result2.getProject();
+
+            // Capture repositories after building child2
+            List<ArtifactRepository> repositoriesAfterChild2 = 
List.copyOf(sharedRequest.getRemoteRepositories());
+
+            // Verify that child1 has its own repository
+            boolean child1HasOwnRepo = 
child1Project.getRemoteArtifactRepositories().stream()
+                    .anyMatch(repo -> "child1-repo".equals(repo.getId()));
+            assertTrue(child1HasOwnRepo, "Child1 should have its own 
repository");
+
+            // Verify that child2 has its own repository
+            boolean child2HasOwnRepo = 
child2Project.getRemoteArtifactRepositories().stream()
+                    .anyMatch(repo -> "child2-repo".equals(repo.getId()));
+            assertTrue(child2HasOwnRepo, "Child2 should have its own 
repository");
+
+            // Print debug information
+            System.out.println("=== REPOSITORY LEAKAGE TEST RESULTS ===");
+            System.out.println(
+                    "Repositories in shared request after building child2: " + 
repositoriesAfterChild2.size());
+            repositoriesAfterChild2.forEach(
+                    repo -> System.out.println("  - " + repo.getId() + " (" + 
repo.getUrl() + ")"));
+
+            System.out.println("Child1 project repositories:");
+            child1Project
+                    .getRemoteArtifactRepositories()
+                    .forEach(repo -> System.out.println("  - " + repo.getId() 
+ " (" + repo.getUrl() + ")"));
+
+            System.out.println("Child2 project repositories:");
+            child2Project
+                    .getRemoteArtifactRepositories()
+                    .forEach(repo -> System.out.println("  - " + repo.getId() 
+ " (" + repo.getUrl() + ")"));
+            System.out.println("=======================================");
+
+            // Check for leakage: child2 should NOT have child1's repository
+            boolean child2HasChild1Repo = 
child2Project.getRemoteArtifactRepositories().stream()
+                    .anyMatch(repo -> "child1-repo".equals(repo.getId()));
+            assertFalse(child2HasChild1Repo, "Child2 should NOT have child1's 
repository (leakage detected!)");
+
+            // Check for leakage in the shared request
+            boolean sharedRequestHasChild1Repo =
+                    repositoriesAfterChild2.stream().anyMatch(repo -> 
"child1-repo".equals(repo.getId()));
+            boolean sharedRequestHasChild2Repo =
+                    repositoriesAfterChild2.stream().anyMatch(repo -> 
"child2-repo".equals(repo.getId()));
+
+            // Print debug information
+            /*
+            System.out.println("Repositories after child1: " + 
repositoriesAfterChild1.size());
+            repositoriesAfterChild1.forEach(repo -> System.out.println("  - " 
+ repo.getId() + ": " + repo.getUrl()));
+
+            System.out.println("Repositories after child2: " + 
repositoriesAfterChild2.size());
+            repositoriesAfterChild2.forEach(repo -> System.out.println("  - " 
+ repo.getId() + ": " + repo.getUrl()));
+            */
+
+            // The shared request should not accumulate repositories from both 
children
+            if (sharedRequestHasChild1Repo && sharedRequestHasChild2Repo) {
+                fail("REPOSITORY LEAKAGE DETECTED: Shared request contains 
repositories from both children!");
+            }
+
+        } finally {
+            // Clean up
+            deleteRecursively(tempDir.toFile());
+        }
+    }
+
+    private void deleteRecursively(File file) {
+        if (file.isDirectory()) {
+            File[] children = file.listFiles();
+            if (children != null) {
+                for (File child : children) {
+                    deleteRecursively(child);
+                }
+            }
+        }
+        file.delete();
+    }
+}
diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/AbstractSession.java 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/AbstractSession.java
index 68e2d6b2a7..af40c643c6 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/AbstractSession.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/AbstractSession.java
@@ -279,6 +279,12 @@ public 
List<org.eclipse.aether.repository.RemoteRepository> toRepositories(List<
         return repositories == null ? null : map(repositories, 
this::toRepository);
     }
 
+    @Override
+    public List<org.eclipse.aether.repository.RemoteRepository> 
toResolvingRepositories(
+            List<RemoteRepository> repositories) {
+        return getRepositorySystem().newResolutionRepositories(getSession(), 
toRepositories(repositories));
+    }
+
     @Override
     public org.eclipse.aether.repository.RemoteRepository 
toRepository(RemoteRepository repository) {
         if (repository instanceof DefaultRemoteRepository 
defaultRemoteRepository) {
diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java
 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java
index 3614056b28..9f22790f39 100644
--- 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java
+++ 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultArtifactResolver.java
@@ -91,7 +91,7 @@ protected ArtifactResolverResult 
doResolve(ArtifactResolverRequest request) {
         InternalSession session = InternalSession.from(request.getSession());
         RequestTraceHelper.ResolverTrace trace = 
RequestTraceHelper.enter(session, request);
         try {
-            List<RemoteRepository> repositories = session.toRepositories(
+            List<RemoteRepository> repositories = 
session.toResolvingRepositories(
                     request.getRepositories() != null ? 
request.getRepositories() : session.getRemoteRepositories());
 
             List<ResolverRequest> requests = new ArrayList<>();
diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolver.java
 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolver.java
index 278d7feb7e..d29c3f369a 100644
--- 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolver.java
+++ 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultDependencyResolver.java
@@ -152,7 +152,7 @@ public DependencyResolverResult collect(@Nonnull 
DependencyResolverRequest reque
                     .setRoot(root != null ? session.toDependency(root, false) 
: null)
                     .setDependencies(session.toDependencies(dependencies, 
false))
                     
.setManagedDependencies(session.toDependencies(managedDependencies, true))
-                    
.setRepositories(session.toRepositories(remoteRepositories))
+                    
.setRepositories(session.toResolvingRepositories(remoteRepositories))
                     .setRequestContext(trace.context())
                     .setTrace(trace.trace());
             collectRequest.setResolutionScope(resolutionScope);
diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionRangeResolver.java
 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionRangeResolver.java
index df182d976a..b0097d5248 100644
--- 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionRangeResolver.java
+++ 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionRangeResolver.java
@@ -69,7 +69,7 @@ public VersionRangeResolverResult 
doResolve(VersionRangeResolverRequest request)
                     session.getSession(),
                     new VersionRangeRequest(
                                     
session.toArtifact(request.getArtifactCoordinates()),
-                                    session.toRepositories(
+                                    session.toResolvingRepositories(
                                             request.getRepositories() != null
                                                     ? request.getRepositories()
                                                     : 
session.getRemoteRepositories()),
diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionResolver.java
 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionResolver.java
index c80a1d24ad..1f233f604b 100644
--- 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionResolver.java
+++ 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultVersionResolver.java
@@ -61,7 +61,7 @@ protected VersionResolverResult 
doResolve(VersionResolverRequest request) throws
         try {
             VersionRequest req = new VersionRequest(
                             
session.toArtifact(request.getArtifactCoordinates()),
-                            session.toRepositories(
+                            session.toResolvingRepositories(
                                     request.getRepositories() != null
                                             ? request.getRepositories()
                                             : session.getRemoteRepositories()),
diff --git 
a/impl/maven-impl/src/main/java/org/apache/maven/impl/InternalSession.java 
b/impl/maven-impl/src/main/java/org/apache/maven/impl/InternalSession.java
index b3ce36d47b..7d9945077f 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/InternalSession.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/InternalSession.java
@@ -101,6 +101,8 @@ <REQ extends Request<?>, REP extends Result<REQ>> List<REP> 
requests(
 
     List<org.eclipse.aether.repository.RemoteRepository> 
toRepositories(List<RemoteRepository> repositories);
 
+    List<org.eclipse.aether.repository.RemoteRepository> 
toResolvingRepositories(List<RemoteRepository> repositories);
+
     org.eclipse.aether.repository.RemoteRepository 
toRepository(RemoteRepository repository);
 
     org.eclipse.aether.repository.LocalRepository toRepository(LocalRepository 
repository);


Reply via email to