Skip to content

Validate legacy metadata inputs and clone proxies before decryption - #12950

Open
slachiewicz wants to merge 4 commits into
apache:masterfrom
slachiewicz:pr/legacy-compat-master
Open

Validate legacy metadata inputs and clone proxies before decryption#12950
slachiewicz wants to merge 4 commits into
apache:masterfrom
slachiewicz:pr/legacy-compat-master

Conversation

@slachiewicz

@slachiewicz slachiewicz commented Aug 30, 2026

Copy link
Copy Markdown
Member

Fixes on the legacy compatibility paths.

  • Checksum policy. Three legacy metadata paths ignored the configured checksum policy and defaulted to a warning regardless of a fail setting; the configured policy is now threaded through and honoured.
  • Repository key and metadata tokens. The repository key is validated before it becomes part of a local file name, and version tokens from downloaded metadata are validated at the single point all metadata passes through, which also covers the latest/release/snapshot transformations.
  • Proxy decryption. DefaultSettingsDecrypter now clones each proxy before setting its decrypted password, mirroring the existing behaviour for servers, so decryption no longer mutates the caller's settings objects. Maven 3 already clones here.

Each change is a separate commit.


Draft while related code paths are reviewed — the same guard may be needed in sibling implementations of these interfaces, and I would rather establish that before asking for review time.

AbstractRepositoryMetadata.getLocalFilename rejects a repository key that is
the ".." token, contains '/', '\', ':', or an ISO control character, before
using it in a local file name. DefaultRepositoryMetadataManager.readMetadata
applies the same check to every version token carried by parsed repository
metadata (latest, release, versions, snapshot versions, snapshot timestamp)
before the metadata is merged and used to resolve a version.

Matches the check already used for relocation and version-range coordinates
elsewhere in the resolver.
The proxy loop in DefaultSettingsDecrypter.decrypt mutated the
caller's live Proxy objects directly, unlike the server loop just
above it which already clones before mutating. Since compat model
objects propagate setter changes up into their parent Settings
delegate, this meant a decrypted proxy password could end up written
back into the session-wide Settings object. Clone the proxy first,
mirroring the server handling, so decryption only ever touches the
copies returned in the result.
@slachiewicz slachiewicz added the bug Something isn't working label Aug 30, 2026
@slachiewicz
slachiewicz marked this pull request as draft August 30, 2026 19:05
@slachiewicz
slachiewicz marked this pull request as ready for review August 30, 2026 22:00

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The repository key validation and proxy clone-before-decrypt changes are correct, well-tested, and consistent with the approved 4.0.x (#12945) and 3.10.x (#12954) variants.

However, this PR appears to be missing two checksum-policy commits that are present in the 4.0.x variant (#12945):

1. Description/content mismatch (medium)

The PR description states "Checksum policy. Three legacy metadata paths ignored the configured checksum policy and defaulted to a warning regardless of a fail setting; the configured policy is now threaded through and honoured." — but the diff does not include the commits that implement this:

  • DefaultRepositoryMetadataManager.getArtifactMetadataFromDeploymentRepository() (line 358) still hardcodes CHECKSUM_POLICY_WARN
  • DefaultRepositoryMetadataManager.resolve() lacks a ChecksumFailedException catch clause
  • LegacyRepositorySystem.retrieve() (line 663) still hardcodes CHECKSUM_POLICY_WARN

The approved 4.0.x PR (#12945) has 5 commits; this master PR has only 3 — the two missing are "Fail closed on metadata checksum mismatches under the fail policy" and "Thread the configured checksum policy through two legacy metadata fetches".

Suggestion: Either cherry-pick the two missing checksum commits into this PR, or update the PR description to remove the checksum bullet.

2. Minor: code duplication (low)

isInvalidPathToken() / validateRepositoryKey() are duplicated in LegacyLocalRepositoryManager and AbstractRepositoryMetadata — acceptable for deprecated compat code.

📋 PR Metadata

Aspect Current Suggested
Milestone (none) 4.1.0

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

The legacy metadata manager and repository system hardcoded
CHECKSUM_POLICY_WARN, silently ignoring the operator's
--strict-checksums / -C flag and per-repository checksumPolicy
settings. This brings the master branch in line with the
maven-4.0.x fix (PR apache#12945):

- Catch ChecksumFailedException in resolve() and propagate it as a
  RepositoryMetadataResolutionException under CHECKSUM_POLICY_FAIL
- Move updateCheckManager.touch() out of the finally block so that
  failed transfers do not suppress retries for a full update interval
- Use the repository's configured checksum policy for deployment
  metadata retrieval instead of hardcoded WARN
- Pick the stricter of release/snapshot policies in
  LegacyRepositorySystem.retrieve() instead of hardcoded WARN

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

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Delta re-review — Previous finding resolved. The new commit 6ff4b8a cleanly addresses the missing checksum-policy issue.

Previous finding resolved:

Checksum policy now honoured on all three legacy paths:

  • DefaultRepositoryMetadataManager.getArtifactMetadataFromDeploymentRepository() — no longer hardcodes CHECKSUM_POLICY_WARN
  • DefaultRepositoryMetadataManager.resolve()ChecksumFailedException catch clause correctly placed before the TransferFailedException catch (important since ChecksumFailedException extends TransferFailedException)
  • LegacyRepositorySystem.retrieve() — uses getChecksumPolicy() which returns the stricter of releases/snapshots policies via a rank helper

Design observations (non-blocking):

  • updateCheckManager.touch() wisely restructured: moved from finally to explicit success/error paths, deliberately omitting it from ChecksumFailedException so the next build retries immediately instead of trusting stale metadata
  • The "stricter of releases/snapshots" approach in LegacyRepositorySystem.getChecksumPolicy() is the right choice for a generic path that can't be classified
  • Two focused tests verify the strict-fail behaviour

📋 PR Metadata

Aspect Current Suggested
Milestone (none) 4.1.0

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

Claude Code on behalf of Guillaume Nodet

@gnodet

gnodet commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Update on cross-branch coverage:

The original review on this PR incorrectly referenced #12954 as a related variant. PR #12954 is actually a different set of fixes (credential scoping, relocation validation, exact server ID matching) — not a port of this PR.

The correct cross-branch map for the fixes in this PR (path traversal validation + checksum policy + proxy clone) is:

Branch PR
maven-4.0.x #12945
master #12950 (this PR)
maven-3.10.x #12978

Separately, the fixes from #12954 (credential scoping + relocation validation + server ID matching) have been forward-ported:

Branch PR
maven-3.10.x #12954
maven-4.0.x #12977
master #12976

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants