Skip to content

fix(tui): preserve npm binary executable modes - #8330

Merged
lawrencecchen merged 5 commits into
mainfrom
feat-tui-npm-executable
Jul 17, 2026
Merged

lawrencecchen merged 5 commits into
mainfrom
feat-tui-npm-executable

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

npx cmux@0.9.1 fails with EACCES because GitHub artifact transfer removes executable bits after package smoke verification.

This wraps generated npm package directories in a validated tar archive before artifact upload, restores it in stable and nightly publish jobs, and rejects unsafe archive entries. The same helper verifies all four platform binaries plus the launcher remain executable.

Regression history:

  • ed2529b64c adds the failing archive round-trip test.
  • 97de7f447a adds the fix.

Verified:

  • 8 focused packaging and publishing-policy tests
  • workflow syntax with actionlint
  • local artifact round trip, npm pack, install, and launcher execution

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Preserves npm binary executable modes across artifact transfer to fix EACCES when running npx cmux@0.9.1. Builds now tar dist/npm-packages, and publish jobs extract it safely before npm publish.

  • Bug Fixes
    • Added cmux-tui/dist/scripts/package_npm_artifact.py to create/extract npm-packages.tar.gz, enforce safe extraction (no absolute/.. paths, entry/size limits), and verify executables.
    • Workflows: build uploads the tarball; nightly and stable extract to dist/ to restore modes; nightly checks out the immutable source ref before extraction.
    • Tests cover archive round-trip exec bits, path safety/limits, and workflow wiring; now executed in CI via .github/workflows/ci.yml.

Written for commit 6ffc42d. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved npm package publishing flows by packaging artifacts into a single tarball and preserving executable permissions during archive transfer.
    • Restores executable permissions after download/extraction before publishing.
    • Added protection to reject unsafe archive paths to prevent writes outside the target directory.
  • Tests
    • Added coverage for archive round-trip, executable mode preservation, path-traversal rejection, and that publishing workflows use the updated packaging steps.
    • Added CI guard step to run the new packaging artifact tests.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The workflows package npm directories into a tarball that preserves executable modes. Stable and nightly publish jobs extract the tarball before publishing, with tests covering permissions, traversal protection, and workflow configuration.

Changes

npm artifact mode preservation

Layer / File(s) Summary
Archive production and validation
.github/workflows/cmux-tui-build-package.yml, tests/test_tui_npm_package_artifact.py
The package job creates and uploads dist/npm-packages.tar.gz; tests verify executable permissions, workflow references, and the test entrypoint.
Safe archive extraction validation
tests/test_tui_npm_package_artifact.py
Extraction rejects traversal paths and prevents writes outside the target directory.
Publish workflow restoration
.github/workflows/cmux-tui-nightly.yml, .github/workflows/tui-publish-npm.yml, .github/workflows/ci.yml
Publish jobs download and extract the archive before npm publishing; nightly publishing checks out the resolved source revision, and CI runs the artifact transfer tests.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BuildWorkflow
  participant ArtifactStorage
  participant PublishWorkflow
  participant package_npm_artifact.py
  participant npm
  BuildWorkflow->>package_npm_artifact.py: create npm-packages.tar.gz
  BuildWorkflow->>ArtifactStorage: upload archive
  PublishWorkflow->>ArtifactStorage: download archive
  PublishWorkflow->>package_npm_artifact.py: extract archive into dist
  PublishWorkflow->>npm: publish restored packages
Loading

Suggested reviewers: austinywang

🚥 Pre-merge checks | ✅ 24 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (24 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PASS: The PR only changes YAML workflows and a Python test; no Swift files or actor-isolation-affecting production code are introduced.
Cmux Swift Blocking Runtime ✅ Passed No Swift files are changed; the diff only touches CI YAML and a Python test, so the Swift blocking-runtime rule is not applicable.
Cmux Browser Automation Off-Main ✅ Passed PASS: The PR only touches npm packaging workflows and a packaging test; it doesn't modify browser socket automation routing, mainActor hops, or policy tests.
Cmux Expensive Synchronous Load ✅ Passed No Swift production code changed; this commit only touches a CI workflow and a Python test, so the expensive-sync-load rule is not implicated.
Cmux Cache Substitution Correctness ✅ Passed No production Swift/TS/JS code changed; diff only touches workflows, a Python packaging helper, and tests, so the cache-substitution rule is not applicable.
Cmux No Hacky Sleeps ✅ Passed Diff only adds tar archive validation/extraction and CI/test wiring; no fixed sleeps, timers, or polling in changed runtime/build scripts.
Cmux Algorithmic Complexity ✅ Passed New helper is a single-pass tar validation/extract flow with a 1,024-member cap; workflow and test changes only add fixed-size checks.
Cmux Swift Concurrency ✅ Passed PASS: The diff only changes GitHub workflows and a Python packaging test; no Swift files or Swift concurrency patterns were introduced.
Cmux Swift @Concurrent ✅ Passed No Swift files or Swift async concurrency changes are in the diff, so the Swift @concurrent rule is not applicable.
Cmux Swift Package Boundaries ✅ Passed PASS: The PR changes only workflow YAML, a Python helper, and tests; no Swift production files or package-boundary changes are present.
Cmux Swiftpm Lockfiles ✅ Passed Diff only changes npm workflow/script/test files; no Package.swift, Package.resolved, Xcode project, or .gitignore lockfile policy changes are present.
Cmux Swift Logging ✅ Passed No production Swift code changed; the diff only touches a CI workflow and a Python test, with no added Swift logging.
Cmux User-Facing Error Privacy ✅ Passed Only CI workflow and test-only changes were introduced; no user-facing errors, alerts, command output, or secret/provider details were added.
Cmux Full Internationalization ✅ Passed PR only changes workflows, a packaging helper script, and tests; no app/UI/web locale text or string-catalog/message files were modified.
Cmux Swiftui State Layout ✅ Passed PR only changes workflows, a packaging script, and tests; no SwiftUI sources or forbidden state/layout patterns are introduced.
Cmux Architecture Rethink ✅ Passed No Swift files were changed; the Swift-architecture rethink rule is not applicable to this PR.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only changes workflows/tests; no Swift NSWindow/WindowGroup code or cmuxAuxiliaryWindowIdentifiers changes, so this rule is not applicable.
Cmux Source Artifacts ✅ Passed Changed paths are a workflow config and a hand-written test; no local artifacts, logs, caches, or temp directories were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The diff changes only workflow YAML and a test file; no production Swift files under Sources/ were modified, so the seam rule is not applicable.
Cmux No Ambient Global State ✅ Passed PASS: The PR only changes workflow YAML and a Python test; it adds no production Swift ambient globals, so the rule is not applicable.
Title check ✅ Passed The title is concise and accurately summarizes the main change: preserving npm package executable modes.
Description check ✅ Passed The description covers the change, rationale, and testing/verification, though it omits the demo video, review trigger, and checklist sections.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-tui-npm-executable

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes EACCES on npx cmux by preserving executable modes across GitHub artifact transfer. Previously, uploading the dist/npm-packages directory as an artifact stripped execute bits; now the build wraps the directory in a validated tar archive and the publish jobs extract it before calling npm publish.

  • New script cmux-tui/dist/scripts/package_npm_artifact.py handles archive creation (create) and extraction (extract), enforcing path-traversal safety, member-count and size limits, symlink rejection, and post-extraction executable verification.
  • Build workflow archives dist/npm-packages into npm-packages.tar.gz before upload; both stable and nightly publish jobs now download the tarball and extract it with filter=\"tar\" to restore modes before publishing.
  • Nightly workflow gains a checkout step so the helper script is available before it is invoked.

Confidence Score: 5/5

Safe to merge; the archive round-trip correctly preserves executable modes and the path-safety guards are sound for a trusted build pipeline.

The core fix is well-scoped: tarball creation uses recursive add with mode preservation, extraction applies filter=tar (preserves execute bits, strips setuid/setgid), and verify_executables post-extraction confirms the critical binaries are actually executable before publish proceeds. Path traversal, zip-bomb, and duplicate-entry checks are all present. Workflow wiring is covered by tests. The only observation is a create/extract asymmetry with symlinks, which is not a current concern given the simple package structure.

cmux-tui/dist/scripts/package_npm_artifact.py — see the note about symlink asymmetry between create and extract paths.

Important Files Changed

Filename Overview
cmux-tui/dist/scripts/package_npm_artifact.py New helper script wrapping tarball creation and extraction; correctly applies filter=tar, validates paths/sizes/member types, and verifies executables post-extract. Minor asymmetry: create_archive silently includes symlinks that validated_members then rejects on extraction.
.github/workflows/cmux-tui-build-package.yml Adds archive creation step before artifact upload; upload now points at npm-packages.tar.gz instead of the directory. Correctly guarded by the package_npm input flag.
.github/workflows/cmux-tui-nightly.yml Adds required checkout step before download and extraction; the script is now available before it is called. Extraction target and publish paths are consistent.
.github/workflows/tui-publish-npm.yml Stable publish job already had a checkout; adds extraction step after download, paths are consistent with the build step.
tests/test_tui_npm_package_artifact.py Covers archive round-trip exec-bit preservation, path-traversal rejection, and workflow wiring checks. Tests run as main for standalone CI invocation.
.github/workflows/ci.yml Adds a single step to run the new test file in CI syntax validation; straightforward and correct.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Build as cmux-tui-build-package
    participant Store as GitHub Artifact Store
    participant Publish as publish job
    participant NPM as npmjs.com

    Build->>Build: "cargo build → dist/npm-packages/"
    Build->>Build: "package_npm_artifact.py create (tar → npm-packages.tar.gz)"
    Build->>Store: "upload npm-packages.tar.gz"
    Note over Store: "executable bits preserved in tarball"
    Publish->>Store: "download npm-packages.tar.gz → dist/"
    Publish->>Publish: "package_npm_artifact.py extract (validate + filter=tar)"
    Publish->>Publish: "verify_executables() post-extract"
    Publish->>NPM: "npm publish with provenance"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Build as cmux-tui-build-package
    participant Store as GitHub Artifact Store
    participant Publish as publish job
    participant NPM as npmjs.com

    Build->>Build: "cargo build → dist/npm-packages/"
    Build->>Build: "package_npm_artifact.py create (tar → npm-packages.tar.gz)"
    Build->>Store: "upload npm-packages.tar.gz"
    Note over Store: "executable bits preserved in tarball"
    Publish->>Store: "download npm-packages.tar.gz → dist/"
    Publish->>Publish: "package_npm_artifact.py extract (validate + filter=tar)"
    Publish->>Publish: "verify_executables() post-extract"
    Publish->>NPM: "npm publish with provenance"
Loading

Reviews (2): Last reviewed commit: "test(tui): run npm artifact regression i..." | Re-trigger Greptile

Comment thread cmux-tui/dist/scripts/package_npm_artifact.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_tui_npm_package_artifact.py`:
- Around line 48-53: Replace the manual os.walk-based cleanup with shutil.rmtree
for the packages directory, adding the shutil import if needed. Preserve
deletion of the entire directory tree and its root while removing the
now-unnecessary traversal and individual unlink/rmdir calls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a51f8cc4-557a-4adf-bc97-ef741257ad48

📥 Commits

Reviewing files that changed from the base of the PR and between 493d5ad and 1d44800.

⛔ Files ignored due to path filters (1)
  • cmux-tui/dist/scripts/package_npm_artifact.py is excluded by !**/dist/**
📒 Files selected for processing (4)
  • .github/workflows/cmux-tui-build-package.yml
  • .github/workflows/cmux-tui-nightly.yml
  • .github/workflows/tui-publish-npm.yml
  • tests/test_tui_npm_package_artifact.py

Comment thread tests/test_tui_npm_package_artifact.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 13721be80b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/test_tui_npm_package_artifact.py
Comment thread tests/test_tui_npm_package_artifact.py
@lawrencecchen
lawrencecchen merged commit af11cf4 into main Jul 17, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant