fix(detect) handle truncated pnpm lockfiles and empty yarn.lock#17
Merged
fix(detect) handle truncated pnpm lockfiles and empty yarn.lock#17
Conversation
Truncated pnpm lockfiles (incomplete YAML flow collections) caused js-yaml to throw during both detection and parsing. Detection now parses only the YAML header, and a new parsePnpmYaml helper progressively trims trailing lines until parsing succeeds. Empty yarn.lock files (header-only, no packages) were rejected by detection because it required at least one package entry. Now allows empty results when the yarn lockfile v1 header is present in the first 5 lines. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix biome lint: use optional chaining for pkg?.resolution, sort imports in set.js, remove trailing commas in test arrays. Add tests for truncated pnpm v6 lockfile (synthetic, cut mid-flow- collection) and empty yarn.lock (header-only). Verify detection and parsing both succeed for each case. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tsc requires explicit casts since yaml.load returns unknown. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
tryParsePnpminsrc/detect.jsnow parses only the first 20 lines of YAML (the header) instead of the full file, so detection succeeds even when the file body is truncated. A newparsePnpmYaml()helper insrc/parsers/pnpm/index.jswrapsyaml.loadwith progressive tail-trimming — if parsing fails, it removes up to 20 trailing lines one at a time until the YAML is valid.FlatlockSet.#parseAllinsrc/set.jsandfromPnpmLockboth use this helper instead of rawyaml.load.tryParseYarnClassicinsrc/detect.jsno longer requires at least one package entry. Empty yarn.lock files (header-only, zero packages) are now accepted asyarn-classicwhen the# yarn lockfile v1comment appears at column 0 within the first 5 lines.Why
Truncated pnpm lockfiles
pnpm v5/v6 lockfiles use inline YAML flow collections for resolution metadata (
resolution: {integrity: sha512-...}). When a lockfile is truncated mid-entry — common when files are copied from browser downloads, partial clones, or disk corruption — the unclosed{causesjs-yamlto throwunexpected end of the stream within a flow collection. This error propagated through three code paths:tryParsePnpmin detection — caught bytry/catch, returnedfalse, causing "Unable to detect lockfile type"yaml.load(content)inFlatlockSet.#parseAll— unhandled, threw to the useryaml.load(input)infromPnpmLock— sameThe fix splits the concern: detection only needs the header (where
lockfileVersionlives), so it parses the first 20 lines. The parser needs the full file but tolerates truncation by trimming trailing lines untilyaml.loadsucceeds. The null guard onpkg.resolutionat line 280 handles the boundary entry that parsed as a key withnullvalue after trimming.Empty yarn.lock
yarn initand various CI setups produce yarn.lock files containing only the standard header comment and no package entries. The previous detection requiredObject.keys(result.object).length > 0, which rejected these files. Simply removing the check would cause false positives — the@yarnpkg/lockfileparser is lenient enough to return{ type: 'success', object: {} }for arbitrary indented text (e.g., the spoofing test fixture). The fix allows empty results only when/^# yarn lockfile v1/mmatches within the first 5 lines, which is where real yarn.lock files place the header.Risk Assessment
Low risk. Detection changes are additive — previously-detected lockfiles take the same code paths. The pnpm tail-trimming only activates when
yaml.loadthrows (previously a hard failure). The yarn header check is strictly more permissive than the oldhasEntriesrequirement, gated by a narrow regex on the first 5 lines. All 156 existing tests pass, including the spoofing resistance suite.