Skip to content

fix(scripts): accept CRLF tar listings when inspecting npm tarballs - #217

Open
rohanpoudel2 wants to merge 2 commits into
openai:mainfrom
rohanpoudel2:fix/tar-crlf
Open

fix(scripts): accept CRLF tar listings when inspecting npm tarballs#217
rohanpoudel2 wants to merge 2 commits into
openai:mainfrom
rohanpoudel2:fix/tar-crlf

Conversation

@rohanpoudel2

Copy link
Copy Markdown

Fixes #32

Problem

scripts/check-package.mjs validated the whole tar --ignore-zeros -tvzf listing in one shot:

if (/^[^d-]/mu.test(listing)) {
  throw new Error(
    "npm tarball contains a non-regular entry (symbolic or hard link, device, or pipe).",
  );
}

With the m flag, JavaScript treats both \r and \n as line terminators. On a CRLF listing, ^ therefore matches the position between the \r and the \n, and the \n is inspected as if it were the first character of an entry line. It is neither d nor -, so a perfectly valid archive is rejected:

Error: npm tarball contains a non-regular entry (symbolic or hard link, device, or pipe).

Windows contributors whose tar emits CRLF cannot run pnpm run check:package at all, as reported in #32 with bsdtar 3.5.2.

The bug is only in this early check. A few lines further down the same listing is already normalized correctly with split(/\r?\n/u).

Change

Hoist the split that already exists and check each line individually, so the entry-type check and the entry-count check now read the same normalized lines:

const listingLines = listing.split(/\r?\n/u).filter(Boolean);
if (listingLines.some((line) => !/^[d-]/u.test(line))) {

I audited the rest of the script for the same class of defect — the sizeField check, the entries split, unsafePath, the launcher-permission split, internalMarker, and the .br/PNG filename tests. None of them combine the m flag with a multi-line input, so this was the only occurrence.

Verification

New tests-ts/check-package.test.ts packs the real tarball and runs the real script as a child process, with a tar shim on PATH that forwards every invocation to the real binary untouched except -tvzf, whose output it CRLF-terminates. That reproduces the Windows listing behavior exactly while leaving the archive itself valid.

Against the unfixed script:

+ error: npm tarball contains a non-regular entry (symbolic or hard link, device, or pipe).
(fail) npm tarball package check > accepts a valid tarball listed with CRLF line endings
 1 pass
 1 fail

With the fix:

 2 pass
 0 fail

A second test shims the listing with sed 's#^-#l#' to confirm a genuinely non-regular entry is still rejected, so the fix cannot silently turn into a no-op.

Full suite: 719 pass / 5 skip / 0 fail. pnpm run types and pnpm run format are clean.

The shims are POSIX shell scripts, so the tests use the repository's existing testPosix helper and skip on Windows — the same pattern tests-ts/container-entrypoint.test.ts uses. The Windows listing behavior is what is being reproduced, and the fix itself is platform-independent.

check-package.mjs validated the `tar -tvzf` listing with a single
multiline regex (`/^[^d-]/mu`) to assert every entry begins with `-`
(regular file) or `d` (directory). With the `m` flag, JavaScript
treats both `\r` and `\n` as line terminators, so on a CRLF listing
(as emitted by tar on Windows) `^` matches the position between `\r`
and `\n`, and the bare `\n` is then evaluated as the first character
of that "line". It is neither `d` nor `-`, so the regex matched and
the script rejected a perfectly valid tarball with:

  Error: npm tarball contains a non-regular entry (symbolic or hard
  link, device, or pipe).

The listing is already normalized correctly a few lines later via
`split(/\r?\n/u)`; the fix does that split once and checks each
line's first character individually instead of regexing the whole
blob, matching how the rest of the script already handles line
endings. Audited the remainder of the script for the same class of
bug; no other multiline regex or line-handling logic assumes LF.

Added a regression test that packs a real tarball with `pnpm pack`
and runs check-package.mjs through a `tar` shim that reproduces the
CRLF verbose listing, plus a companion test proving a real
non-regular entry is still rejected.

Fixes openai#32
@github-actions github-actions Bot added the bug Something isn't working label Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

check-package.mjs rejects valid npm tarballs when Windows tar emits CRLF

1 participant