Skip to content

Commit 8d469ba

Browse files
committed
audit-ecosystems: file E23 (#937), new finding E66 (#936)
Assisted-by: Claude Code:claude-opus-5-5
1 parent 2bb9671 commit 8d469ba

3 files changed

Lines changed: 57 additions & 3 deletions

File tree

‎doc/05-vendored.md‎

Lines changed: 5 additions & 1 deletion
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 @ 9c43dfc on 2026-10-06 by audit-ecosystems (5.2 dead `force`/`sources` parameters re-checked at `9c43dfc`; per-backend service-copy and cleanup copies re-checked at `9c43dfc`; 5.4 NuGet, Poetry/PDM and Gem re-checked at `4646693`; as of `045d7ec`: 5.4 Python, Cargo, Maven XML, Gem, Go and CRLF helpers; 5.6 scaffolding; the vendored-reference scan behind repair and the orphan sweeps). Owner: audit-ecosystems._
5+
_Last checked against main @ 9c43dfc on 2026-10-06 by audit-ecosystems (5.4 Poetry/PDM/Pipenv backend skeleton and Poetry forward splicers re-checked at `9c43dfc`; 5.2 dead `force`/`sources` parameters re-checked at `9c43dfc`; per-backend service-copy and cleanup copies re-checked at `9c43dfc`; 5.4 NuGet, Poetry/PDM and Gem re-checked at `4646693`; as of `045d7ec`: 5.4 Python, Cargo, Maven XML, Gem, Go and CRLF helpers; 5.6 scaffolding; the vendored-reference scan behind repair and the orphan sweeps). 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
@@ -130,6 +130,9 @@ Revert/restore/unwind code in the non-npm backends totals **about 3,540 lines**:
130130
- `check_target_guards` (missing / forked / ours-in-sync / ours-stale / user-authored)
131131
- `wire_*`
132132
- `revert_*`
133+
134+
The wire and revert envelope around each format edit is identical in all three, verified on `9c43dfc`: symlink refusal → guards → a defensive `InSync` refusal → edit → `ensure_unchanged` → memo invalidate → mode-preserving write. Each also has its own `{Fresh, InSync}` enum. Target: one shared envelope with flavor-derived error codes. {{E23}}
135+
- Vendored Poetry has **two forward splicers**. Legacy and CRLF locks go through the shared `utils::poetry_lock` engine; LF 2.x locks go through a private `toml_surgery` line scanner (`rewrite_target_package_unit`). The scanner writes a different `files` shape and skips the engine's wheel-name and lowercase-digest gates (executed twice). {{E66}}
133136
- Pipfile.lock is read through one shared parser but **written two ways**: vendored reserializes canonically, hosted splices spans.
134137
- Hosted-URL recognition for Pipenv is shared: hosted `owned_url` and the vendored Pipenv guard both ask `lock_inventory::pypi::hosted_pypi_reference`, which applies `hosted_patch_uuid`'s origin allowlist to `hosted_artifact_url`'s tail grammar; the vendored guard gets the run's `--patch-server-url` origin (#572). {{E04}}
135138

@@ -247,6 +250,7 @@ Old `kind`s are translated into `SpliceRecord`s when the ledger loads, so legacy
247250

248251
### New findings since the review
249252

253+
- {{E66}}: vendored Poetry wires a 2.x lock through the `toml_edit` engine when it is CRLF and through a `toml_surgery` line scanner when it is LF. For the same lock the two give different `files` shapes, and only the engine checks the wheel name and lowercases the digest (executed twice); see 5.4.
250254
- {{E65}}: `vendor --force` documents a missing-file tolerance and a `vendor_content_mismatch_overwritten` warning that no backend implements; every acquisition sink takes `_force`/`_sources`, and `vendor` with and without `--force` behave the same (executed twice). Bears on #615; see 5.2.
251255
- {{E61}}: the vendored-reference scan behind `repair`, the `vendor` stranded-reference gate and the orphan sweeps never sees NuGet or Maven wiring. `nuget.config` and `pom.xml` lack the `VENDORED` registry role, and both backends reference the bare uuid directory, which `parse_vendor_path` rejects (it needs a leaf). So with a missing ledger entry, `vendor --revert` and the vendored gc delete a feed or repository that `nuget.config` / `pom.xml` still name (proven by execution). The `eco == "maven2"` arm of the stranded-reference gate is dead.
252256
- {{E59}}: vendored gem `edit_lock` searched only the first `GEM` section of `Gemfile.lock`, so a gem from a later source was refused; fixed by #805; see 5.4.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
[agent] 2026-10-06: architecture audit (ecosystems and formats)
2+
3+
**main @ `9c43dfc`**, unchanged since the last run. There were no new maintainer replies in the discussion and no handovers for this routine.
4+
5+
**Reconciled.**
6+
- No status changed: E09/E51 are still in #657 and E64 is still in #909. No open PR references my other issues, except #927, which only cites #883.
7+
- With `main` unchanged, re-checking open issues would only repeat last run's permalinks, so I skipped it.
8+
9+
**Verified and filed: E23 → [#937](https://github.com/SocketDev/socket-patch/issues/937)** (refactor).
10+
- `pypi_poetry.rs`, `pypi_pdm.rs` and `pypi_pipenv.rs` each wrap their format edit in the same envelope:
11+
- symlink refusal;
12+
- guards;
13+
- a defensive `InSync` refusal (the message is spelled three times);
14+
- `ensure_unchanged`;
15+
- memo invalidation;
16+
- a mode-preserving write mapped to `pypi_<flavor>_write_failed`.
17+
- Each revert opens with the same `kept_artifact: true` symlink prelude, and each backend has its own `{Fresh, InSync}` enum.
18+
- No drift is proven in the envelope. The issue proposes one shared module with flavor-derived codes (byte-identical strings), about −150 / +80 production lines.
19+
20+
**New finding: E66, [#936](https://github.com/SocketDev/socket-patch/issues/936)** (refactor, `pm:poetry`). `wire_poetry` picks its forward splicer by line ending:
21+
- legacy and CRLF locks go through the shared `utils::poetry_lock` engine, which hosted mode uses too;
22+
- LF 2.x locks go through the private `toml_surgery` line scanner, `rewrite_target_package_unit`.
23+
24+
**Proof:** a throwaway test, run twice on `9c43dfc`, wired each of the three 2.x fixtures as LF and as CRLF.
25+
- The outputs differ every time. LF writes Poetry's multi-line `files = [\n {file = …},\n]`; CRLF writes the inline `files = [{ file = … }]`.
26+
- Wheel `evil-9.9-py3-none-any.whl` wires on LF but is refused on CRLF.
27+
- An uppercase digest is written uppercase on LF and lowercase on CRLF. The engine's comment says an uppercase digest would fail every install.
28+
- The last two gates are latent with today's orchestrator inputs.
29+
30+
The target is for the engine to emit Poetry's multi-line shape, which also aligns hosted output. The LF branch, `replace_files_array`, `package_unit_lines` and `unit_has_canon_name` would be deleted.
31+
32+
**Searched without filing:**
33+
- PDM reverts non-atomically, while Poetry uses `revert_lock_fragment_splice_atomic`. This is documented, because PDM records a single fragment per unit, so it is not drift.
34+
- Only PDM has the partial-relock patched-hash guard (`target_carries_patched_wheel_hash`). I couldn't show that Poetry can reach the same state, so I didn't claim it.
35+
- requirements, pylock and Hatch don't call `ensure_unchanged`. requirements re-reads its files at wire time, and pylock and Hatch have their own compare-before-write (`pypi_lock_changed`, "Hatch configuration changed"). So none of them lacks the race guard.
36+
- Duplicate check for #936: #694 and #703 covered the utils engines only. Open PR #877 touches `utils/poetry_lock.rs` for parse reuse and not the vendored line scanner.
37+
38+
**False positives ruled out:**
39+
- The wheel-name and uppercase-digest gate gap is not a live bug today. The orchestrator always passes a wheel it built for that package and a lowercase sha. It is recorded as drift, not filed as a bug.
40+
41+
**Living document:**
42+
- Part 5 §5.4 Python: the skeleton bullet now describes the shared envelope with {{E23}}, and a new two-splicers bullet has {{E66}}.
43+
- Part 5: a new-findings bullet for {{E66}}; the check line is updated.
44+
- The register files E23 and adds E66.
45+
46+
**Next backlog rows:** E08 (yarn grammars; after #657), E21 (`VendorBackend` tracking; count `Ecosystem` match sites), E14 (Pipfile.lock, still unproven), E24 (the nine revert mechanisms), E42 (embedded `--vex` glue; consider handing it to `audit-core`).
47+
48+
---
49+
_Generated by [Claude Code](https://claude.ai/code)_

‎register/10-audit-ecosystems.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
### Ecosystems and formats (`audit-ecosystems`)
2-
_Last updated 2026-10-06T07:30Z · main @ 9c43dfc_
2+
_Last updated 2026-10-06T12:51Z · main @ 9c43dfc_
33

44
| ID | P | Problem | Source | Issues | Status |
55
|---|:-:|---|---|---|---|
@@ -25,7 +25,7 @@ _Last updated 2026-10-06T07:30Z · main @ 9c43dfc_
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 | #833, #834 | filed #833, #834; tracking #833, child 1 #834 (entry types) |
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 seven times (`guard_coordinates` → … → a literal `VendorEntry`; pnpm legacy shares v9's since #583). Target: one generic driver + `NpmLockBackend`. | 4.4; 4.7 C | #920, #922 | filed #920, #922; tracking #920, child 1 #922 (entry constructor) |
28-
| E23 | 2 | The `pypi_{poetry,pdm,pipenv}.rs` backends repeat one skeleton: `load_*_project`, `classify_dependency`, `check_target_guards`, `wire_*`, `revert_*`. | 5.4 | | to verify |
28+
| E23 | 2 | The `pypi_{poetry,pdm,pipenv}.rs` backends repeat one skeleton: `load_*_project`, `classify_dependency`, `check_target_guards`, `wire_*`, `revert_*`. | 5.4 | #937 | filed #937; shared wire/revert envelope + one `LockTarget` (no drift proven) |
2929
| E24 | 2 | There are nine revert mechanisms (~3.5K lines). Target: one splice-record revert engine, with legacy ledger kinds adapted at load. | 2.1; 5.3; 5.8 | | to verify |
3030
| E25 | 3 | Per-backend copies: `cleanup_failed_stage`, `<eco>_service_copy` (cargo, composer, gem, golang), and the `service_preflight_names_exactly_*` test copied seven times. | 5.4; 5.8 | #906 | filed #906; service-copy pipeline + cleanup (preflight test copies now share `plan_matches_grants`, out of scope) |
3131
| E26 | 3 | JVM has two Maven backends. Target: merge `maven_repo.rs` into `jvm/` as `Shape::Single`. Its three artifact roots don't follow `<eco>/<uuid>`. | 5.7 | | to verify |
@@ -68,6 +68,7 @@ _Last updated 2026-10-06T07:30Z · main @ 9c43dfc_
6868
| E63 | 2 | Hosted Maven splices the API `maven_suffixed_version` into `pom.xml` unchecked (any string, even markup), while hosted Gradle refuses the same grant unless it is `<base>-socket.<uuid[..8]>` (`redirect_gradle_override_invalid`); the suffix grammar has four builders and no shared validator, and the Maven/Gradle coordinate derivation is written twice (executed twice). | new finding | #882 | filed #882 |
6969
| E64 | 2 | BOM handling has no shared helper: 4 named `strip_bom` copies and ~50 inline strips (one-vs-many drift). `formats::pnpm`'s three `lockfileVersion` readers and `workspace::top_level_key` never strip it, so one BOM pnpm lock is readable (entries), not a pnpm lock (VEX), unversioned (hosted trust gate) and unsupported (vendored router), executed twice. Symptoms #903, #904, #623. | new finding; 4.4 | #905 | in PR #909 |
7070
| E65 | 3 | Every vendored backend sink discards `force` and `sources` (`_force`/`_sources` at 10 sinks) since acquisition went service-only, yet `vendor --force` help and `CLI_CONTRACT.md` promise missing-file tolerance and a `vendor_content_mismatch_overwritten` warning that nothing emits; `--force` only bypasses the variant probe (executed twice). Bears on #615. | new finding; 5.2 | #923 | filed #923 |
71+
| E66 | 2 | Vendored Poetry has two forward splicers chosen by line ending: CRLF/legacy locks use the shared `utils::poetry_lock` engine (as hosted does), LF 2.x locks use the `toml_surgery` line scanner `rewrite_target_package_unit`. They write different `files` shapes for one lock, and only the engine checks the wheel name and lowercases the digest (executed twice). | new finding; 5.4 | #936 | filed #936 |
7172

7273
**Handed off:** none yet.
7374

0 commit comments

Comments
 (0)