Skip to content

mcpb pack on Windows produces .mcpb without Unix file permissions #235

@ybenouag

Description

@ybenouag

Describe the bug

mcpb pack on Windows produces .mcpb archives without Unix file permission metadata in the ZIP external file attributes. When the resulting .mcpb is unpacked or used on Linux/macOS, launcher scripts (.sh) and platform binaries are missing the executable bit, causing "Permission denied" errors.

This also affects the MCPB staging workflow itself: running npm install on Windows and then copying the staging directory to Linux results in node_modules/.bin/mcpb losing its execute bit, so even mcpb validate fails.

This is a variant of #12, which was fixed for the macOS/Linux packing path but not for Windows.

To Reproduce

  1. On a Windows machine, stage an MCPB bundle (e.g., via npm install + a Go stager that writes launcher scripts with 0o755)
  2. Copy the staging directory to a Linux machine (e.g., via git, CI artifact, or shared filesystem)
  3. Run npm run mcpb-validate on Linux
$ npm run mcpb-validate

> mcpb-validate
> mcpb validate bundle/manifest.json

sh: 1: mcpb: Permission denied

Similarly, running mcpb pack on Windows and unpacking on Linux produces non-executable binaries and launcher scripts.

Expected behavior

.mcpb bundles should be valid cross-platform regardless of where they were packed. mcpb pack on Windows should still embed Unix permission attributes in the ZIP so that executable files are runnable after unpacking on Unix systems.

Logs

> npm run mcpb-validate

> mcpb-validate
> mcpb validate bundle/manifest.json

sh: 1: mcpb: Permission denied

Additional context

The root cause is in dist/cli/pack.js:

const isUnix = process.platform !== "win32";
if (isUnix) {
    zipFiles[filePath] = [fileData.data, { os: 3, attrs: (fileData.mode & 0o777) << 16 }];
} else {
    zipFiles[filePath] = fileData.data;  // no permissions stored
}

The stat.mode is already read on Windows (in files.js), but discarded during packing. A possible fix: always write the attrs field with os: 3, using the stat.mode from the filesystem (Git Bash / MSYS2 do report meaningful mode bits), or defaulting to 0o755 for files matching known executable patterns (.sh, binaries listed in entry_point).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions