diff --git a/src/libarchive/libarchive.zig b/src/libarchive/libarchive.zig index 7765ab4e4607..09f5c495546e 100644 --- a/src/libarchive/libarchive.zig +++ b/src/libarchive/libarchive.zig @@ -462,7 +462,13 @@ pub const Archiver = struct { } }, .file => { - const mode: bun.Mode = if (comptime Environment.isWindows) 0 else @intCast(entry.perm()); + // first https://github.com/npm/cli/blob/feb54f7e9a39bd52519221bae4fafc8bc70f235e/node_modules/pacote/lib/fetcher.js#L65-L66 + // this.fmode = opts.fmode || 0o666 + // + // then https://github.com/npm/cli/blob/feb54f7e9a39bd52519221bae4fafc8bc70f235e/node_modules/pacote/lib/fetcher.js#L402-L411 + // + // we simplify and turn it into `entry.mode || 0o666` because we aren't accepting a umask or fmask option. + const mode: bun.Mode = if (comptime Environment.isWindows) 0 else @intCast(entry.perm() | 0o666); const file_handle_native = brk: { if (Environment.isWindows) { diff --git a/test/cli/install/bun-install.test.ts b/test/cli/install/bun-install.test.ts index 088199222acc..3c33dbc6cd21 100644 --- a/test/cli/install/bun-install.test.ts +++ b/test/cli/install/bun-install.test.ts @@ -11,8 +11,18 @@ import { setDefaultTimeout, test, } from "bun:test"; -import { access, mkdir, readlink, rm, writeFile } from "fs/promises"; -import { bunEnv, bunExe, bunEnv as env, tempDirWithFiles, toBeValidBin, toBeWorkspaceLink, toHaveBins } from "harness"; +import { access, mkdir, readlink, rm, writeFile, cp, stat } from "fs/promises"; +import { + bunEnv, + bunExe, + bunEnv as env, + tempDirWithFiles, + toBeValidBin, + toBeWorkspaceLink, + toHaveBins, + runBunInstall, + isWindows, +} from "harness"; import { join, sep } from "path"; import { dummyAfterAll, @@ -8185,6 +8195,31 @@ describe("Registry URLs", () => { }); }); +it("should ensure read permissions of all extracted files", async () => { + await Promise.all([ + cp(join(import.meta.dir, "pkg-only-owner-2.2.2.tgz"), join(package_dir, "pkg-only-owner-2.2.2.tgz")), + writeFile( + join(package_dir, "package.json"), + JSON.stringify({ + name: "foo", + version: "0.0.1", + dependencies: { + "pkg-only-owner": "file:pkg-only-owner-2.2.2.tgz", + }, + }), + ), + ]); + + await runBunInstall(env, package_dir); + + expect((await stat(join(package_dir, "node_modules", "pkg-only-owner", "package.json"))).mode & 0o666).toBe( + isWindows ? 0o666 : 0o644, + ); + expect((await stat(join(package_dir, "node_modules", "pkg-only-owner", "src", "index.js"))).mode & 0o666).toBe( + isWindows ? 0o666 : 0o644, + ); +}); + it("should handle @scoped name that contains tilde, issue#7045", async () => { await writeFile( join(package_dir, "bunfig.toml"), diff --git a/test/cli/install/pkg-only-owner-2.2.2.tgz b/test/cli/install/pkg-only-owner-2.2.2.tgz new file mode 100644 index 000000000000..c45ba36ad033 Binary files /dev/null and b/test/cli/install/pkg-only-owner-2.2.2.tgz differ