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/09/16 12:29:17 UTC
(maven) branch maven-3.10.x updated: Fix #13100: honor repositories from legitimately-active external model profiles
This is an automated email from the ASF dual-hosted git repository.
gnodet 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 dda1c3f20a Fix #13100: honor repositories from legitimately-active external model profiles
dda1c3f20a is described below
commit dda1c3f20aaf55f88a8f15ecf5e5fc943e54ae21
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Wed Sep 16 14:29:11 2026 +0200
Fix #13100: honor repositories from legitimately-active external model profiles
The `withoutRepositories()` stripping was applied to all active profiles unconditionally — regardless of why they activated. The `withoutFileAndPropertyActivation` filter already suppresses file- and property-activated profiles before they reach injection, so the blanket strip was over-broad: it discarded repositories from legitimately-active profiles (JDK/OS, `activeByDefault`) with no security benefit.
Removes the stripping from the profile injection loop and the dead `withoutRepositories()` helper. `BUILD_CONSUMER` stripping is intentional and unchanged. Adds TODO(#13146) for the deferred central-shadowing policy.
Fixes #13100.
---
.../maven/model/building/DefaultModelBuilder.java | 18 +-----
.../ResolvedDependencyProfileActivationTest.java | 66 ++++++++++++++++++++--
2 files changed, 63 insertions(+), 21 deletions(-)
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
index 642caef728..ae3f9b55f2 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
@@ -324,12 +324,10 @@ protected ModelBuildingResult build(ModelBuildingRequest request, Collection<Str
currentData.setActiveProfiles(rawProfiles);
// profile injection
+ // TODO(#13146): repositories contributed by external-model profiles can shadow
+ // central; a WARN/FAIL policy for URL mismatches should be added separately.
for (Profile activeProfile : activePomProfiles) {
- profileInjector.injectProfile(
- tmpModel,
- externalModel ? withoutRepositories(activeProfile) : activeProfile,
- request,
- problems);
+ profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
}
if (currentData == resultData) {
@@ -532,16 +530,6 @@ private static List<Profile> withoutFileAndPropertyActivation(List<Profile> prof
return eligible;
}
- /**
- * Returns a copy of the given profile with its repositories and plugin repositories cleared.
- */
- private static Profile withoutRepositories(Profile profile) {
- Profile stripped = profile.clone();
- stripped.setRepositories(Collections.emptyList());
- stripped.setPluginRepositories(Collections.emptyList());
- return stripped;
- }
-
@Override
public ModelBuildingResult build(ModelBuildingRequest request, ModelBuildingResult result)
throws ModelBuildingException {
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/ResolvedDependencyProfileActivationTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/ResolvedDependencyProfileActivationTest.java
index 7ab4747d3f..1fdb785f2f 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/ResolvedDependencyProfileActivationTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/ResolvedDependencyProfileActivationTest.java
@@ -31,10 +31,10 @@
* Models built at {@link ModelBuildingRequest#VALIDATION_LEVEL_MINIMAL} come from POMs resolved
* from a repository during dependency resolution (a dependency POM, one of its parents, or an
* imported BOM), see for instance {@code DefaultArtifactDescriptorReader#loadPom}. Their file and
- * property activators are not evaluated, and their profiles contribute no repositories. A project
- * build, at {@link ModelBuildingRequest#VALIDATION_LEVEL_STRICT}, still evaluates every activator.
- * Platform-derived activation (JDK version, operating system, activeByDefault) is unaffected at
- * either level.
+ * property activators are not evaluated. Platform-activated profiles (JDK version, OS,
+ * {@code activeByDefault}) still fire and may contribute repositories; only file- and
+ * property-activated profiles are suppressed. A project build, at
+ * {@link ModelBuildingRequest#VALIDATION_LEVEL_STRICT}, still evaluates every activator.
*/
class ResolvedDependencyProfileActivationTest {
@@ -112,12 +112,66 @@ void testProjectBuildEvaluatesAllActivators() throws Exception {
}
@Test
- void testDependencyPomActivatesOnlyEnvironmentIndependentProfiles() throws Exception {
+ void testDependencyPomHonorsJdkActivatedProfileRepositories() throws Exception {
Model model = build(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
assertNull(model.getProperties().get("profile.file"));
assertNull(model.getProperties().get("profile.property"));
assertEquals("activated", model.getProperties().get("profile.jdk"));
- assertTrue(model.getRepositories().stream().noneMatch(r -> "profile-repo".equals(r.getId())));
+ // The JDK-activated profile fires legitimately under the sandbox and its
+ // repository must be honored (dep1 → dep2 pattern where dep2 is not on Central).
+ assertTrue(model.getRepositories().stream().anyMatch(r -> "profile-repo".equals(r.getId())));
+ }
+
+ /**
+ * An {@code activeByDefault=true} profile in an external dependency model must contribute
+ * its repositories — the same guarantee as for JDK/OS-activated profiles (see #13100).
+ * Uses an isolated POM with only an activeByDefault profile so the standard Maven rule
+ * ("activeByDefault is suppressed when any other profile activates") does not interfere.
+ */
+ @Test
+ void testActiveByDefaultProfileRepositoryHonored() throws Exception {
+ // Isolated POM: only one profile (activeByDefault=true), no other profiles that could
+ // suppress it. Without isolation the JDK-activated sibling in POM would cause Maven
+ // to skip the activeByDefault profile entirely, making the test vacuous.
+ String activeByDefaultPom = "<project>\n"
+ + " <modelVersion>4.0.0</modelVersion>\n"
+ + " <groupId>thegroup</groupId>\n"
+ + " <artifactId>active-by-default-profile</artifactId>\n"
+ + " <version>1</version>\n"
+ + " <packaging>pom</packaging>\n"
+ + " <profiles>\n"
+ + " <profile>\n"
+ + " <id>always-active</id>\n"
+ + " <activation>\n"
+ + " <activeByDefault>true</activeByDefault>\n"
+ + " </activation>\n"
+ + " <repositories>\n"
+ + " <repository>\n"
+ + " <id>always-active-repo</id>\n"
+ + " <url>https://repo.example.test/always-active</url>\n"
+ + " </repository>\n"
+ + " </repositories>\n"
+ + " </profile>\n"
+ + " </profiles>\n"
+ + "</project>\n";
+
+ ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
+
+ Properties systemProperties = new Properties();
+ systemProperties.putAll(System.getProperties());
+
+ DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
+ request.setModelSource(new StringModelSource(activeByDefaultPom));
+ request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+ request.setSystemProperties(systemProperties);
+
+ Model model = builder.build(request).getEffectiveModel();
+
+ // The always-active profile activates by default: its repository must survive external
+ // model resolution unchanged. See #13100, #13116.
+ assertTrue(
+ model.getRepositories().stream().anyMatch(r -> "always-active-repo".equals(r.getId())),
+ "Repository from activeByDefault profile must be retained in external dependency model");
}
}