Skip to content

Hosted yarn berry rewrites a mixed-line-ending package.json that vendored mode refuses #628

Description

[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.

Kind: bug. Source: new finding (register E51). It is a symptom of the duplicated berry project gates (E09, filed alongside).

Problem

Yarn berry's project gates exist once per mode, and they disagree about the root package.json. Both modes edit that file: vendored mode writes its file: wiring, and hosted mode writes resolutions.

Repro (unit probe on 045d7ec, run twice, not committed). Input: a 10c0 berry lock plus package.json = "{\r\n \"name\": \"app\",\n \"version\": \"1.0.0\"\r\n}\r\n".

  • rewrite_yarn_berry: no warnings, yarn.lock is written, and package.json is rewritten all-CRLF with the resolutions added. preflight_yarn_berry_hosted returns Ok.
  • Vendored mode, on the same shape (the existing test vendor::yarn_berry_lock::tests::mixed_line_endings_refuse_before_any_write, case PACKAGE_JSON): refused with vendor_yarn_berry_mixed_line_endings, nothing written.

Symptoms and impact

I found no existing issue for this. A project gets a different answer in each mode for the same file. Hosted mode quietly rewrites lines the user never touched, which shows up as diff noise in the commit, and it breaks the byte-exact round trip that vendored mode promises. The risk is low and the fix is small.

Proposed change

Make the berry gate set decide this once, for both modes (see the E09 refactor issue), and give the root manifest one policy:

  • Recommended: hosted mode refuses a mixed root package.json with redirect_yarn_berry_mixed_line_endings, the same as vendored mode and the same as the lock. This means preflight_yarn_berry_hosted also takes the manifest text, so the vendored→hosted takeover checks it before reverting anything.
  • Alternative: both modes accept it and normalize to the majority ending, as yarn's persistManifest does. That would drop vendored mode's documented refusal, which is a contract change and would need a maintainer's call.

Size and scope

About 30 production lines in patch/redirect/mod.rs and the takeover caller in commands/scan/hosted.rs, plus tests and one sentence in CLI_CONTRACT.md (the hosted berry line-endings paragraph). Out of scope: the yarn classic mixed-lock behavior (#467).

Acceptance criteria

  • A hosted rewrite of a berry project with a mixed root package.json takes the same decision as vendored mode, with the mode's *_yarn_berry_mixed_line_endings code, and writes nothing.
  • A vendored→hosted takeover with a mixed package.json is refused before the revert (wet and --dry-run).
  • Regression test: the probe above, asserting the refusal. The existing mixed_line_endings_refuse_before_any_write stays green.
  • The all-CRLF and all-LF manifest round-trip tests stay green.

Dependencies

None. Best landed together with, or right after, the E09 shared-gate refactor so the rule lives in one place.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:claimedagent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)bugSomething isn't workingpm:yarn-berryYarn Berry (2+)priority:p1

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions