Repository navigation
Consolidate remaining BOM stripping after the pnpm reader failures were fixed #905
Description
Activity
- addedbugSomething isn't workingSomething isn't workingpm:pnpmpnpmpnpmarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)Filed by a scheduled architecture audit routine (see the architecture review discussion)
on Oct 6, 2026 mikolalysenko commented
on Oct 6, 2026 CollaboratorAuthorMore actions[agent] Shares root cause with #903, #904: the
formats::pnpmlock and workspace readers (head_lock_version,lock_versions,is_pnpm_lock_text,workspace::top_level_key) match a column-0 literal and never skip a leading UTF-8 BOM. Will be fixed together.
Generated by Claude Code
mikolalysenko commented
on Oct 6, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (with #903, #904; shared root cause: pnpm lock/workspace readers don't skip a leading UTF-8 BOM). Branch: agent/fix-pnpm-bom-readers. Claim-ID: 2026-10-06T01:20:29Z-3fcf3e
Generated by Claude Code
mikolalysenko commented
on Oct 6, 2026 CollaboratorAuthorMore actions[agent] Fix in progress: #909 (steps 1 and 2 of the proposed change; step 3 stays a follow-up).
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue for the architecture refactor routine (highest leverage: step 3, the inline BOM strips onto
formats::text. It is the top-scoring candidate that lies entirely in files no open PR changes). Branch: arch-refactor/905-bom-sites. Claim-ID: 2026-10-08T07:55:58Z-1460c5The earlier fixer claim (2026-10-06T01:24Z) ended with #909, which merged steps 1 and 2 and left step 3 as a follow-up.
This slice covers the production sites in files no open PR touches: the hosted and shared requirements lexers,
manifest/operations.rs,hosted/npm_manifest.rs,gradle/dsl.rs,policy/socket_yml.rsand the CLI's hosted Pipenv remedy. It also adds a one-sided guard test, so a new file can't spell out its own BOM handling. The sites that sit in open-PR files stay on the guard's pending list for a later slice.
Generated by Claude Code
2 remaining items
- changed the title
[-]pnpm lock and workspace readers don't skip a leading BOM, because BOM handling has no shared helper (4 named copies, ~50 inline strips)[/-][+]Consolidate remaining BOM stripping after the pnpm reader failures were fixed[/+]on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue for the architecture refactor routine (highest leverage: step 3, slice 2: the inline BOM strips in the 11
PENDING_INLINE_BOMSfiles that no open PR changes now, ontoformats::text). Branch: arch-refactor/905-bom-sites-2. Claim-ID: 2026-10-08T18:56:38Z-46a945The previous claim (2026-10-08T07:59Z) ended with #1117, which merged as slice 1.
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions- added a commit that references this issue
on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue for the architecture refactor routine (highest leverage: step 3, slice 3: the inline BOM strips in the 4
PENDING_INLINE_BOMSfiles that no open PR changes,redirect/vlt.rs,vendor/go_mod_edit.rs,vendor/jvm/gradle.rsandvendor/lock_inventory/pypi.rs, ontoformats::text). Branch: arch-refactor/905-bom-sites-3. Claim-ID: 2026-10-08T23:59:38Z-061a4b
Generated by Claude Code
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions- added 2 commits that reference this issue
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue for the architecture refactor routine (highest leverage: step 3, slice 4: the inline BOM strips in the 7
PENDING_INLINE_BOMSfiles that no open PR changes now,crawlers/npm_crawler.rs,formats/pnpm/lines.rs,hosted/governing_root.rs,patch/redirect/npmrc.rs,patch/redirect/upstream/npm.rs,vex/discover/npm.rsandvex/discover/pypi_other.rs, ontoformats::text). Branch: arch-refactor/905-bom-sites-4. Claim-ID: 2026-10-09T13:56:35Z-7070bcThe remaining 4 files (
redirect/mod.rs,upstream/pypi.rs,vendor/yarn_classic_lock.rs,vex/discover/yarn.rs) wait on the open PRs that change them.
Generated by Claude Code
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions- added a commit that references this issue
on Oct 9, 2026
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.
Kind: bug (with a refactor fix). Source: new finding; review "CRLF/BOM/indent policy" (Part 4.4), register E64.
Problem
No module owns "a leading UTF-8 BOM is encoding, not content". Each reader decides for itself, on
main@9c43dfc:utils::serde::strip_bom,gradle::dsl::strip_bom, a privateformats::yarn::strip_bomandcargo_manifest::split_bom.``strip_prefix('\u{feff}')ortrim_start_matches('\u{feff}'), and several also re-add the BOM after an edit:split_bom,vendor::common,redirect/mod.rs,[`upstream/npm.rs`](https://github.com/SocketDev/socket-patch/blob/9c43dfc96a3da66ff83c0d3a977db9f496ecbd53/crates/socket-patch-core/src/patch/redirect/upstream/npm.rs#L457-L459),`` plus requirements, Pipenv and Gradle.vendor::common::parse_json_manifeststrips exactly one BOM, which its testparse_json_manifest_reads_past_one_bom_onlypins down.lock_inventory/pypi.rs,``pypi_hatch.rs, `upstream/pypi.rs` and `vex/discover/pypi_other.rs` strip any number.lockfileVersionreaders in one file match a column-0 literal:head_lock_version(behindsniff_lock_grammar),lock_versions(behindlock_version_majorandmay_need_store_flag) andis_pnpm_lock_text.[`workspace::top_level_key`](https://github.com/SocketDev/socket-patch/blob/9c43dfc96a3da66ff83c0d3a977db9f496ecbd53/crates/socket-patch-core/src/formats/pnpm/workspace.rs#L20-L25``) doesn't strip it either, while the otherpnpm-workspace.yamlkey reader,governing_root::workspace_lockfile_dir,`` does. The yarn sniffis_berry_lockskips it on purpose.Proof by execution. I ran a throwaway unit test twice on
9c43dfcwith identical results. It used one pnpm 9 lock with oneleft-pad@1.3.0entry, once plain and once with a\u{feff}prefix:PnpmLock::entries(inventory, hosted rewrite)inventory_project_diagnosedPnpmLock::is_pnpm_lock(VEX discovery)sniff_lock_grammar/detect_npm_lock_flavor(vendored router)Pnpmvendor_lockfile_version_unsupported: "has no lockfileVersion in its head … re-lock with pnpm >= 9"lock_version_major(hosted trust gate)workspace::top_level_key("trustLockfile: false")trustLockfile\u{feff}trustLockfileworkspace_lockfile_dir("lockfileDir: ../x")../x../xformats::yarn::is_berry_lock(control)So a single BOM lock gets four answers inside
formats::pnpm: it is readable, not a pnpm lock, unversioned, and unsupported. pnpm itself reads it (see #903).Symptoms
trustLockfile: trueauto-config when pnpm-lock.yaml starts with a UTF-8 BOM, so pnpm 11/12 frozen installs fail with ERR_PNPM_TARBALL_URL_MISMATCH after a successful scan #903: the hosted trust gate misses a BOMpnpm-lock.yaml, and the frozen install fails.trustLockfile/overrides, so every pnpm install fails with "duplicate mapping key" after a successful scan #904:top_level_keymisses a BOM workspace key, and a duplicatetrustLockfile/overridesis appended.serde_json::from_strrefuses a BOMpackages.lock.json.Impact: medium. Each new reader repeats the decision, and every one that forgets it is a new bug. Three bug-hunt issues have hit this in different ecosystems so far.
Proposed change
formats::textwithsplit_bom(&str) -> (&str, &str)(one BOM, asparse_json_manifestpins down) andstrip_bom. Deleteutils::serde::strip_bom,gradle::dsl::strip_bom,formats::yarn::strip_bomandcargo_manifest::split_bom, and re-point their callers.formats::pnpm: havehead_lock_version,lock_versions,is_pnpm_lock_textandmay_need_store_flagreadstrip_bom(text). Have thepnpm-workspace.yamlsplices calltop_level_keyon a BOM-stripped first line, re-adding the BOM on write. Then makegoverning_root::workspace_lockfile_diratop_level_keycaller, which deletes its private key-prefix grammar.strip_prefix('\u{feff}')/trim_start_matches('\u{feff}')sites to the helper, file by file. Any site that keeps "any number of BOMs" must justify it in a comment.Size and scope
formats/,utils/serde.rs,gradle/dsl.rs,vendor/cargo_manifest.rsandhosted/governing_root.rs.pip freeze >writes) as absent: exit 0, no warning, and pip keeps installing the unpatched pin #721 / Fix UTF-16 requirements.txt silently skipped (#721) #724).Acceptance criteria
strip_bom/split_bompair informats::text, and the four named copies are deleted.sniff_lock_grammar,lock_version_major,is_pnpm_lockandentriesanswers as its plain twin (table-driven unit test).top_level_keyon a BOM first line returns the plain key, and a workspace splice keeps the BOM byte-exact (regression tests for Hosted pnpm scan skips thetrustLockfile: trueauto-config when pnpm-lock.yaml starts with a UTF-8 BOM, so pnpm 11/12 frozen installs fail with ERR_PNPM_TARBALL_URL_MISMATCH after a successful scan #903 and pnpm-workspace.yaml with a UTF-8 BOM: hosted and vendored miss the first top-level key and append a duplicatetrustLockfile/overrides, so every pnpm install fails with "duplicate mapping key" after a successful scan #904).parse_json_manifest_reads_past_one_bom_onlyand the existing CRLF/BOM round-trip tests (npm_lock_rewrite_keeps_crlf_tabs_and_bom,berry_crlf_and_bom_locks_round_trip_byte_exact,bom_prefixed_lock_is_rewritten_with_the_bom_intact) stay green.grep -rn "feff" crates/socket-patch-core/srcoutsideformats/text.rsand tests lists only sites with a justifying comment (after step 3).Dependencies
trustLockfile: trueauto-config when pnpm-lock.yaml starts with a UTF-8 BOM, so pnpm 11/12 frozen installs fail with ERR_PNPM_TARBALL_URL_MISMATCH after a successful scan #903, pnpm-workspace.yaml with a UTF-8 BOM: hosted and vendored miss the first top-level key and append a duplicatetrustLockfile/overrides, so every pnpm install fails with "duplicate mapping key" after a successful scan #904 and Hosted and vendored NuGet reject a packages.lock.json with a UTF-8 BOM that dotnet restores fine: hosted skips the redirect and exits 0 success, vendored fails apply_failed #623 one-line fixes.Backlog review — 2026-10-08
Priority: P1 → P3. The functional pnpm BOM-reader failures were fixed by #909. The remaining broad strip_bom consolidation is maintenance; keep active PR #1117.
The title now describes the remaining scope after the partial fixes. The original report is preserved above for historical context.