Skip to content

[WP11] Build config & dependency hygiene: unpinned plugins, no Maven update lane, EOL Boot line, jar build-info pollution #183

Closed as not planned

Description

@shihyuho

此內容由 AI 產生(specification-mapper 全庫審查 2026-07-16)。

Work package WP11 · findings: DEP-03, DEP-01, DEP-04, COR-03 · worst severity: medium

From the 2026-07-16 whole-codebase review (branch jakarta, modules mapper/ + starter/). Each finding below is CONFIRMED by independent adversarial verification. File paths and line numbers reflect the review snapshot and may drift — treat them as starting points, not exact coordinates.


DEP-03 — spring-boot-maven-plugin and native-maven-plugin have no pinned version and currently resolve to Boot 4.1.0 against the 3.5.15 BOM

  • Category / severity: dependencies / medium · effort S · confidence high
  • Location: mapper/pom.xml:83
  • Evidence: mapper/pom.xml:81-91 and starter/pom.xml:61-64 declare org.springframework.boot:spring-boot-maven-plugin with no , and the parent's pluginManagement (pom.xml:124-190) manages only spotless/license/compiler/surefire; the nativeTest profile (pom.xml:329-359) declares spring-boot-maven-plugin and org.graalvm.buildtools:native-maven-plugin unversioned too. mvn -pl mapper help:effective-pom warns "'build.plugins.plugin.version' for org.springframework.boot:spring-boot-maven-plugin is missing" and resolves it to version 4.1.0 — a different major than the imported spring-boot-dependencies 3.5.15 BOM (importing a BOM does not import pluginManagement).
  • Failure scenario: Every Spring Boot plugin release silently changes this build with no commit: the day 4.x shipped, all builds switched plugin majors overnight. Running make test-native executes 4.1.0's process-test-aot against a Boot 3.5 test classpath, which can fail or generate incompatible AOT artifacts; the mapper's build-info goal likewise runs a Boot-4 plugin on a 3.5 project. Builds are non-reproducible across time.
  • Suggested fix: Add spring-boot-maven-plugin (version ${spring-boot.version}) and native-maven-plugin to the parent's pluginManagement so both modules and the nativeTest profile inherit pinned versions that move with the BOM.
  • Verification: [CONFIRMED] Traced and reproduced every structural claim. mapper/pom.xml:81-91 and starter/pom.xml:61-64 declare org.springframework.boot:spring-boot-maven-plugin with no . The parent pom.xml pluginManagement (lines 124-190) manages only spotless/license/compiler/surefire — not spring-boot-maven-plugin. The nativeTest profile (pom.xml:329-359) declares both spring-boot-maven-plugin and org.graalvm.buildtools:native-maven-plugin unversioned. The dependencyManagement import of spring-boot-dependencies 3.5.15 (pom.xml:97-107) is scope=import, which imports only dependencyManagement, not pluginManagement — correct per Maven semantics. Empirical verification via `mvn -o -pl mapper help:e…

DEP-01 — No automated update lane for any Maven dependency or plugin except spring-boot.version; visible staleness confirms the gap

  • Category / severity: dependencies / medium · effort S · confidence high
  • Location: .github/dependabot.yml:5
  • Evidence: dependabot.yml configures only the github-actions ecosystem; bump-spring.yml updates only the spring-boot.version property; Makefile:49-51 has a bump-deps target (versions:update-properties -DexcludeProperties=spring-boot.version) but nothing schedules or CI-invokes it. Resulting staleness in pom.xml: maven-gpg-plugin 3.0.1 (released 2021; 3.2.x is current and is what signs the Central releases), archunit-junit5 1.3.0 (mid-2024; 1.4.x current), maven-jar-plugin 3.3.0, maven-surefire-plugin 3.5.2.
  • Failure scenario: A CVE or breaking bug in jandex, archunit, or a build plugin never surfaces as a PR; versions drift for years (gpg plugin already ~5 years behind) until a Maven/JDK upgrade suddenly breaks the release pipeline during a time-sensitive release.
  • Suggested fix: Add a package-ecosystem: maven entry to dependabot.yml (dependabot supports ignoring spring-boot artifacts so the existing bump-spring lane stays authoritative for the BOM), or schedule a workflow that runs make bump-deps and opens a PR like bump-spring.yml does.
  • Verification: [CONFIRMED] Traced every structural claim. .github/dependabot.yml (lines 3-8) declares only one update entry: package-ecosystem "github-actions"; there is no maven ecosystem. bump-spring.yml runs make bump-spring-boot which sets only spring-boot.version (Makefile: versions:set-property -Dproperty=spring-boot.version). The Makefile bump-deps target (versions:update-properties -DexcludeProperties=spring-boot.version) exists, but grep across .github/ for bump-deps/update-properties returns nothing — no workflow schedules or invokes it, so it is manual-only. Version staleness confirmed directly in pom.xml: maven-gpg-plugin.version 3.0.1 (line 59), archunit-junit5.version 1.3.0 (line 66…

DEP-04 — Spring Boot 3.5.x baseline is at/past OSS end-of-support and the auto-bump lane is capped at ~3.x, so the lane will go silently stale

  • Category / severity: dependencies / medium · effort M · confidence medium
  • Location: pom.xml:63
  • Evidence: pom.xml:63 pins spring-boot.version 3.5.15; bump-spring.yml:33 constrains the daily bump to boot-version: "~3.x". Spring Boot 3.5 (the final 3.x line) left OSS support on 2026-06-30; Boot 4.x has been the current line since Nov 2025. The workflow even includes a keepalive job (bump-spring.yml:94-101) that keeps the daily cron alive indefinitely even after it can never find a newer 3.x version.
  • Failure scenario: Once 3.5 patches stop, the daily workflow keeps running and green while producing nothing; CVE fixes in Spring Data JPA / Spring Framework land only in Boot 4.x trains, leaving the library's build/test baseline (and its compatibility claims to consumers) on an unpatched line with no alerting that the lane is dead.
  • Suggested fix: Decide the Boot 4 story for the jakarta branch (new branch or major bump), and make the bump lane fail loudly or notify when the constrained line stops receiving releases instead of silently no-oping.
  • Verification: [CONFIRMED] Traced all cited code. pom.xml:63 pins spring-boot.version=3.5.15. bump-spring.yml:33 sets go-spring-version boot-version="~3.x", which caps the daily auto-bump at the 3.x major and cannot reach Boot 4.x. The pipeline (current-version → latest-version → compare-version → bump-spring gated on comparison-result=='>') silently skips when no newer 3.x is found, and the keepalive job (lines 94-101, liskin/gh-workflow-keepalive) keeps the daily cron alive indefinitely; there is no step that fails or notifies when the constrained line stops receiving releases. Upstream premises are accurate: Spring Boot 4.0 GA'd Nov 2025 as the current line, 3.5 is the final 3.x line with OSS support en…

COR-03 — Library jar ships META-INF/build-info.properties, hijacking consumers' BuildProperties//actuator/info

  • Category / severity: correctness / medium · effort S · confidence high
  • Location: mapper/pom.xml:87
  • Evidence: mapper/pom.xml binds spring-boot-maven-plugin's build-info goal (lines 82-91), writing META-INF/build-info.properties into target/classes; verified present in the released artifact (specification-mapper-3.1.1.jar contains META-INF/build-info.properties). Nothing in mapper or starter source consumes it (grep for build-info/BuildProperties in src/main is empty).
  • Failure scenario: A Spring Boot app that depends on specification-mapper but does not generate its own build-info satisfies ProjectInfoAutoConfiguration's @ConditionalOnResource on classpath:META-INF/build-info.properties; the app's /actuator/info and BuildProperties bean then report the library's group/artifact/version/time as the application's build info; with both files present, classpath ordering silently decides which wins.
  • Suggested fix: Remove the build-info execution from mapper/pom.xml (no code reads it), or relocate the file outside META-INF/build-info.properties if build metadata is wanted in the jar.
  • Verification: [CONFIRMED] mapper/pom.xml lines 82-91 bind spring-boot-maven-plugin's build-info goal with no custom outputFile, so it writes to the default ${project.build.outputDirectory}/META-INF/build-info.properties. Verified the file exists at mapper/target/classes/META-INF/build-info.properties, meaning it is packaged into the mapper jar. Grep across mapper/starter src shows nothing consumes build-info/BuildProperties (only hit is the pom goal itself). The hijacking is directly reproduced by the repo's own starter surefire reports (e.g. SpecificationResolverBuilderTest.xml lines 246-248): ProjectInfoAutoConfiguration#buildProperties matched because @ConditionalOnResource found classpath:META-INF/bui…

Full report: see the codebase-review-2026-07-16 branch (linked on the parent tracking issue).

Activity

  1. added theissue type on Jul 16, 2026
  2. shihyuho commented on Jul 16, 2026

    @shihyuho
    MemberAuthor

    This was generated by AI during triage.

    Triage Notes - needs human

    Category: enhancement (build config / dependency & supply-chain hygiene; includes one packaging-correctness item)

    Summary: WP11 bundles four confirmed build-config findings — two are clean, agent-safe POM edits (DEP-03, COR-03); two require human policy/infrastructure decisions (DEP-01 dependency update-lane, DEP-04 Boot EOL strategy) — so the package as a whole is held for a human call.

    Current behavior

    • DEP-03 (unpinned build plugins): The spring-boot-maven-plugin is declared with no <version> in the specification-mapper (mapper) module, the specification-mapper-starter module, and the parent nativeTest profile; the native-maven-plugin in that same profile is likewise unversioned. The parent's pluginManagement pins only spotless / license / compiler / surefire. The parent imports spring-boot-dependencies with scope=import, which contributes dependencyManagement only — it does not manage plugin versions. As a result the Spring Boot plugin version floats to whatever Maven resolves as latest, independent of the pinned spring-boot.version (currently 3.5.15), and the build emits a "plugin version is missing" warning and is not reproducible across time.
    • COR-03 (build-info pollution): The mapper module binds the spring-boot-maven-plugin build-info goal with no custom outputFile, so it writes META-INF/build-info.properties into the module output and ships it inside the released library jar. No source in either module reads build-info / BuildProperties. A downstream Spring Boot app that does not generate its own build-info will match ProjectInfoAutoConfiguration's @ConditionalOnResource(classpath:META-INF/build-info.properties) off the library's file, so its BuildProperties bean and /actuator/info report the library's coordinates as the application's build info.
    • DEP-01 (no Maven update lane): dependabot.yml declares only the github-actions ecosystem. The scheduled bump-spring workflow updates only the spring-boot.version property. A bump-deps Makefile target (versions:update-properties -DexcludeProperties=spring-boot.version) exists but no workflow invokes it, so every non-Boot dependency and plugin is updated manually only. Confirmed staleness in the parent POM: maven-gpg-plugin 3.0.1, archunit-junit5 1.3.0, maven-jar-plugin 3.3.0, maven-surefire-plugin 3.5.2.
    • DEP-04 (EOL Boot line + silently-dead lane): spring-boot.version is 3.5.15; the bump-spring workflow constrains the auto-bump to boot-version: "~3.x", which cannot reach Boot 4.x. A keepalive job keeps the daily cron alive indefinitely. Once the 3.5 line stops publishing, the workflow keeps running green while producing nothing, and there is no step that fails or notifies when the constrained line goes silent.

    Desired behavior

    • DEP-03: Both Spring Boot plugin and the native plugin resolve to explicitly pinned versions that track the Boot BOM; spring-boot-maven-plugin moves with spring-boot.version, and the "missing plugin version" warning disappears.
    • COR-03: The published mapper jar does not contain META-INF/build-info.properties, so it cannot hijack a consuming application's BuildProperties / /actuator/info.
    • DEP-01: Non-Boot Maven dependencies and build plugins get an automated update lane (Dependabot maven ecosystem, or a scheduled workflow running make bump-deps) that opens PRs, without conflicting with the authoritative Boot lane.
    • DEP-04: A decided direction for the Boot 3.x-vs-4.x baseline on the jakarta branch, and an auto-bump lane that alerts (fails or notifies) rather than silently no-op'ing when its constrained version line stops receiving releases.

    Key interfaces

    • Parent pom.xml: build/pluginManagement, the spring-boot.version / plugin-version properties, and the nativeTest profile plugin declarations.
    • specification-mapper (mapper) module pom.xml: the spring-boot-maven-plugin execution binding the build-info goal.
    • specification-mapper-starter module pom.xml: its spring-boot-maven-plugin declaration (no execution).
    • .github/dependabot.yml; .github/workflows/bump-spring.yml; Makefile targets bump-deps and bump-spring-boot.
    • Downstream contract: Spring Boot ProjectInfoAutoConfiguration + @ConditionalOnResource(classpath:META-INF/build-info.properties).

    Acceptance criteria

    Agent-safe subset (DEP-03 + COR-03), if scoped out for autonomous work:

    • spring-boot-maven-plugin is pinned (version tracking spring-boot.version) so the mapper module, the starter module, and the nativeTest profile all inherit it; native-maven-plugin in the nativeTest profile is pinned to an explicit version.
    • mvn help:effective-pom (or the build) no longer warns that the Spring Boot plugin version is missing, and the resolved version matches the pinned Boot line rather than a floating latest.
    • The mapper module no longer produces META-INF/build-info.properties in its build output, and the packaged jar does not contain that resource.
    • mvn test passes for both modules.

    Human-gated items (DEP-01 + DEP-04) — criteria depend on the decisions below and are intentionally left open here.

    Out of scope

    • Bumping any specific stale dependency/plugin to a chosen version (that is the output of the update lane, not this package).
    • Migrating the codebase to Spring Boot 4.x.

    Needs human because

    • DEP-04 is a strategic policy decision: whether the jakarta branch stays on the EOL 3.5 line, cuts a new branch, or takes the breaking Boot 4 major bump is a compatibility-contract judgment for the library's consumers — not something an autonomous agent should decide. The related "alert when the lane goes dead" change is CI/release-infrastructure work needing sign-off.
    • DEP-01 is a supply-chain/CI-infrastructure decision: enabling a Dependabot maven ecosystem (or a scheduled auto-PR workflow) and defining how it coexists with the authoritative Boot lane is release-pipeline configuration that a human must own, and it is not verifiable by the JUnit suite.
    • Because these two findings are load-bearing to the work package (and DEP-04 is arguably its most important item on security grounds), the whole WP is held for a human. A human may split it: DEP-03 and COR-03 meet the ready-for-agent bar and can be handed off as a scoped sub-task with the acceptance criteria above.
  3. shihyuho commented on Jul 20, 2026

    @shihyuho
    MemberAuthor

    Superseded by #200 in the execution map #204, which carries the same findings (DEP-01, DEP-03, DEP-04, COR-03). This 2026-07-16 static plan is being retired in favour of that map.

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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions