[agent] Found by the scheduled Maven bug-hunt routine (ledger #318).
Summary
The hosted rewriter (scan --mode hosted) and the vendored wiring (vendor) each look for an existing section by an exact text pattern. When that pattern doesn't match, they write a brand-new section before </project>, even though the pom already has one. Maven's pom reader rejects the result with Non-parseable POM … Duplicated tag, so nothing builds. Meanwhile socket-patch exits 0, reports redirected: 1 / applied: 1 with no warning, and vex attests not_affected.
Three ordinary pom shapes trigger it:
| shape |
mode |
why the anchor is missed |
result |
<repositories/> (self-closed, empty) |
hosted |
insert_maven_repository checks pom.contains("<repositories>") |
a second <repositories> before </project> |
<repositories/> |
vendored |
build_repo_edit anchors on </repositories> |
a second <repositories> |
<dependencyManagement> with an XML comment before <dependencies> (e.g. <!-- versions shared across the org -->), and the patched GA is transitive |
hosted |
the regex (?s)<dependencyManagement>\s*<dependencies> allows only whitespace between the tags |
a second <dependencyManagement> |
<dependencyManagement/>, patched GA transitive |
hosted |
same regex |
a second <dependencyManagement> |
This is a different mechanism from #259, where edits land inside comments or profiles. Here the anchor is missed entirely and a duplicate top-level element is created. Masking comments, as #259 suggests, would not fix the self-closed shapes, and would only fix the comment shape if the regex is also changed.
Impact
- The build is broken on every Maven line (3.6.3 → 4.0.0-rc-7) right after a successful
scan / vendor.
- The CLI's JSON and
vex both claim the patch is in effect: vex --no-verify emits not_affected for the hosted case, and vex --offline does the same for the vendored case.
Repro
Setup: socket-patch 4.0.0 built from main f6b7fb9, and real Apache Maven. For hosted, a local stub API serves the same grant, patched jar and served pom as crates/socket-patch-cli/tests/e2e_redirect_maven_build.rs (commons-text 1.10.0 → 1.10.0-socket.4d5e6f70), and a settings.xml mirror maps socket-patch-<uuid> onto the stub. For vendored, a hand-staged .socket/manifest.json + blob is used, as in e2e_vendor_maven_build.rs.
Hosted, comment inside <dependencyManagement> (commons-text arrives transitively via commons-configuration2 2.9.0):
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId><artifactId>app</artifactId><version>1.0.0</version>
<dependencyManagement>
<!-- versions shared across the org -->
<dependencies>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-configuration2</artifactId><version>2.9.0</version></dependency>
</dependencies>
</project>
$ socket-patch scan --mode hosted --json --yes --cwd . --api-url http://127.0.0.1:8765 --org test-org --api-token fake
exit 0, redirect.redirected = 1, warnings: [redirect_maven_dep_management_added]
# pom.xml now has a SECOND <dependencyManagement> (holding commons-text 1.10.0-socket.4d5e6f70) after </dependencies>
$ socket-patch vex --no-verify --product pkg:maven/com.example/app@1.0.0 -O vex.json ...
exit 0, not_affected for pkg:maven/org.apache.commons/commons-text@1.10.0
$ mvn -B -s settings.xml org.apache.maven.plugins:maven-dependency-plugin:3.1.2:copy-dependencies
[ERROR] Non-parseable POM /…/pom.xml: Duplicated tag: 'dependencyManagement' (position: START_TAG seen ...</dependencies>\n <dependencyManagement>... @21:25)
exit 1
Self-closed repositories, hosted or vendored (a direct commons-text:1.10.0 dependency):
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId><artifactId>app</artifactId><version>1.0.0</version>
<repositories/>
<dependencies>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-text</artifactId><version>1.10.0</version></dependency>
</dependencies>
</project>
$ socket-patch scan --mode hosted ... # or: socket-patch vendor --json --offline
exit 0, redirected = 1 (applied = 1), no warnings
$ mvn ... copy-dependencies
[ERROR] Non-parseable POM /…/pom.xml: Duplicated tag: 'repositories' (position: START_TAG seen ...</dependencies>\n <repositories>... @12:17)
Control: the same poms without the self-closed tag or the comment are rewritten in place and resolve the patched jar (PATCHED commons-text-1.10.0-socket.4d5e6f70.jar, and for vendored PATCHED commons-text-1.10.0.jar).
Expected vs actual
- Expected: the rewrite leaves a pom Maven can read. CLI_CONTRACT.md / docs/ecosystems.md describe hosted Maven as "fail-closed" by pinning the suffixed version, and vendored as a committed
file:// repository wired into the project pom. If the tool can't find a safe anchor, it should expand the self-closed element, or refuse with a warning instead of reporting redirected / applied.
- Actual: a duplicate top-level element, exit 0, a positive VEX, and a build Maven won't load.
Matrix (Linux, JDK 21; each cell run twice on fresh copies)
| case |
Maven 3.6.3 |
3.8.8 |
3.9.11 |
4.0.0-rc-7 |
hosted, <repositories/> |
Duplicated tag |
Duplicated tag |
Duplicated tag |
Duplicated tag |
hosted, comment in <dependencyManagement> |
Duplicated tag |
Duplicated tag |
Duplicated tag |
Duplicated tag |
hosted, <dependencyManagement/> |
Duplicated tag |
Duplicated tag |
Duplicated tag |
Duplicated tag |
vendored, <repositories/> |
Duplicated tag |
Duplicated tag |
Duplicated tag |
Duplicated tag |
| controls (hosted direct / transitive, vendored plain) |
— |
— |
PATCHED |
PATCHED |
macOS and Windows weren't probed. The rewrite is pure text, so it doesn't depend on the OS.
Suspect code (main f6b7fb9)
crates/socket-patch-core/src/patch/redirect/mod.rs:7007: insert_maven_repository uses pom.contains("<repositories>"), else a new section before </project> (line 7011).
crates/socket-patch-core/src/patch/redirect/mod.rs:7028: the insert_maven_dependency_management regex (?s)<dependencyManagement>\s*<dependencies>, else a new section (line 7037).
crates/socket-patch-core/src/vendor/maven_repo.rs:1115: build_repo_edit anchors only on </repositories>, then falls back to a new section before </project> (line 1117).
Related, but a different mechanism: #259 (edits landing in comments/profiles/plugins) and #260 (redirect confirmed by substring, which is why vex accepts these poms).
[agent] Found by the scheduled Maven bug-hunt routine (ledger #318).
Summary
The hosted rewriter (
scan --mode hosted) and the vendored wiring (vendor) each look for an existing section by an exact text pattern. When that pattern doesn't match, they write a brand-new section before</project>, even though the pom already has one. Maven's pom reader rejects the result withNon-parseable POM … Duplicated tag, so nothing builds. Meanwhile socket-patch exits 0, reportsredirected: 1/applied: 1with no warning, andvexattestsnot_affected.Three ordinary pom shapes trigger it:
<repositories/>(self-closed, empty)insert_maven_repositorycheckspom.contains("<repositories>")<repositories>before</project><repositories/>build_repo_editanchors on</repositories><repositories><dependencyManagement>with an XML comment before<dependencies>(e.g.<!-- versions shared across the org -->), and the patched GA is transitive(?s)<dependencyManagement>\s*<dependencies>allows only whitespace between the tags<dependencyManagement><dependencyManagement/>, patched GA transitive<dependencyManagement>This is a different mechanism from #259, where edits land inside comments or profiles. Here the anchor is missed entirely and a duplicate top-level element is created. Masking comments, as #259 suggests, would not fix the self-closed shapes, and would only fix the comment shape if the regex is also changed.
Impact
scan/vendor.vexboth claim the patch is in effect:vex --no-verifyemitsnot_affectedfor the hosted case, andvex --offlinedoes the same for the vendored case.Repro
Setup:
socket-patch 4.0.0built from mainf6b7fb9, and real Apache Maven. For hosted, a local stub API serves the same grant, patched jar and served pom ascrates/socket-patch-cli/tests/e2e_redirect_maven_build.rs(commons-text 1.10.0 →1.10.0-socket.4d5e6f70), and asettings.xmlmirror mapssocket-patch-<uuid>onto the stub. For vendored, a hand-staged.socket/manifest.json+ blob is used, as ine2e_vendor_maven_build.rs.Hosted, comment inside
<dependencyManagement>(commons-text arrives transitively via commons-configuration2 2.9.0):Self-closed repositories, hosted or vendored (a direct
commons-text:1.10.0dependency):Control: the same poms without the self-closed tag or the comment are rewritten in place and resolve the patched jar (
PATCHED commons-text-1.10.0-socket.4d5e6f70.jar, and for vendoredPATCHED commons-text-1.10.0.jar).Expected vs actual
file://repository wired into the project pom. If the tool can't find a safe anchor, it should expand the self-closed element, or refuse with a warning instead of reportingredirected/applied.Matrix (Linux, JDK 21; each cell run twice on fresh copies)
<repositories/><dependencyManagement><dependencyManagement/><repositories/>macOS and Windows weren't probed. The rewrite is pure text, so it doesn't depend on the OS.
Suspect code (main
f6b7fb9)crates/socket-patch-core/src/patch/redirect/mod.rs:7007:insert_maven_repositoryusespom.contains("<repositories>"), else a new section before</project>(line 7011).crates/socket-patch-core/src/patch/redirect/mod.rs:7028: theinsert_maven_dependency_managementregex(?s)<dependencyManagement>\s*<dependencies>, else a new section (line 7037).crates/socket-patch-core/src/vendor/maven_repo.rs:1115:build_repo_editanchors only on</repositories>, then falls back to a new section before</project>(line 1117).Related, but a different mechanism: #259 (edits landing in comments/profiles/plugins) and #260 (redirect confirmed by substring, which is why
vexaccepts these poms).