Repository navigation
Fix Maven ${property} groupId/artifactId (#683) - #1788
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A dependency written as <groupId>${ct.group}</groupId> (or a property
artifactId) was never recognised as the patched package. Hosted scan
then added a dependencyManagement pin that the direct literal version
overrides, so Maven built the unpatched jar while scan reported it
redirected and vex attested not_affected (#683).
The shared pom scope now resolves ${prop} in groupId and artifactId
from the pom's own <properties>, so the hosted rewriter pins the
direct literal, vex reads the real coordinates, and rollback finds the
pin it wrote. A coordinate that names a property the pom does not
define (a parent's) may be the patched package: hosted scan refuses
the dep with redirect_maven_coordinate_unresolved and vex does not
attest past it.
Assisted-by: Claude Code:claude-opus-5-5
A sibling declaration such as ${project.groupId}:${project.artifactId}
-core would have looked like it might be any patched package and
blocked every hosted Maven pin in the pom. The pom scope now resolves
the project's own groupId, artifactId and version references (the
parent's when inherited), and an undefined reference only matches
packages whose name fits the literal text around it.
Assisted-by: Claude Code:claude-opus-5-5
Review fixes for the #683 change: - rollback removes a dependencyManagement pin an earlier release wrote beside a ${property} declaration, instead of leaving it at the base version - vex attests a vendored pin when an unresolved-coordinate declaration names the vendored version, and folds such declarations into Maven's version precedence instead of a separate refusal - properties defined through other properties, project.parent.* refs, and project.* model values (over same-named properties) resolve - a pom-type import or classifier variant never counts as the main jar; a profile declaration warns like a literal one - restore reads the pom scope once per pin Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
A project groupId or version written through a property is now interpolated rather than replaced by the parent's, and an element of the same name inside <properties> is no longer read as the project's own. A <type> given by an undefined property may still be jar, so that declaration now blocks a pin the same way. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
Ready for review at
Generated by Claude Code |
interpolate re-expanded the whole coordinate for up to 8 rounds with no size limit, so a pom whose properties each name the previous one many times grew exponentially: a 1.4 KB pom drove vex, the hosted rewrite and rollback to ~10 GB and an OOM kill. A round that would exceed 1 KB is now not taken, leaving the reference unresolved, which may_shadow already treats as fail-closed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Final reviewer: pushed 27ca653, which caps Maven coordinate interpolation at 1 KB.
Not fixed here: Removed bugbot run Generated by Claude Code |
|
bugbot run Generated by Claude Code |
|
Ready for review at
Generated by Claude Code |
Final review briefWhat it does. Fixes #683. A Maven dependency written as Risk: medium. It changes Maven matching in three readers, but the new rule fails closed (an unknown property can only block a pin or an attestation, never add one), and interpolation is capped at 8 rounds and 1 KB. Look here
Verified
Changes I made: none this pass. Open questions (not blocking)
Auto-merge (squash) is armed, so approving sends this straight to the merge queue. Generated by Claude Code |
Maven lets .mvn/maven.config's -D user properties override the pom's own <properties>. Hosted scan, vex and rollback ignored them, so a pom with <g>org.slf4j</g> built with -Dg=com.acme.fork had the fork's dependency rewritten to the Socket version, which then failed to resolve. All three now read maven.config's user properties over the pom's when interpolating a coordinate, sharing the reader the vendored reactor already uses. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
Final reviewer: I turned auto-merge off. The review brief covers Generated by Claude Code |
Final review brief (updated for
|
|
bugbot run Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 09ac691. Configure here.
|
Burn-down agent: Ready for review confirmed at
Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #683
Summary
A Maven dependency declared through a property coordinate, such as
<groupId>${ct.group}</groupId>withct.groupdefined in the pom's own<properties>, was never recognised as the patched package.scan --mode hostedthen added a<dependencyManagement>pin. The directliteral
<version>1.10.0</version>overrides that pin, so Maven builtCentral's unpatched jar. Scan still reported the dep as redirected, and both
the in-run and standalone
vexattestednot_affected.The
<exclusions>-first half of #683 was already fixed onmain: thehosted matcher reads through
PomScope, which blanks<exclusions>. Aregression case for it is included here.
Root cause
formats::maven::PomScope::dependencies()readgroupId/artifactIdasraw text. Every reader built on it missed the declaration: the hosted
rewriter (
maven_index::PomIndex), the VEX reader (parse_pom, whichresolved
${prop}only in<version>), and the upstream restore.Fix
PomScopenow interpolatesgroupId/artifactIdfrom the root<properties>. That covers properties definedthrough other properties and the project model refs (
project.*,pom.*,project.parent.*, the parent's coordinates when inherited).Model refs win over same-named properties, as in Maven. The rewriter
pins the direct literal, VEX reads the real GA, and rollback finds the
pin it wrote.
declaration whose coordinate is a property the pom does not define (a
parent's) may be the patched GA, and then its own version wins. The
shared rule is
formats::maven::may_shadow. An unresolved reference actsas a wildcard, and the literal text around it must still match, so
${project.artifactId}-corenever shadowsslf4j-api.pom-type andclassifier declarations never count as the main jar.
redirect_maven_coordinate_unresolved(documented inCLI_CONTRACT.mdand
docs/ecosystems.md). A<profiles>declaration of that kind isreported as
redirect_maven_profile_dependency_unpatched, the same as aliteral one.
(
ga_versions), so the existing "Maven resolves …" check refuses thehosted pin. The vendored conflict check still attests a declaration at
the vendored version.
<dependencyManagement>pin that anearlier release added beside such a declaration (the Hosted Maven adds a dependencyManagement pin that the direct literal overrides when the dependency's groupId/artifactId is a ${property} or <exclusions> come first, so the build stays unpatched while scan reports redirected and VEX attests not_affected #683 bug itself) is
still recognised as the rewriter's own and is removed. The authored
check now counts suffixed declarations, not all versioned ones. Restore
also reads the pom scope once per pin instead of twice.
Per-issue checklist
groupId) and variant B (propertyartifactId), hosted:maven_pom_property_coordinates_are_the_direct_declaration<exclusions>first), hosted: same test(already fixed on
main; regression case)property_coordinates_are_the_declared_ga,undefined_coordinate_property_is_not_attested_past, and the vendoredcase in
vendored_ga_pinned_to_another_version_is_invalidmaven_pom_undefined_coordinate_property_refuses_the_dep,maven_pom_undefined_coordinate_property_in_a_profile_is_reportedproperty_coordinate_pin_round_trips,pre_683_managed_pin_beside_a_property_declaration_is_removedformats::maven::tests::coordinate_referencesTest evidence
Red→green: with the fix neutralised, all 5 initial regression tests fail
(
maven_pom_property_coordinates_are_the_direct_declaration,maven_pom_undefined_coordinate_property_refuses_the_dep,property_coordinate_pin_round_trips,property_coordinates_are_the_declared_ga,undefined_coordinate_property_is_not_attested_past), and with it theypass.
pre_683_managed_pin_beside_a_property_declaration_is_removedfails with the old authored-entry count and passes with the new one.
cargo fmt --all -- --check: clean.cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-core --all-features: 7523 passed, 4 failed.The 4 failures are permission-based tests that cannot fail as root
(uid 0 in this container) and are unrelated to Maven:
copy_tree::relax_loop_must_not_traverse_symlinked_root,vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry,pypi_poetry::wire_write_failure_maps_error_and_leaves_lock_untouchedand
pypi_requirements::wire_failure_rolls_back_already_written_files.The core integration suites (
redirect_goldenandupstream_restore_goldenamong them) passed 655/655.socket-patch-cli, a subset (not the whole crate: a fullcargo test --workspacefilled the container's disk):contract_gradle_codes,e2e_vex_redirect,e2e_mavenandcli_parse_vex: 1020 passed, 0 failed.in_process_redirect, run on an earlier revision: 149 passed,3 failed. The 3 are the same kind of write-failure tests that need a
non-root user.
Real Maven 3.9 (
--ignored):e2e_redirect_maven_buildande2e_vendor_maven_buildboth pass./code-review high: 10 findings. Nine are fixed in 026c536. One is notchanged:
dropped from discovery rather than kept as an unattested ref. This
matches how VEX already treats a pin shadowed by a literal direct
version (
managed_pin_shadowed_by_a_direct_plain_version_is_invalid):DIAG_REF_INVALID, with the ledger claim recognised as dead.Changing that is a broader VEX policy question than Hosted Maven adds a dependencyManagement pin that the direct literal overrides when the dependency's groupId/artifactId is a ${property} or <exclusions> come first, so the build stays unpatched while scan reports redirected and VEX attests not_affected #683.
Bugbot (026c536), both findings fixed in 453253e: a project coordinate
written through a property is interpolated, not inherited from the
parent, and `` is not read as the project's own
coordinates; an unresolved `` may still be `jar`. CI was green on
026c536 (82 checks).
Review (Tanmay182003): `.mvn/maven.config` `-D` user properties override pom
properties in Maven, but the coordinate lookup ignored them. Fixed in
09ac691: hosted, `vex` and restore read them over the pom's, using the
reader the vendored reactor already had (moved to `formats::maven`).
Tests: `maven_pom_coordinate_properties_read_maven_config_overrides`,
`coordinate_properties_read_maven_config_overrides`.
Follow-ups
None. The TypeScript twin in depscan cannot be reached from here. If
depscan's hosted Maven rewriter shares this matcher, it needs the same
property resolution.
https://claude.ai/code/session_011f9aeQkgxbNChxvpC4fAEF
Note
Medium Risk
Changes Maven hosted rewrite, VEX attestation, and rollback matching for property coordinates—build-critical lockfile/POM behavior—but stays fail-closed with broad regression tests rather than widening pins silently.
Overview
Fixes #683: hosted Maven treated dependencies whose
groupId/artifactIdused${…}as missing matches, added a<dependencyManagement>pin, and still reported redirect/VEX success while Maven built the unpatched jar from the direct declaration.Shared POM reading now interpolates coordinates from the pom’s
<properties>, project model refs (project.*, parent inheritance), and.mvn/maven.config-Doverrides (centralized informats::maven, reused by vendored reactor). Defined properties pin the literal dependency line; undefined parent-style placeholders are handled withmay_shadow/may_nameso the tool fails closed instead of pinning through a shadowing declaration.Hosted
scan --mode hostedskips writes and emitsredirect_maven_coordinate_unresolved(or profileredirect_maven_profile_dependency_unpatched) when an unresolved coordinate may be the GA. VEX discovery folds those shadow versions into GA precedence so pins are not attested past them. Rollback/upstream restore finds property-coordinate pins and removes legacy pre-fix<dependencyManagement>entries beside property literals.Contract/docs (
CLI_CONTRACT.md,docs/ecosystems.md) document the new refusal; extensive unit tests cover rewrite, VEX, rollback, andmaven.configoverrides.Reviewed by Cursor Bugbot for commit 09ac691. Configure here.
Generated by Claude Code