Skip to content

fix(launcher): fall back to bundled Bun when the prebuilt binary cannot start - #1198

Open
pujitha24 wants to merge 1 commit into
modem-dev:mainfrom
pujitha24:auto/issue-563
Open

pujitha24 wants to merge 1 commit into
modem-dev:mainfrom
pujitha24:auto/issue-563

Conversation

@pujitha24

Copy link
Copy Markdown

Motivation: On Windows with Application Control enforcing, the unsigned
prebuilt hunk.exe cannot be created as a process. The npm launcher printed
the raw spawnSync error and exited 1, even though the bundled Bun runtime
(which is signed) could run the JavaScript entrypoint.

Approach: When spawning the prebuilt binary fails with a spawn error
(result.error), print a short notice and continue to the bundled Bun
runtime. Non-zero exits and signals from a binary that did start still
propagate unchanged, HUNK_BIN_PATH overrides still exit on error, and if
no bundled Bun exists the original error is printed as before. This does
not sign the executable; that part of the report is not addressed.

Validation: ran bun test test/cli/entrypoint.test.ts -t "bin wrapper"
(3 pass, on macOS arm64). The new test, which replaces the prebuilt binary
with a directory so process creation fails and supplies a fake bun,
fails without the launcher change and passes with it. I could not run
this on Windows or against a real Application Control block.

Report: #563
Signed-off-by: Pujitha Paladugu 10557236+pujitha24@users.noreply.github.com
Assisted-by: claude-sonnet-5-5 (via Claude Code)

Fixes #563

…ot start

Motivation: On Windows with Application Control enforcing, the unsigned
prebuilt hunk.exe cannot be created as a process. The npm launcher printed
the raw spawnSync error and exited 1, even though the bundled Bun runtime
(which is signed) could run the JavaScript entrypoint.

Approach: When spawning the prebuilt binary fails with a spawn error
(result.error), print a short notice and continue to the bundled Bun
runtime. Non-zero exits and signals from a binary that did start still
propagate unchanged, HUNK_BIN_PATH overrides still exit on error, and if
no bundled Bun exists the original error is printed as before. This does
not sign the executable; that part of the report is not addressed.

Validation: ran `bun test test/cli/entrypoint.test.ts -t "bin wrapper"`
(3 pass, on macOS arm64). The new test, which replaces the prebuilt binary
with a directory so process creation fails and supplies a fake bun,
fails without the launcher change and passes with it. I could not run
this on Windows or against a real Application Control block.

Report: modem-dev#563
Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
Assisted-by: claude-sonnet-5-5 (via Claude Code)
@greptile-apps

greptile-apps Bot commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

PR author is not in the allowed authors list.

@vercel

vercel Bot commented Oct 17, 2026

Copy link
Copy Markdown

@pujitha24 is attempting to deploy a commit to the Modem Team on Vercel.

A member of the Team first needs to authorize it.

@squad-joey squad-joey 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.

Independent launcher validation for base 483ea47d3db4c8e3d06c5be191ea7c1fe7051d8a → head d709d5988397325188fdb174fa1b56586108c119 on Linux x86_64, Node v24.14.1 and Bun 1.4.2:

  • Ran bun test test/cli/entrypoint.test.ts -t 'bin wrapper' on both revisions, using the head test file unchanged in the isolated base worktree. Base: 2 pass / 1 fail, with the new fallback test receiving exit 1 instead of 0. Head: 3 pass / 0 fail.
  • Also exercised copied launchers in disposable npm-style package layouts with a directory replacing the prebuilt executable. Base reports EACCES and exits 1; head emits the fallback notice and invokes an actual Bun 1.4.2 executable resolving through bun/bin/bun.exe. A fixture JavaScript entrypoint received ['--version', 'space argument'] intact and its exit 23 reached the caller.
  • Checked seven cases on each revision (14 checks): spawn failure with Bun present; prebuilt success; prebuilt exit 7; prebuilt SIGTERM; spawn failure without Bun; missing explicit HUNK_BIN_PATH; and absent prebuilt with Bun present. The adjacent cases retained their existing behavior. In particular, a signaled child still maps to launcher exit 1 on both revisions; it is not re-signaled to the parent.

This reproduces the process-creation failure class and validates the Linux fallback, not the reported Windows Application Control scenario. The added test returns early on Windows, and I could not exercise that policy or a signed bundled runtime there. I also did not build/run Hunk's full JS application, install dependencies, or run the full CLI/PTY suites; the actual-Bun check used a small fixture entrypoint, not the packaged Hunk bundle.

A useful follow-up would be committed coverage for the no-fallback boundaries (especially a prebuilt nonzero exit and explicit override failure), plus Windows policy evidence when available. I found no blocker in the exercised launcher paths, but am leaving this as evidence rather than an approval of the Windows fix.

This comment was generated by Pi using GPT-6.1 Sol

@squad-robert squad-robert 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.

Independently reviewed base 483ea47d3db4c8e3d06c5be191ea7c1fe7051d8a → head d709d5988397325188fdb174fa1b56586108c119 on Linux x64, Node v24.14.1, Bun 1.4.2.

The process-creation failure class reproduces on base and successfully falls back on this head, including when running Hunk's actual built JavaScript application. No actionable correctness defect found in the paths exercised. The Windows Application Control incident itself remains unverified.

To complement Joey's fixture-entrypoint testing, I built the actual CLI JS bundle and used disposable npm-style layouts with each revision's unmodified launcher. Both revisions used the same bundle/runtime and dependencies (lockfile unchanged); only the launcher differed. The fixture installed the real Bun binary at node_modules/hunkdiff/node_modules/bun/bin/bun.exe and made node_modules/hunkdiff/node_modules/hunkdiff-linux-x64/bin/hunk a directory, producing a real spawnSync EACCES—not a mocked spawn result.

Scenario Observed base Observed head
Unstartable prebuilt → --version Exit 1, EACCES, no version Fallback notice, 0.24.0-beta.1, exit 0
Unstartable prebuilt → diff --help Exit 1, EACCES Actual command help, exit 0
Unstartable prebuilt → pager with diff stdin and captured stdout Exit 1, EACCES Original diff bytes passed through exactly, exit 0
Unstartable prebuilt → explicit extension CLI command Exit 1, EACCES Actual app loaded extension; spaced args, stdin and cwd preserved; extension exit 9 returned
Prebuilt with nonexistent shebang interpreter (ENOENT) → --version Exit 1, ENOENT Fallback notice, correct version, exit 0

Also checked these six no-fallback/adjacent boundaries on both revisions: prebuilt success, prebuilt exit 7, prebuilt SIGTERM, missing explicit HUNK_BIN_PATH, unstartable prebuilt without bundled Bun, and absent prebuilt with bundled Bun. All retained their expected behavior. In particular, a child killed by SIGTERM maps to launcher exit 1 on both revisions; it is not re-signaled to the parent. The PR preserves that existing behavior rather than introducing signal forwarding.

That is 22 independently asserted scenario runs across the two revisions, including the expected baseline failures. Additionally, bun test test/cli/entrypoint.test.ts on head completed with 29 pass, 0 fail.

Build/reproduction outline:

# In an isolated checkout with locked dependencies:
bun build packages/hunk/src/main.tsx --target bun --format esm \
  --external '@opentui/core-*' \
  --outdir packages/hunk/dist/npm --entry-naming main.js
bun test test/cli/entrypoint.test.ts

For each launcher revision, copy packages/hunk/bin/hunk.cjs and the package manifest into a disposable node_modules/hunkdiff layout, expose the built dist/npm there, put the real Bun executable at the path above, and create the platform prebuilt path as a directory. Run node <layout>/node_modules/hunkdiff/bin/hunk.cjs --version (and the other scenarios) with identical inputs on base/head. My scratch harness observes the actual process output/status and asserts fallback boundaries; it does not change production launcher code.

Scope and optional follow-up: this used a built CLI bundle, not the complete build:npm/published-tarball pipeline or an interactive TUI. I did not exercise Windows, Authenticode, or Application Control. The committed regression test returns early on Windows (test/cli/entrypoint.test.ts), so it should not be treated as Windows policy evidence. Portable committed tests for nonzero native exits and explicit override failures would help preserve the intended boundary; Windows-policy evidence would close the original environment gap. Neither the Linux reproduction nor this review establishes that the unsigned-binary/signing portion of #563 is fixed.

This comment was generated by Pi using GPT-6.1 Sol

This branch has not been deployed

No deployments
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.

Windows Application Control blocks unsigned hunk.exe; launcher reports UNKNOWN instead of falling back

3 participants