Skip to content

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

Description

@ShawnSiao

Summary

scripts/check-package.mjs rejects a valid npm tarball on Windows when the system tar command emits CRLF line endings for tar -tvzf.

The validation uses a multiline regular expression directly on the complete listing. In JavaScript, both CR and LF are line terminators for multiline anchors, so ^ can match between the \r and \n. The following \n is then tested as if it were the first character of a new line and triggers the non-regular-entry error.

Affected version and environment

  • Released package: @openai/[email protected]
  • Confirmed still present on current main at f22d4a36f26d16287bcdfd707b369116e02a08c3
  • Microsoft Windows NT 10.0.19045.0
  • PowerShell 7.6.3
  • Node.js 24.18.0
  • pnpm 11.17.0
  • bsdtar 3.5.2 / libarchive 3.5.2

Steps to reproduce

From the repository root:

cd sdk/typescript
corepack pnpm install --frozen-lockfile
corepack pnpm run build
corepack pnpm pack --pack-destination ../../dist
node scripts/check-package.mjs ../../dist/openai-codex-security-0.1.1.tgz

Observed error:

Error: npm tarball contains a non-regular entry (symbolic or hard link, device, or pipe).
    at scripts/check-package.mjs:185

I then captured the exact tar --ignore-zeros -tvzf output and checked every non-empty line. The generated archive contained 178 entries, and every listing line began with - or d; there were no links, devices, or pipes.

The package installation smoke test also passed:

Validated installed @openai/[email protected]: public import, CLI, and 94 bundled plugin files.

A minimal diagnostic using the same listing demonstrated the false match:

/^[^d-]/mu.exec(listing) matches the LF in the first CRLF sequence.

Expected behavior

A valid npm tarball containing only regular files and allowed directories should pass check-package.mjs regardless of whether the local tar command emits LF or CRLF.

Actual behavior

The validator reports a non-regular tar entry before the later code normalizes the same listing with split(/\r?\n/u).

Impact

Windows contributors using a CRLF-emitting tar implementation cannot run the repository's package-boundary validation locally, even though the generated package is valid and installable.

Relevant code

  • Current check:
    const listing = tar(["-tvzf", archive], "utf8");
    if (/^[^d-]/mu.test(listing)) {
    throw new Error(
    "npm tarball contains a non-regular entry (symbolic or hard link, device, or pipe).",
    );
    }
    const listingLines = listing.split(/\r?\n/u).filter(Boolean);
    if (
  • The code immediately below already creates normalized listingLines:
    }
    const listingLines = listing.split(/\r?\n/u).filter(Boolean);
    if (
    listingLines.length !== entries.length ||
    listingLines.some(
    (line, index) => line.startsWith("d") !== entries[index].endsWith("/"),
    )
    ) {
    throw new Error("npm tarball contains an invalid tar entry.");
    }
    const launcherPermissions =

PR #3 introduced the package-boundary checker and validated a Windows CI configuration, but its patch and review discussion do not cover a tar implementation that emits CRLF for verbose listings.

Suggested direction

Normalize the listing before checking entry types and reuse the normalized lines for both validations. For example:

const listingLines = listing.split(/\r?\n/u).filter(Boolean);
if (
  listingLines.some(
    (line) => !line.startsWith("d") && !line.startsWith("-"),
  )
) {
  throw new Error(
    "npm tarball contains a non-regular entry (symbolic or hard link, device, or pipe).",
  );
}

A focused regression test can pass a CRLF-formatted verbose listing with only regular files and assert that it is accepted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomersplatform:windowsWindows, PowerShell, Windows paths, or Windows ACLspriority:p2Significant defect or product gap with narrower impact or a workaround

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions