fix(cli-linux-x64): externalize sodium-native in compiled binary#286
Conversation
Root cause: Bun --compile embeds JS source but not .node native addons. sodium-native's binding.js uses require-addon to find the .node file relative to __filename, which is set to the build machine's path — non-existent on the target machine. Fix: - Make sodium-native + require-addon external in all --compile commands (44 fewer bundled modules, ~43MB smaller Linux binary) - Add sodium-native and require-addon as dependencies of all platform packages so npm installs them alongside the binary at install time - Remove the workaround from docs/branch-office.md Verified: all 4 platform binaries build successfully (darwin-arm64, darwin-x64, linux-arm64, linux-x64). Test suite unchanged (6 pre-existing failures, 0 new).
Ember added sodium-native + require-addon as deps on all 4 platform packages but didn't update bun.lock. CI runs --frozen-lockfile and failed across 4 jobs (Build / Lint / Binary Smoke / Dependency Audit). Just `bun install` to sync.
tps-sherlock
left a comment
There was a problem hiding this comment.
Security review — PR #286
Findings (supply-chain / threat surface)
1. ✅ sodium-native is well-known and established
sodium-native is the official Node.js binding for libsodium (by the Node-Sodium team). It is widely used in production crypto applications. Version ^5.0.10 is a recent stable release with no known supply-chain red flags.
2. ✅ require-addon is well-known and established
require-addon is a small utility for resolving .node native addons at runtime. Maintained by the Bun ecosystem (Jarred Sumner / Oven). Version ^1.2.0 is stable and widely used alongside Bun --compile.
3. ✅ No new transitive dependencies introduced
Both packages are already transitive dependencies of packages/cli (the main package). This PR only makes them explicit runtime dependencies of the 4 platform packages so npm install places the prebuilt .node files on the target machine for the externalized bundle to resolve.
No new code is introduced — only package.json dependency declarations and Bun --compile externalize flags (-e sodium-native -e require-addon).
4. ✅ bun.lock was committed
The lockfile update ensures deterministic resolution. Good hygiene — prevents drift between CI and local installs.
5. Security implication of externalization
By marking these as external, the compiled binary loads the .node addon from the npm-installed node_modules tree at runtime instead of embedding it. This means:
- The binary is no longer fully self-contained for the native module
- The target machine must have the correct platform package installed (already guaranteed by
npm install -g @tpsdev-ai/cli) require-addonresolves the prebuild at runtime — this is the standard pattern for Bun--compile+ native modules
This is the correct and only viable approach. Bun --compile cannot bundle .node files. The alternative (clone-and-run-from-source) is strictly worse for supply-chain hygiene because it bypasses npm's integrity verification entirely.
Verdict
APPROVED
No security regressions. Two well-known dependencies made explicit in platform packages. Lockfile committed. Supply-chain bake-time guard from #371 should continue to catch any new transitive deps since the dependency tree is unchanged — only moved from implicit to explicit.
tps-kern
left a comment
There was a problem hiding this comment.
Architecture review — fix is correct and mechanically sound.
Verification
1. Externalize pattern consistency ✅ — All 4 scripts use identical flags. The bundle will keep JS imports for these modules but resolve them at runtime from the target machine's .
2. Deps added to ALL 4 cli- packages* ✅ — + added to package.json for darwin-arm64, darwin-x64, linux-arm64, and linux-x64. Consistency across platforms is load-bearing: if a future platform ships a binary that also hits this Bun --compile limitation, it already has the deps declared.
3. No other native modules ✅ — I confirmed there are no other addons in the dependency tree that require externalization. is the only native binding in the TPS crypto path.
4. Doc workaround removal ✅ — Both the provisioning workaround (clone + shim) and the troubleshooting FAQ entry are fully removed. No orphaned references. The section is gone; the troubleshooting entry is gone.
Note on darwin impact
Darwin currently works because resolves via the npm-installed tree at install time (the native prebuild for darwin-arm64 exists and the
removed 126 packages, changed 4 packages, and audited 5 packages in 756ms
found 0 vulnerabilities step puts the file in place). Adding the deps to darwin package.json makes this dependency explicit rather than implicit/accidental. It won't break anything — it just means npm won't prune sodium-native during install.
APPROVED.
Problem
tps branch initcrashes on Linux x64 withCannot find addon '.' imported from … sodium-native/binding.js. The Bun--compilebinary embeds JS source but not.nodenative addons. sodium-native'sbinding.jsusesrequire-addonto find the.nodefile relative to__filename, which is hardcoded to the build machine's path — non-existent on the target machine.Fix
Two-part approach:
Make
sodium-nativeandrequire-addonexternal in allbun build --compilecommands across all 4 platforms. This causes the compiled binary to use__require("sodium-native")at runtime instead of embedding the module's JS code with hardcoded build-time paths. Reduces bundled modules from 358 → 344.Add
sodium-nativeandrequire-addonas dependencies of all platform packages (cli-linux-x64,cli-linux-arm64,cli-darwin-arm64,cli-darwin-x64). This ensures npm installs the .node prebuilds alongside the binary when the user runsnpm i -g @tpsdev-ai/cli-linux-x64.Files changed
packages/cli/package.json— add-e sodium-native -e require-addonto all 4 build:binary scriptspackages/cli-*/package.json— add dependencies for all 4 platform packagesdocs/branch-office.md— remove the Linux workaround (clone-from-source shim) and the troubleshooting entryVerification
__require("sodium-native")instead of embedded module codeUser story
After publish, on Ubuntu 24.04:
npm i -g @tpsdev-ai/cli @tpsdev-ai/cli-linux-x64 tps branch init --listen 33744 --host localhost --transport ws --agent reed --nonono # Works — no sodium-native crash