Conversation
We had overlapping changes in Resolver and Maven, align them.
|
Sure about the SNAPSHOT-dependency, @cstamas ? Or will you resolve this before you make the draft final? |
|
We usually run "main" branches (in quotes, as we have several "main" branches, the master, the maven-4.0.x, the maven-3.10.x, etc) just before the release with SNAPSHOT versions, as we do produce and deploy them, is fine to get another layer of confirmation. OTOH, you cannot release anyway with a SNAPSHOT, hence, this is completely okay, and we did it before as well. |
|
So, all of ITs explode, reason is f013 in this commit: @gnodet ping |
|
@cstamas The root cause is the tracking key function change from This affects all 9 IT jobs (4229 test failures, 507 unique test classes on ubuntu/JDK26 alone). The Fix PR: apache/maven-resolver#2133 — adds a backward-compatible fallback in |
…allback (#2133) ## Summary When the tracking key function is URL-qualified (`nid_hurl`, the default since 2.0.23 / commit 339161b), tracking entries written by an older resolver using ID-only keys (`nid` format, e.g. `artifact>central=`) are invisible to the new lookup which expects `artifact>central-<sha1>=`. This causes **all** artifacts cached in the local repository before the upgrade to appear as "present but unavailable", triggering full re-downloads from remote repositories. In CI environments and integration tests that use fake/file-based repositories (like maven-integration-testing), this breaks resolution entirely — see [apache/maven#13078 (comment)](apache/maven#13078 (comment)). ## Root Cause The tracking key change from `nid` to `nid_hurl` (finding f013 in the security audit) makes existing `_remote.repositories` entries invisible: - **Old entry**: `maven-core-3.8.6.pom>central=` - **New lookup**: `maven-core-3.8.6.pom>central-<sha1 of repo URL>=` → no match The `isTracked()` check finds the old `central=` entry, so the artifact is treated as "tracked but not for the current repo" rather than "untracked" — the untracked inter-op fallback does not apply, and the artifact is rejected. ## Fix Add a backward-compatible fallback in `applyTracking()`: when the URL-qualified (`nid_hurl`) lookup misses, try the system-wide key function (`nid` by default) as a fallback. If that matches, accept the artifact and log a debug message. The legacy entry will be upgraded to the new key format on the next download. This preserves the f013 security improvement (URL-qualified tracking prevents same-id-different-URL repository poisoning for *new* entries) while providing a smooth upgrade path from older resolvers. ## Tests - Updated `testUrlQualifiedTrackingTreatsLegacyIdOnlyEntriesAsStale` → `testUrlQualifiedTrackingAcceptsLegacyIdOnlyEntriesViaFallback`: legacy entries from a matching repo are now accepted - Added `testUrlQualifiedTrackingRejectsLegacyIdOnlyEntriesFromDifferentRepo`: legacy entries from a *different* repo are still rejected - `testUrlQualifiedTrackingDistinguishesSameIdDifferentUrl`: unchanged — URL-qualified entries still prevent same-id-different-URL poisoning
|
Updated the resolver fix PR based on @cstamas's analysis. The first fix only handled legacy The ITs override The fix now has a two-stage fallback:
This effectively relaxes f013 to recording-only: entries are written with URL-qualified keys, but lookups fall back to repo-ID matching. All 585 resolver tests pass. Fix PR: apache/maven-resolver#2133 (force-pushed with the updated fix) |
|
@cstamas — the SNAPSHOT and IT-explosion questions are resolved on my side (thanks, and to @gnodet for #2133). One code point from the validation consolidation itself, independent of the IT fix: The removed Two minors: |
gnodet
left a comment
There was a problem hiding this comment.
Review: validation consolidation looks correct, one gap to fix
The consolidation from two separate validation sites (DefaultMetadataReader.validateMetadata() and DefaultRepositoryMetadataManager.validateVersioning()) into the single ValidatingMetadataXpp3Reader.validate() is clean — it eliminates the duplicate validateVersioning() call and the now-redundant per-reader validation logic.
The new validate() method correctly covers versioning tokens (latest, release, versions[], snapshotVersions[].version, snapshot.timestamp) and plugin.getArtifactId(). The snapshot timestamp validation and metadata.getVersion() validation are new additions not present in either old reader — good.
However, as @ascheman noted: plugin.getPrefix() validation was dropped. The removed DefaultMetadataReader.validateMetadata() explicitly validated both plugin.getArtifactId() and plugin.getPrefix(), with its Javadoc stating these "get carried forward by callers as if they were already-validated path and coordinate components." The consolidated reader only validates plugin.getArtifactId().
Fix: add PathUtils.validatePathComponent(plugin.getPrefix(), "plugin/prefix"); alongside the artifactId validation in ValidatingMetadataXpp3Reader.validate().
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of @gnodet
Co-authored-by: Guillaume Nodet <gnodet@gmail.com>
gnodet-bot
left a comment
There was a problem hiding this comment.
Re-review: previous finding addressed, one gap remains
The plugin.getPrefix() validation raised in the previous review is now correctly added alongside plugin.getArtifactId() in ValidatingMetadataXpp3Reader.validate() — that concern is resolved.
The consolidation itself is clean:
- The double
validateVersioning()call inDefaultRepositoryMetadataManager.readMetadata()(once inside thetryblock and once after it — running twice on the happy path) is correctly removed validate()goingprivateis safe — no external callers exist in the codebaseIllegalArgumentException→IOExceptionwrapping is consistent and chains the cause correctly- Resolver 2.0.23 is released on Central ✓
One gap: the new plugin validation path (plugin/artifactId, plugin/prefix) has no test coverage. The existing tests exercise versioning tokens and snapshot timestamps, but there is no test with a metadata file containing an invalid plugin token (e.g. a plugin.getPrefix() with a / or ..). The validation code is correct, but there's no guard against a regression there.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
| for (Plugin plugin : metadata.getPlugins()) { | ||
| PathUtils.validatePathComponent(plugin.getArtifactId(), "plugin/artifactId"); | ||
| PathUtils.validatePathComponent(plugin.getPrefix(), "plugin/prefix"); |
There was a problem hiding this comment.
DefaultRepositoryMetadataManagerTest and DefaultRepositoryMetadataManagerValidationTest only cover versioning tokens and snapshot timestamps — neither fires when plugin.getArtifactId() or plugin.getPrefix() contains an invalid character. Add a test resource (e.g. metadata-invalid-plugin-prefix/maven-metadata.xml) with a <plugin> whose prefix contains / or .., and assert the expected exception.
gnodet-bot
left a comment
There was a problem hiding this comment.
Re-review: previous finding addressed — LGTM
The missing plugin validation test coverage flagged in the last review is now in place:
testMetadataWithInvalidPluginArtifactIdIsRejected()→ exercisesplugin/artifactIdrejection onsome/../artifactid(contains/)testMetadataWithInvalidPluginPrefixIsRejected()→ exercisesplugin/prefixrejection onsome/prefix(contains/)
The message substring assertions ("Invalid plugin/artifactId", "Invalid plugin/prefix") correctly match the PathUtils.validatePathComponent error format, which propagates through the IOException wrapping in ValidatingMetadataXpp3Reader.read() and the RepositoryMetadataReadException in DefaultRepositoryMetadataManager.readMetadata().
Rest of the consolidation remains solid: no external callers of validate() (making it private is safe), IllegalArgumentException → IOException chaining is correct, and the resolver bump to 2.0.23 is clean.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
We had overlapping changes in Resolver and Maven, align them.