Skip to content

Improve standalone ApiRunner to properly apply settings - #12998

Merged
gnodet merged 8 commits into
masterfrom
apirunner-is-the-main-entry-point-to-use-maven-4-s
Sep 2, 2026
Merged

Improve standalone ApiRunner to properly apply settings#12998
gnodet merged 8 commits into
masterfrom
apirunner-is-the-main-entry-point-to-use-maven-4-s

Conversation

@gnodet

@gnodet gnodet commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

The standalone ApiRunner is the main entry point for using the Maven 4 API outside of a full Maven build (e.g. in tools like mvnup). Previously it had several gaps that made it unsuitable for production use — settings were hardcoded to a test directory, proxy/mirror/auth from settings.xml were ignored, and dependency resolution machinery was not configured.

This PR fixes all of these issues:

  • Remove hardcoded user.home = "target" — the standalone API now reads settings from the real user home (~/.m2/settings.xml)
  • Store effective settings on the sessionsession.getSettings() now returns the actual effective settings instead of an empty object
  • Apply proxy configuration from settings via DefaultProxySelector
  • Apply mirror configuration from settings via DefaultMirrorSelector
  • Apply server authentication from settings via DefaultAuthenticationSelector (username, password, private key)
  • Configure dependency resolution machinery via MavenSessionBuilderSupplierDependencyTraverser, DependencyManager, DependencySelector, DependencyGraphTransformer, ArtifactTypeRegistry, ArtifactDescriptorPolicy
  • Detect and set Maven version from classpath pom.properties (fixes @Nonnull contract violation)
  • Honor offline mode from settings
  • Clean up stale TODO comments and dead commented-out code

Also makes 5 getter methods in MavenSessionBuilderSupplier public (from protected) so they can be reused by ApiRunner across packages.

Test plan

  • All 611 tests in maven-impl pass (0 failures)
  • TestApiStandalone — verifies artifact resolution and dependency collection work
  • RequestTraceTest — verifies request tracing works with standalone session
  • DiTest — verifies DI wiring
  • maven-core compiles successfully with the visibility changes

🤖 Generated with Claude Code

@gnodet gnodet added the enhancement New feature or request label Sep 1, 2026
@gnodet gnodet added this to the 4.0.0-rc-7 milestone Sep 1, 2026
@gnodet
gnodet marked this pull request as ready for review September 1, 2026 10:59

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid enhancement that makes the standalone ApiRunner production-ready by wiring proxy, mirror, auth, and dependency resolution from settings.xml.

One item merits attention:

getMavenVersion() can still return null when pom.properties is absent from the classpath or version parsing fails, violating the @Nonnull contract declared in Session.java. The PR improves on the previous code (which always returned null in standalone mode) but doesn't fully close the gap. A fallback sentinel version (e.g. "0.0.0") would satisfy the contract.

Strengths:

  • The proxy/mirror/auth configuration faithfully follows patterns from DefaultRepositorySystemSessionFactory and DefaultMavenExecutionRequestPopulator
  • Clean removal of dead code and stale TODO comments
  • Widening 5 MavenSessionBuilderSupplier methods from protected to public is appropriate — these are in the impl module, not the public API

Note: The commit message uses a placeholder JIRA number ([MNG-8xxx]). This should be replaced with a real issue number before merging.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delta re-review — 3 new commits since previous review.

The three new commits are well-implemented improvements:

  • Property loading (e484175, 333654f) correctly mirrors the CLI's precedence (installation system → user system → user properties) without needing ${includes} directive support. The ~/.m2/ location for user properties is correct per Maven conventions. Code comments clearly explain the design decisions.
  • Repository handling (7521131) properly preserves settings-derived repositories in mvnup and only appends fallback defaults when not already present. The set-based ID check is the right approach.

Previous findings status

Finding Status Detail
getMavenVersion() null vs @Nonnull ⬆️ Improved detectMavenVersion() now tries both maven-core and maven-impl pom.properties, but still returns null when neither exists. Pre-existing on master (previously always null in standalone mode), so the PR is an improvement. A fallback sentinel (e.g. VersionParser.parseVersion("0.0.0")) would fully close the gap.
Placeholder JIRA [MNG-8xxx] ⏳ Pending First commit message still reads [MNG-8xxx] — should be replaced with a real issue number before merge.

New observation (low severity)

loadMavenProperties silently swallows IOException and returns an empty map. The class has no logger, so there's nowhere to log, but this could mask real configuration failures on files that exist but are unreadable (permissions, concurrent deletion). A debug-level log or comment explaining the rationale would help.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

@gnodet
gnodet force-pushed the apirunner-is-the-main-entry-point-to-use-maven-4-s branch from 333654f to df53ab2 Compare September 1, 2026 18:44

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delta re-review — All previous findings addressed.

getMavenVersion() null contractdetectMavenVersion() now returns @Nonnull Version, falling back to a "0.0.0" sentinel when no pom.properties is on the classpath. Fully closes the @Nonnull contract gap.

Placeholder JIRA [MNG-8xxx] — Removed from the rebased commit message.

Silent IOException in loadMavenProperties — Catch block now has a clear 3-line comment explaining the design rationale: properties files are optional, standalone API has no logger, and failure gives the same behavior as if the file didn't exist.

Clean fix commit, well-scoped to exactly the reported issues. No new concerns.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delta review — one new commit: 6d26d3fdec — "Support encrypted settings passwords in standalone ApiRunner"

Well-designed addition with a clean SecurityMode API, proper classpath detection, and support for both legacy ({...}) and Maven 4 master-key-based encryption.

Two minor observations (non-blocking):

  1. hasExistingDispatchers guard (ApiRunner.java:252): The check uses getAllBindings(Dispatcher.class) which only finds unqualified bindings. The test-scoped SecDispatcherProvider registers named dispatchers (via @Named(LegacyDispatcher.NAME) etc.), so the guard doesn't actually detect them. In practice this is harmless (DI framework handles duplicates and dispatchers are stateless), but the check doesn't achieve its documented intent of preventing duplicate bindings in the test scenario.

  2. SecurityMode test coverage (ApiRunner.java:143): The existing TestApiStandalone implicitly exercises the default IF_AVAILABLE_WARN path, but the NONE, IF_AVAILABLE, and REQUIRED modes are untested. In particular, the REQUIRED mode's MavenException throw when plexus-sec-dispatcher is absent has no test verifying the behavior.

Positive notes:

  • Good design decision to call configureSecurityDispatchers before injectorConsumer.accept(injector), allowing callers to override default bindings.
  • SecDispatcherBindings correctly mirrors the test-scoped SecDispatcherProvider, covering all four master source types.
  • Visibility changes in MavenSessionBuilderSupplier (protected→public) are a reasonable follow-on from earlier commits.

🤖 This review was generated by ForgeBot.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delta review — one new commit: d220f4e91c — "Add tests for ApiRunner settings handling and SecurityMode"

SecurityMode test coverage — All four enum values (NONE, IF_AVAILABLE, IF_AVAILABLE_WARN, REQUIRED) are now exercised in the happy path. Settings features (servers, mirrors, repositories, offline, encrypted passwords) are well-tested with proper isolation. The REQUIRED mode's exception path when plexus-sec-dispatcher is absent remains untested, but the test comment explicitly acknowledges this limitation — the library is a compile dependency, so ClassNotFoundException cannot be triggered without classloader tricks. Reasonable trade-off.

Good use of the validated master/server password values from the mng-8379 integration test fixtures.

No new concerns.


🤖 This review was generated by ForgeBot.

gnodet and others added 6 commits September 1, 2026 23:05
The standalone ApiRunner is the main entry point for using the Maven 4
API outside of a full Maven build (e.g. in tools like mvnup). Previously
it had several gaps that made it unsuitable for production use:

- Hardcoded user.home to "target" (meant for unit tests only)
- Settings were built but never stored on the session (getSettings()
  always returned empty)
- No proxy, mirror, or server authentication support
- Missing dependency resolution machinery (DependencySelector,
  DependencyGraphTransformer, DependencyManager, etc.)
- getMavenVersion() returned null, violating @nonnull contract
- Offline mode from settings was ignored

This commit fixes all of these issues:

- Remove the hardcoded user.home override so real settings.xml is loaded
- Store effective settings on the session so getSettings() returns them
- Apply proxy configuration from settings via DefaultProxySelector
- Apply mirror configuration from settings via DefaultMirrorSelector
- Apply server authentication from settings via DefaultAuthenticationSelector
- Configure dependency resolution via MavenSessionBuilderSupplier
  (DependencyTraverser, DependencyManager, DependencySelector,
  DependencyGraphTransformer, ArtifactTypeRegistry, ArtifactDescriptorPolicy)
- Detect and set Maven version from classpath pom.properties
- Honor offline mode from settings
- Clean up stale TODO comments and dead commented-out code

Also makes 5 getter methods in MavenSessionBuilderSupplier public
(from protected) so they can be reused by ApiRunner across packages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ApiRunner

Resolves the Maven configuration directory (via maven.installation.conf,
maven.conf, or maven.home) and loads both property files with interpolation,
matching the CLI behavior. System properties are merged into the session's
system properties map; user properties are exposed via getUserProperties()
and set on the resolver session.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The installation-level maven-user.properties (in ${maven.home}/conf/)
is a CLI bootstrapper that contains Maven-internal configuration
(maven.cache.config, aether.conflictResolver.impl) which interferes
with standalone usage. Load user properties from the user-level
location (~/.m2/maven-user.properties) instead, matching the
${includes} chain the CLI follows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- detectMavenVersion() now returns "0.0.0" sentinel instead of null when
  no pom.properties is on the classpath, so Session.getMavenVersion() is
  never null.
- loadMavenProperties() IOException catch block now has a comment
  explaining why the exception is silently ignored (no logger available,
  files are optional configuration, same behavior as if file didn't exist).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add SecurityMode enum to control how the standalone session handles
encrypted passwords in settings.xml:
- NONE: skip decryption entirely
- IF_AVAILABLE: try to bind dispatchers, skip silently if unavailable
- IF_AVAILABLE_WARN (default): try, warn if unavailable
- REQUIRED: try, fail if unavailable

When plexus-sec-dispatcher is on the classpath, both legacy ({...}) and
Maven 4 master-key-based encrypted passwords are supported.  The binding
is skipped if dispatchers are already provided (e.g., by test discovery).

Remove the manual LegacyDispatcher binding from mvnup's
AbstractUpgradeStrategy since ApiRunner now handles it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers all four SecurityMode values, settings servers/mirrors/repositories,
legacy encrypted password decryption, plaintext password pass-through,
and offline mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet
gnodet force-pushed the apirunner-is-the-main-entry-point-to-use-maven-4-s branch from d220f4e to e2bc0f7 Compare September 1, 2026 21:12
gnodet and others added 2 commits September 1, 2026 23:22
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ceTest

The relocatedTarget method now declares ArtifactDescriptorException but this
test method was not updated to handle it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet gnodet self-assigned this Sep 2, 2026
@gnodet gnodet modified the milestones: 4.0.0-rc-7, 4.1.0 Sep 2, 2026
@gnodet gnodet added the mvn4 label Sep 2, 2026
@gnodet
gnodet merged commit c6afe7e into master Sep 2, 2026
23 checks passed
@gnodet
gnodet deleted the apirunner-is-the-main-entry-point-to-use-maven-4-s branch September 2, 2026 09:53
gnodet added a commit that referenced this pull request Sep 2, 2026
Backport of #12998 to maven-4.0.x.

The standalone ApiRunner is the main entry point for using the Maven 4 API
outside of a full Maven build (e.g. in tools like mvnup). This improves it
to be production-ready:

- Remove hardcoded user.home = "target" — read settings from real user home
- Store effective settings on the session
- Apply proxy, mirror, and server authentication from settings.xml
- Configure dependency resolution machinery
- Support encrypted settings passwords with SecurityMode enum
- Load maven-system.properties and maven-user.properties
- Detect and set Maven version from classpath pom.properties
- Honor offline mode from settings
- Use ApiRunner-provided repositories in mvnup instead of replacing them
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request mvn4

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants