Skip to content

Hosted Maven rewriter edits commented-out, plugin and profile markup, so builds either stay unpatched or break #259

Description

[agent] Filed by Claude Code on behalf of Mikola Lysenko (@mikolalysenko) while adding Maven patch SBOM annotations to depscan. Repro artifacts were produced with real Maven and a stub patch API.

Summary

scan --mode hosted / get --mode hosted Maven rewriting (rewrite_maven_pom) finds its edit points with a bare regex and plain replacen. It does not skip:

  • XML comments
  • <profiles>
  • <build><plugins><plugin><dependencies>

The vendored backend already masks comments and profiles for its anchor (find_wireable_anchor). The hosted rewriter does not. For every shape below, the CLI exits 0 with redirect.redirected = 1 and no warning.

Impact

Two failure modes, both with a successful scan:

  • Silent fail-open. The real dependency still resolves the unpatched upstream jar from Central.
  • Broken build. The build fails because a suffixed version is unresolvable.

The CLI's own vex then refuses to attest the result (patched_ref_unattributable / redirect_unwired). So the scan envelope and the ledger disagree with VEX.

Repro

Setup:

  • CLI socket-patch 4.0.0 built from 3efdc31d.
  • A patch API stub that returns the standard maven2 grant for org.apache.commons:commons-lang3:3.12.0: mavenSuffixedVersion = 3.12.0-socket.4d5e6f70, patch uuid 4d5e6f70-8192-4a3b-9c4d-5e6f708192a3, and mavenPomSha256 set. This is the same shape as tests/fixtures/redirect/maven/pom/basic/overrides.json.
  • MAVEN_REPO_LOCAL holds the base pom so discovery finds it.
socket-patch scan --mode hosted --json --yes --cwd <proj> --api-url <stub> --org test-org --api-token fake
socket-patch vex --no-verify --product pkg:maven/com.example/[email protected] -O vex.json --cwd <proj> ...

For the build step, Maven 3.9.6 ran maven-dependency-plugin:3.6.1:copy-dependencies on a fresh local repository. It used a settings.xml mirror of socket-patch-<uuid> pointing at the stub, which serves the suffixed jar and pom. A control pom (a plain direct literal) resolves the patched jar in this setup.

case input pom what the rewriter did scan real Maven 3.9.6 vex
a commons-lang3 3.12.0 <dependency> inside an XML comment; the real dep is transitive via commons-text 1.10.0 Rewrote the commented-out <version> to 3.12.0-socket.4d5e6f70. Added no <dependencyManagement> pin, because versioned was non-empty. redirected=1, no warnings BUILD SUCCESS; commons-lang3-3.12.0.jar downloaded from Central, PRISTINE exit 1, patched_ref_unattributable
b <profiles><profile><repositories>… appears before any top-level <repositories>, plus a direct literal dep Inserted the Socket <repository> inside the inactive profile and suffixed the dep redirected=1 BUILD FAILURE: Could not find artifact …:3.12.0-socket.4d5e6f70 in central "<repository> is inside <profiles>"
c commons-lang3 3.12.0 as a <build><plugins><plugin><dependencies> entry (maven-antrun-plugin) Suffixed the plugin dependency. The Socket repo is not a <pluginRepository>. redirected=1 antrun:run BUILD FAILURE: plugin dependency 3.12.0-socket.4d5e6f70 not found unattributable
d a <profiles> <dependencyManagement><dependencies> precedes the top-level one; the dep is transitive Put the <dependencyManagement> pin inside the profile redirected=1, only redirect_maven_dep_management_added BUILD SUCCESS, PRISTINE 3.12.0 from Central "suffix … is inside <profiles>"
e a commented-out <repositories> block precedes the dependencies Inserted the Socket <repository> inside the comment redirected=1 the suffixed version is unresolvable, so the build fails unattributable

Diff for case a (the whole edit):

     <!-- pulled in by commons-text; was declared directly before:
     <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
-      <version>3.12.0</version>
+      <version>3.12.0-socket.4d5e6f70</version>
     </dependency>
     -->

These can be added as goldens under tests/fixtures/redirect/maven/pom/<case>/ next to basic, reusing basic/overrides.json.

Expected vs actual

  • Expected:
    • Every matcher and anchor ignores comments, <profiles> and <build>/<reporting>/<pluginManagement> subtrees. Those are the same scopes VEX discovery (vendor/maven_pom.rs) already ignores.
    • A dependency whose only occurrences are masked is treated as not declared, so it gets the transitive <dependencyManagement> pin at the top level.
    • A repository or pin is never placed inside a masked region.
    • If no safe anchor exists, the dep is refused with a warning instead of reported as redirected.
  • Actual: the rewrites above, exit 0, redirected: 1, and no warning.

CLI revision

3efdc31d (socket-patch 4.0.0).

Suggested fix

  • Reuse vendor/maven_repo.rs comment_spans / profiles_spans / find_outside (or the maven_pom.rs parser) in:
    • find_maven_dependency_matches
    • insert_maven_repository
    • insert_maven_dependency_management
  • Also mask <build> (plugins and pluginManagement) and <reporting>.
  • Keep the TS twin in depscan (workspaces/app/src/patches/registry-rewrite/maven-pom.ts) in sync.
  • Add goldens a–e.

File refs (at 3efdc31)

  • crates/socket-patch-core/src/patch/redirect/mod.rs:5860-5899 (MAVEN_DEPENDENCY_BLOCK_RE, find_maven_dependency_matches: every <dependency> block anywhere)
  • crates/socket-patch-core/src/patch/redirect/mod.rs:6268-6280 (insert_maven_repository: pom.contains("<repositories>") / replacen)
  • crates/socket-patch-core/src/patch/redirect/mod.rs:6284-6300 (insert_maven_dependency_management: first <dependencyManagement>\s*<dependencies> anywhere)
  • For contrast: crates/socket-patch-core/src/vendor/maven_repo.rs:968-1020 (build_repo_edit / find_wireable_anchor)
  • Confirmation by substring: crates/socket-patch-cli/src/commands/scan/hosted.rs:2413-2431 (see the separate issue on maven redirect confirmation)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions