Skip to content

Commit 7995df5

Browse files
committed
audit-ecosystems: E19 filed (#780, #781); new E58 (#782), E59 (#779)
Assisted-by: Claude Code:claude-opus-5-5
1 parent f465285 commit 7995df5

5 files changed

Lines changed: 46 additions & 10 deletions

File tree

‎doc/03-hosted.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
## Part 3: Hosted mode (redirect, hosted engine, upstream restore, Node addon)
44

5-
_Last checked against main @ 203e092 on 2026-10-02 by audit-ecosystems. Owner: `audit-ecosystems`._
5+
_Last checked against main @ 045d7ec on 2026-10-04 by audit-ecosystems (3.6 vlt dead helpers re-checked; the rest as of `203e092`). Owner: `audit-ecosystems`._
66

77
> Scope: `patch/redirect/**`, `hosted/**`, `crates/socket-patch-node/**`, CLI `scan/hosted.rs`, `scan/hosted/*`, `hosted_bundle.rs`.
88
@@ -163,7 +163,7 @@ For uv, pylock, poetry, pdm, hatch, vlt, maven and bun.lockb, the module's own f
163163

164164
| Feature | Prod LOC (approx.) | Notes |
165165
|---|---:|---|
166-
| vlt hosted | 2,454 + 1,707 tests | The warm-tree heal deletes `node_modules/.vlt` store entries: installed-tree surgery in a lockfile-only mode. vlt never redirects in memory. Contains dead ledger helpers. |
166+
| vlt hosted | 2,454 + 1,707 tests | The warm-tree heal deletes `node_modules/.vlt` store entries: installed-tree surgery in a lockfile-only mode. vlt never redirects in memory. Contains dead ledger helpers (`edit_dep_id`, `lock_node_ids`, `carried_pin_original`, `vlt_heal::ledger_targets`), orphaned when #277 removed the ledger merge. {{E58}} |
167167
| npm `allow-remote` auto-config | ~900 + 514 tests | `npmrc.rs` re-implements npm's `ini` tokenizer and its user/global/builtin/env config layering, all to decide whether to append one line to `.npmrc`. |
168168
| pnpm `trustLockfile` auto-config | ~450 | Heal-on-rerun, takeover previews, legacy and Rush special cases. Open issues #400, #401, #402 (quoted keys, flow style, duplicate keys) are all here. |
169169
| Parallel rewriter groups | ~260 + 451 equivalence tests | Parallelizes CPU work over a handful of texts that is already single-pass. Benchmark it, or delete it. |
@@ -202,6 +202,7 @@ For uv, pylock, poetry, pdm, hatch, vlt, maven and bun.lockb, the module's own f
202202
- {{E50}}: hosted `rewrite_nuget` and upstream restore rewrite every `packages.lock.json` entry of the patched id, in every target framework, whatever its `resolved` version; vendored `locked_at` only touches entries at the patched version. `packages.lock.json` has four walkers (hosted, restore, vendored, VEX).
203203
- {{E52}}: `vendor/go_sum_edit.rs` keeps free `upsert_module_lines` / `has_module_version` / `remove_exact_module_version_lines` with no production caller, re-implemented by the `GoSumEditor` the hosted Go rewriter uses; the free copies survive only as a test oracle, and the pure hosted codec lives in `vendor/`.
204204
- {{E57}}: the hosted cargo planner `plan_cargo_toml` is a line scanner, gated by a second `toml_edit` classifier of the same declarations. It refuses `serde = { version = "1", features = [⏎ "derive",⏎] }` as "inline table does not close on its line", although cargo and `toml_edit` accept it, so hosted skips a crate that vendored mode handles. Upstream restore unpins with a third, line-level grammar.
205+
- {{E58}}: the hosted-vlt ledger helpers `edit_dep_id`, `lock_node_ids`, `carried_pin_original` and `vlt_heal::ledger_targets` have no production caller since #277 deleted `rebase_vlt_edits` and the ledger heal; `UpstreamClient::seed_rubygems_sha256` is a test helper compiled into production.
205206

206207
---
207208
_Generated by [Claude Code](https://claude.ai/code)_

‎doc/05-vendored.md‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
## Part 5: Vendored mode and the non-JS backends
44

5-
_Last checked against main @ 045d7ec on 2026-10-04 by audit-ecosystems (5.4 Python, Cargo and Maven XML). Owner: audit-ecosystems._
5+
_Last checked against main @ 045d7ec on 2026-10-04 by audit-ecosystems (5.4 Python, Cargo, Maven XML, Gem and Go). Owner: audit-ecosystems._
66

77
> Scope: `vendor/` framework (`mod`, `common`, `state`, `verify`, `registry_fetch`, `service_fetch`, `prestage`, `reuse`, `redownload`, `ledger_snapshots`, `parse_memo`, `path`, `source`, `toml_surgery`, `lock_inventory`); backends for cargo, gem, pypi (×10 files), golang, composer, nuget, maven and `jvm/`; related `utils/` parsers; and the CLI `vendor.rs` + `vendored_backend/`.
88
@@ -141,9 +141,10 @@ Revert/restore/unwind code in the non-npm backends totals **about 3,540 lines**:
141141
- They have drifted, proven by execution: a BOM manifest is invisible to the crawler but read by VEX and `cargo_tag`; `[project]` and dotted keys are read only by `cargo_tag`; `[package] junk` (invalid TOML) is accepted only by the crawler. {{E15}}
142142
- Hosted mode plans the dependency pin itself with a line scanner (`plan_cargo_toml`, six regexes), then re-checks it with a second, `toml_edit` classifier (`validate_cargo_toml_pins`). `CargoRegistryPins`, a `#[cfg(test)]` oracle and upstream restore's `unpin_line` are three more line-level readers of the same declarations. Vendored edits only through `toml_edit`. The scanner refuses an inline table whose `features` array spans lines, which is valid TOML and accepted by cargo, so hosted skips a crate that vendors fine. {{E57}}
143143

144-
**Gem:** `vendor/gem.rs` imports three token helpers from `formats::gem` and keeps its own section model. `formats/gem` itself has two section models, and there are two DEPENDENCIES-name parsers with different rules.
144+
**Gem:** `vendor/gem.rs` imports three token helpers from `formats::gem` and keeps its own section model (`section_span` / `section_end`, which take the *first* line equal to a header). With `formats::gem::parse` and hosted's `GemLockSection` that makes three section models and three DEPENDENCIES-name parsers; the name rules agree on Bundler-written entries. {{E19}}
145+
- The section models have drifted, proven by execution: Bundler 2 writes one `GEM` section per source, and vendored `edit_lock` looks only in the first, so a gem from any later source (rubygems.org, when a private source sorts first) is refused with "GEM specs has no entry", while hosted and the shared parser handle it. {{E59}}
145146

146-
**Go:** `go_mod_edit.rs` is properly shared (9 users) but lives under `vendor/`. `crawlers/go_crawler.rs:63` still has its own `parse_go_mod_module`.
147+
**Go:** `go_mod_edit.rs` is properly shared (9 users) but lives under `vendor/`. `crawlers/go_crawler.rs:63` still has its own `parse_go_mod_module`, which has no production caller; the live `module` reader is `vex/product.rs`'s own, and both misread Go's block form `module ( … )` as the module `(`. {{E19}}
147148

148149
**Small helpers:**
149150
- **CRLF:** four policies for the same "`toml_edit` emits LF" problem:
@@ -249,6 +250,8 @@ Old `kind`s are translated into `SpliceRecord`s when the ledger loads, so legacy
249250

250251
### New findings since the review
251252

253+
- {{E59}}: vendored gem `edit_lock` searches only the first `GEM` section of `Gemfile.lock`. Bundler 2 writes one per source, so in a project with a private source that sorts first, every rubygems.org gem is refused with "GEM specs has no entry"; see 5.4.
254+
- {{E58}}: production `pub fn`s with no production caller, orphaned by #277: `VendorEntry::committed_artifact_intact` and `go_sum_edit::remove_lines` (no reference at all), plus test-only helpers compiled into production (`cargo_tag::copy_manifest_tag`, `jvm::apply::read_project_file`). The hosted-vlt half is in Part 3.
252255
- {{E55}}: vendored Maven decides "is this a reactor?" twice. `jvm::detect` uses the reactor's `Doc`-based `declares_modules`, which ignores plugin `<configuration><modules>`, then the legacy single-pom path re-checks with its own comment-stripping `declares_modules` and refuses `vendor_maven_multimodule_unsupported`. That refusal fires only on the disagreement, so every `maven-ear-plugin` project is refused; see 5.4.
253256
- {{E54}}: the Poetry and PDM lock rewriters restore line endings with different rules, so a mixed-line-ending lock's edited unit becomes CRLF under Poetry and LF under PDM; see 5.4.
254257
- {{E49}}: hosted Pipenv used to reject its own pins on path-prefixed `--patch-server-url` origins and sdists. Both private grammars (`owned_url`'s segment count, `is_socket_hosted_reference`) are deleted; Pipenv now uses `hosted_pypi_reference` (#572); see 5.4.

‎doc/06-discovery-vex.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
## Part 6: Discovery, inventory and VEX
44

5-
_Last checked against main @ 045d7ec on 2026-10-04 by audit-ecosystems (gem lock selection re-checked). Owner: `audit-ecosystems`._
5+
_Last checked against main @ 045d7ec on 2026-10-04 by audit-ecosystems (gem lock selection and the go.mod row re-checked). Owner: `audit-ecosystems`._
66

77
> Scope: `vex/**` (incl. `vex/discover/*`), `crawlers/**`, `formats/**`, `vendor/lock_inventory/*`, and the CLI consumers `vex.rs`, `vex_sources.rs`, `vex_consumed.rs`, `scan/discovery.rs`, `context.rs`, `list.rs`, `ecosystem_dispatch.rs`.
88
@@ -68,7 +68,7 @@ From that model:
6868
| package-lock | `lock_inventory::npm_lock_nodes` | vendored `scan_lock_matches`, hosted `mod.rs:837`, upstream `npm_lock_hits` |
6969
| Pipfile.lock | `lock_inventory::pypi::pipfile_lock_entries` | vendored `pypi_pipenv.rs` (×3), hosted `redirect/pipenv.rs:98`; the crawler re-implements Pipenv venv hashing |
7070
| Cargo.toml | — | hand-rolled **twice** (`cargo_crawler.rs:21`, `vex/product.rs:167/380`) despite `toml_edit` |
71-
| go.mod | `go_mod_edit` | `module` directive parsed again at `go_crawler.rs:63` and `product.rs:175` |
71+
| go.mod | `go_mod_edit` | `module` directive parsed again at `product.rs:175` and in `go_crawler.rs:63` (no production caller); both misread the block form `module ( … )` {{E19}} |
7272
| NuGet | `formats::nuget::parse_open_tag` | vendored has its own XML scanner. The crawler reads `obj/project.assets.json` **only for `packageFolders`**, never `libraries`/`targets`, then enumerates the global `~/.nuget/packages` |
7373
| Maven | `formats::maven::parse_pom` | vendored `jvm/maven_reactor.rs` `Doc::parse` and `gradle.rs`; hosted's own tag scanner; the crawler's own XML parser; `product.rs` again |
7474

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[agent] 2026-10-04: architecture audit (ecosystems and formats)
2+
3+
**main @ `045d7ec`**, unchanged since the last run. There were no new maintainer replies in the discussion and no handovers for this routine.
4+
5+
**Reconciled.** No status changed: E01 (#597), E02/E03 (#574), E06 (#602), E09/E51 (#657), E13/E54 (#703) and E56 (#750) are still in their PRs, and nothing in this area merged. Because main did not move, no open issue needed re-checking.
6+
7+
**Verified and filed: E19** (gem and Go parsers), split into two refactors:
8+
- **[#780](https://github.com/SocketDev/socket-patch/issues/780)** (pm:bundler): `Gemfile.lock` has three section models (`formats::gem::parse`, hosted's `GemLockSection`, vendored's `section_span` / `section_end`) and three DEPENDENCIES-name rules, not two. Target: both writers splice through the shared parse, deleting the copies. Sequenced after PRs #768 and #776.
9+
- **[#781](https://github.com/SocketDev/socket-patch/issues/781)** (pm:go): `go_crawler::parse_go_mod_module` has no production caller; the live reader is `vex/product.rs`'s own. A unit probe, run twice, shows both read Go's block form `module (⏎\texample.com/blk⏎)` (accepted by `go 1.24.7 list -m`) as `(`, so `--product` becomes `pkg:golang/(`. Target: one `go_mod_edit::module_path` on the shared directive walker.
10+
11+
**New findings:**
12+
- **E59, bug, proved by execution: [#779](https://github.com/SocketDev/socket-patch/issues/779)** (pm:bundler). Vendored gem `edit_lock` looks for the spec only in the first `GEM` section. I generated a real lock with Bundler 4.0.17 for a Gemfile with rubygems.org plus a second (`file://`) source. Bundler sorted the private source first, so `rack` sits in the second `GEM` section. A unit probe on that lock, run twice: vendored refuses with "GEM specs has no entry `rack (2.2.8)`"; the swapped-order control succeeds; `formats::gem::parse().entries()` lists rack; hosted `converge_gem_lock_source` pins it. So every public gem is unvendorable in a project whose private gem source sorts before rubygems.org.
13+
- **E58, refactor: [#782](https://github.com/SocketDev/socket-patch/issues/782).** I swept every `pub`/`pub(crate)` item in scope for references outside `#[cfg(test)]` code. Production helpers orphaned by #277: `VendorEntry::committed_artifact_intact` and `go_sum_edit::remove_lines` (no reference anywhere; #631 would have moved the latter), the hosted-vlt ledger helpers `edit_dep_id` / `lock_node_ids` / `carried_pin_original` / `vlt_heal::ledger_targets` (the review's "dead vlt ledger helpers", E34), and three test-only helpers compiled into production. `git log -S` on deepened history confirms #277 removed their callers (`rebase_vlt_edits`, `ledger_covers`, the rollback/vendor heal).
14+
15+
**Searched without filing:**
16+
- Go "which version is live" (inventory reads every go.sum zip line; hosted refuses a go.mod require mismatch; VEX uses go.mod `require`): already covered by #392 and #509, so not filed.
17+
- Gem default-remote rule (`[] → rubygems.org` in `entries()` and `recover.rs`, two spellings of the URL constant): trivial drift only. `same_remote` is shared.
18+
- Composer reinstall hints (`composer_hints.rs`) walk `composer.lock` with their own vendored-dist rule. It is advisory output only, so not filed.
19+
- NuGet hostname constants: inside E11.
20+
21+
**False positives ruled out:**
22+
- A backquoted module path is rejected by `go` itself ("invalid quoted string"), and so is a BOM go.mod, so neither is a drift case.
23+
- `registry_fetch` `validate_*` and `reuse::prior_entry_reloading` are `#[cfg(test)]` oracles (E35), not dead production code.
24+
25+
**Living document:** Part 5's Gem and Go bullets are rewritten with {{E19}} and {{E59}}, E58/E59 are added under new findings, and the check line now covers Gem and Go. Part 3's vlt row names the dead helpers with {{E58}}, a new-findings bullet is added, and the check line is refreshed (scoped). Part 6's go.mod row is corrected and its check line extended. The register gains E58 and E59; E19 is filed; E34 notes #782.
26+
27+
**Next backlog rows:** E16 (CRLF policies), E08 (yarn grammars; after #657), E14 (Pipfile.lock, still unproven), E18 (JS helper copies), E28 (dead vendored scaffolding; fold in anything #782 leaves).
28+
29+
---
30+
_Generated by [Claude Code](https://claude.ai/code)_

‎register/10-audit-ecosystems.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
### Ecosystems and formats (`audit-ecosystems`)
2-
_Last updated 2026-10-04T07:05Z · main @ 045d7ec_
2+
_Last updated 2026-10-04T13:01Z · main @ 045d7ec_
33

44
| ID | P | Problem | Source | Issues | Status |
55
|---|:-:|---|---|---|---|
@@ -21,7 +21,7 @@ _Last updated 2026-10-04T07:05Z · main @ 045d7ec_
2121
| E16 | 2 | CRLF has five policies in the npm family and three for `toml_edit` output, and `common::detect_eol` contradicts `LineEndings::Mixed`. Target: one line-ending policy. | 4.4; 5.4; 7.3 | | to verify |
2222
| E17 | 2 | "Is a bun lock present" is asked at seven sites with three semantics (lstat, `exists`, `is_file`). With a dangling `bun.lock` symlink, Bun and the writers use `bun.lockb`, but the inventory returns nothing. | 4.4 | #735 | filed #735 |
2323
| E18 | 3 | JS helper copies: JSON-pointer escape ×2, wiring lines↔JSON ×3, `name@spec` split ×2, `KIND_*` re-spelled as literals, uneven recursion bounds, and regexes compiled inside per-dependency loops. | 4.4 | | to verify |
24-
| E19 | 3 | Gem has three section models and two DEPENDENCIES-name parsers with different rules. Go's `go_mod_edit.rs` lives in `vendor/`, and `go_crawler.rs` has its own `parse_go_mod_module`. | 5.4 | | to verify |
24+
| E19 | 3 | Gem has three section models and three DEPENDENCIES-name parsers (vendored sees only the first `GEM` section, so #779). Go: `go_crawler::parse_go_mod_module` has no production caller; `vex/product.rs` has its own `module` reader that misreads the block form; `go_mod_edit.rs` lives in `vendor/`. | 5.4 | #780, #781 | filed #780, #781; gem models (#780), go.mod `module` reader (#781) |
2525
| E20 | 3 | Pure codecs (`bun_lockb.rs`, `bun_lock_text.rs`, `vlt_lock_text.rs`) and the neutral types (`Edit`, `Warning`, `LockfileEntry`) live outside `formats/`, which creates `formats`↔`vendor`/`redirect`/`vex` cycles. | 2.1; 4.5 #2; 4.7 J | | to verify |
2626
| E21 | 2 | Tracking: `VendorBackend` trait + registry. The ecosystem list is enumerated at 16 production sites, and the `vend!` / `vend_installed!` macros stand in for the trait. | 2.1; 5.2; 5.8 | | to verify |
2727
| E22 | 2 | The JS vendor driver skeleton is copied eight times (`guard_coordinates` → … → a literal `VendorEntry`). Target: one generic driver + `NpmLockBackend`. | 4.4; 4.7 C | | to verify |
@@ -36,7 +36,7 @@ _Last updated 2026-10-04T07:05Z · main @ 045d7ec_
3636
| E31 | 2 | Tracking: `trait HostedRewriter` + `Outcome { per_dep }`. It replaces the 20 uuid sets in `RewriteResult`, `merge_group_delta`, the 16-rule `confirm()` and eight parallel tables. | 2.1; 3.7 #2 | | to verify |
3737
| E32 | 2 | There are two hosted orchestrators, disk (`run_redirect_selected`) and in-memory (`hosted/memory`), kept equal by parity tests. Target: one pipeline. Depends on E44. | 3.3; 3.7 #4 | | to verify |
3838
| E33 | 3 | Upstream restore rebuilds originals from the network (~7.4K lines, ignores mirrors, 13 open bugs). Target: an originals sidecar or a narrowed restore. Depends on E45. | 2.3; 3.5 | | to verify |
39-
| E34 | 3 | Per-PM auto-config costs more than it's worth: npm `allow-remote` (~900 lines re-implementing npm config), pnpm `trustLockfile`, the vlt warm-tree heal, and the unbenchmarked parallel rewriter groups. | 3.6; 3.7 #7 | | to verify |
39+
| E34 | 3 | Per-PM auto-config costs more than it's worth: npm `allow-remote` (~900 lines re-implementing npm config), pnpm `trustLockfile`, the vlt warm-tree heal, and the unbenchmarked parallel rewriter groups. | 3.6; 3.7 #7 | #782 | to verify; dead vlt ledger helpers in #782 (E58) |
4040
| E35 | 3 | Retire the refactor oracles: the redirect equivalence suites and 252 KB of goldens, the crawler oracles (3K lines), and the telescoping entry points (use one `RewriteOptions`). | 3.7 #9; 6.6 | | to verify |
4141
| E36 | 2 | Tracking: one `Inventory`. Today's four discovery systems are merged by fabricating `CrawledPackage`s with fake `node_modules/<name>` paths. Rename `vex::discover` (it is the hosted-state store). | 2.1; 6.2; 6.7 | | to verify |
4242
| E37 | 2 | `is_safe_{cargo,gem,nuget}_coordinate` are byte-identical and duplicate `simple_purl`'s check. `composer_crawler::normalize_version` duplicates `strip_leading_v`. | 6.4 | #630 | filed #630 |
@@ -60,6 +60,8 @@ _Last updated 2026-10-04T07:05Z · main @ 045d7ec_
6060
| E55 | 2 | Vendored Maven has two `declares_modules`: `jvm::detect` (reactor `Doc`, ignores plugin `<configuration><modules>`) routes an EAR pom to the legacy path, whose comment-stripping copy then refuses it as `vendor_maven_multimodule_unsupported`. The legacy refusal fires only on that disagreement. | new finding | #716 | filed #716 |
6161
| E56 | 2 | Lock inventory reads only `Gemfile.lock` and VEX discovery reads both locks, while hosted/vendored/crawler use `LoadedManifest::pair`: a `gems.rb` project's `gems.locked` is invisible to the inventory (in-memory hosted, scan supplement, VEX liveness), and a stale `Gemfile.lock` twin is read instead. | new finding | #736 | in PR #750 |
6262
| E57 | 2 | Hosted `plan_cargo_toml` is a line scanner gated by a second `toml_edit` classifier (`validate_cargo_toml_pins`), beside three more line-level readers (`CargoRegistryPins`, a test oracle, restore's `unpin_line`). It refuses a valid inline table whose `features` array spans lines, so hosted skips a crate that vendors fine. | new finding | #757 | filed #757 |
63+
| E58 | 3 | Production `pub fn`s with no production caller, orphaned by #277: `VendorEntry::committed_artifact_intact` and `go_sum_edit::remove_lines` (no reference at all), the hosted-vlt ledger helpers `edit_dep_id` / `lock_node_ids` / `carried_pin_original` / `vlt_heal::ledger_targets`, plus three test-only helpers compiled into production. | new finding; 3.6 | #782 | filed #782 |
64+
| E59 | 2 | Vendored gem `edit_lock` finds the spec only in the first `GEM` section (`section_span(…, "GEM")`); Bundler 2 writes one per source, so a gem from any later source is refused with "GEM specs has no entry". Hosted and the shared parser read every section. | new finding | #779 | filed #779 |
6365

6466
**Handed off:** none yet.
6567

0 commit comments

Comments
 (0)