Skip to content

[3.10] Questions to discuss #13100

Closed
Closed

Description

@cstamas

New feature, improvement proposal

The more I look at commit 03c947d the more questions it raises:

  • it removes repositories from profiles. Why? And what happens with repositories defined in POM itself? Why not removing both, why only one (profile)? What differentiates them from POM defined repositories? And IMHO not removing reposes is the proper solution.
  • Maven relies on POM defined repositories (they may come from profile), as there is pattern that project -> dep1 -> dep2 where dep1 knows dep2 is not on Central but is somewhere else.
  • What we should scrutinize is repository redefine IMHO, where an existing remote repository was "redefined" (and scoped to that node and below) nb: this reminds me of [EXPERIMENT] Update resolver and use newly introduced method #428
  • In case of a "malicious" dependency, that may redefine a repository, it may silently redirect the build to malicious repository?
  • In redefine cases we may want to prevent it, or WARN on it, or maybe even have a switch like WARN/FAIL?

Activity

  1. added this to the 3.10.0 milestone on Sep 13, 2026
  2. ascheman commented on Sep 13, 2026

    @ascheman
    Contributor

    Good questions — worth pinning down, because there are actually two separate axes in 03c947d8 that got entangled:

    1 · Profile activation in resolved models. Suppressing property/file-activated profiles in a repository-resolved POM is what broke RESTEasy (#13084): its BOM is imported by a default-on negated-property profile (!resteasy.dependencies.eap) that got filtered out → missing managed versions. #13095 narrows that to re-allow the negated (default-on, non-injectable) case. That's the activation axis.

    2 · Repository stripping — the axis you're raising, and I agree it deserves its own scrutiny.

    On "why profiles only, not POM-body repos?": as I read it, in a resolved model profiles are activated against the consumer's environment (-D, files, JDK), which is meaningless for a published artifact — so a profile the publisher meant to be inactive can fire in my build and inject its repository. POM-body repos are unconditional (always present, part of the artifact's declared identity), so they stay honored — which is exactly why the project → dep1 → dep2 pattern (dep1 declaring dep2's non-Central repo) keeps working as long as the repo is in the POM body.

    But your point stands: if dep1 declares that repo inside a profile (activeByDefault, or a negated default-on profile), the blanket strip breaks it — legitimate functionality lost to a coarse rule.

    Your redefine-centric framing is the better-targeted model:

    • Honor declared repositories (body and legitimately-active profiles).
    • Scrutinize redefinition of an already-known repository (especially central) — that's the actual attack (silent redirect to a malicious mirror), independent of whether the declaration sits in a profile or the body.
    • WARN by default, with a WARN/FAIL switch — the silent redirect is the dangerous part; making it visible is most of the value (ties back to [EXPERIMENT] Update resolver and use newly introduced method #428).

    Net: I'd keep #13095 (it fixes the acute activation regression within today's model) and treat this issue as the follow-up that reconsiders the repository axis properly — replacing "strip all profile repos" with "detect + warn/fail on repository redefinition." Happy to help shape that.

  3. ascheman commented on Sep 14, 2026

    @ascheman
    Contributor

    One more data point for the record, from a side thread with @cstamas: a fully legitimate pattern is two alternating profiles — e.g. public vs inhouse, each declaring its own <repositories> (inhouse → an MRM). A blanket "strip all profile repositories" breaks exactly that.

    Scoping nuance so we're precise: this only bites when such profiles live in a repository-resolved POM (a dependency's own, built at CONSUMER_DEPENDENCY); a consumer's own project/settings profiles are fully evaluated and unaffected. So the problem space is specifically "repositories a dependency contributes via a profile".

    For what it's worth, your redefine-detection framing — honor declared repos, scrutinize redefinition of an existing repository (especially central), warn/fail — looks like the right axis to me (cf. #428). Leaving the shape to you.

  4. gnodet commented on Sep 14, 2026

    @gnodet
    Contributor

    For the record: the activation axis (#13084) has a fix in progress at #13112 that takes the principled approach — sandbox the ProfileActivationContext rather than filter by activation type.

    The short version of what #13112 does:

    • File activation → suppressed (publisher paths don't exist on the consumer machine)
    • User property activation (consumer -D flags) → suppressed (consumer didn't set those for the dependency)
    • System property activation (java.version, os.name, …) → preserved (platform facts)
    • POM-declared <properties> activation → preserved (part of the artifact's published identity — this is the case Fix #13084: allow negated-property profiles in external model builds #13095 missed)
    • JDK / OS / activeByDefault → preserved (always correct)

    This supersedes #13095. It will need a backport to maven-3.10.x.


    The repository-stripping axis (your original concern, and the new comment about alternating public/inhouse profiles each declaring their own repositories) is a separate question that #13112 deliberately doesn't touch. The redefine-detection framing — honor declared repos, warn/fail on redefinition of existing ones (especially central) — looks like the right approach. That's a separate PR/discussion when the design is settled.

  5. gnodet commented on Sep 15, 2026

    @gnodet
    Contributor

    For the record: the repository-stripping axis (this issue) has a fix in progress at #13116 on the maven-3.10.x branch.

    What #13116 does:

    The withoutRepositories() / .map() stripping was applied to all active profiles unconditionally — regardless of why they activated. But #13114 already introduced a sandboxed activation context that suppresses consumer -D flags and file conditions before profiles even reach the injection step. The blanket strip was therefore over-broad: it discarded repositories from legitimately-active profiles (JDK/OS, activeByDefault, POM-declared properties) with no security benefit.

    The fix removes the stripping for the externalOrigin / VALIDATION_LEVEL_MINIMAL branch in both the compat stack (DefaultModelBuilder.withoutRepositories()) and the impl stack (getActiveProfiles() stripping). The BUILD_CONSUMER stripping (consumer POMs must not leak profile repositories into the published artifact) is unchanged.

    This restores the pattern raised in this issue: project → dep1 → dep2 where dep1 declares dep2's repository inside an activeByDefault or JDK-activated profile.

    The redefinition concern (a dependency shadowing central with a different URL) is orthogonal and not addressed here — that is a separate WARN/FAIL policy discussion, cf. #428.

  6. added 3 commits that reference this issue on Sep 15, 2026
    80f7095
    9ff6500
    dda1c3f
  7. added a commit that references this issue on Sep 16, 2026
    28962de
  8. added 3 commits that reference this issue on Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions