Skip to content

Parent POM dependencies are interpolated in the parent's property scope, ignoring child property overrides #7

Description

@borkdude

effective-pom* inherits the parent POM's dependencies after they have already been interpolated against the parent's own properties. A child POM that overrides a property used in an inherited dependency version has no effect, and the wrong version is selected.

Maven builds the child's effective model by inheriting the raw dependency elements and interpolating them against the child's merged properties.

Repro

test/fixtures/differential-corpus.edn:

[{:name :tools-logging
  :deps {org.clojure/tools.logging {:mvn/version "1.3.0"}}}]
GRENADINE_ORACLE_CASES=0 make oracle
Mismatch: :tools-logging
tools.deps: org.clojure/clojure 1.10.3, spec.alpha 0.2.194, core.specs.alpha 0.2.56
grenadine:  org.clojure/clojure 1.8.0, no spec.alpha, no core.specs.alpha

Cause

org.clojure/pom.contrib:1.1.0 declares the inherited dependency through a property:

<properties>
  <clojure.version>1.8.0</clojure.version>
</properties>
<dependencies>
  <dependency>
    <groupId>org.clojure</groupId>
    <artifactId>clojure</artifactId>
    <version>${clojure.version}</version>
  </dependency>
</dependencies>

org.clojure/tools.logging:1.3.0 overrides that property:

<parent>
  <groupId>org.clojure</groupId>
  <artifactId>pom.contrib</artifactId>
  <version>1.1.0</version>
</parent>
<properties>
  <clojure.version>1.10.3</clojure.version>
</properties>

src/grenadine/pom.cljc:335:

dependencies
(merge-ordered (or (:deps parent) []) declared-dependencies)

(:deps parent) comes back from the recursive effective-pom* call already interpolated with the parent's clojure.version of 1.8.0. The child's override reaches raw-properties at line 288 but never reaches the inherited dependency.

parent-management at line 316 has the same shape. Inherited <dependencyManagement> entries are interpolated in the parent's scope before the child can override the property.

Scope

Every org.clojure/* contrib library inherits org.clojure/clojure from pom.contrib this way, and each pins its own clojure.version. org.clojure/core.async 1.8.741 resolves org.clojure/clojure to 1.9.0 instead of 1.11.4 for the same reason.

More generally this affects any inherited dependency or managed dependency whose group, artifact, or version comes from a property the child overrides.

Suggested fix

Return the parent's uninterpolated <dependencies> and <dependencyManagement> from effective-pom*, and interpolate the merged set once against the child's interpolation-context.

Note on the differential corpus

test/fixtures/differential-corpus.edn holds 6 entries, and random-deps in test/grenadine/oracle.clj draws its fuzz cases from that same corpus, so the fuzz pass only explores combinations of those 6 dependency maps. Widening the corpus to 20 popular libraries surfaced this on the first run. A larger corpus pulled from Clojars would catch this class of bug earlier.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions