Skip to content

Commit a699c1c

Browse files
committed
feat(bootstrap): add IPC handshake support for subprocess detection
Updates bootstrap to always send IPC handshake when spawning the CLI. This allows the subprocess to detect it's running as a subprocess and access configuration data passed via the extra field. - Adds findSystemNode() to find system Node.js (excluding SEA binary) - Always use IPC channel with subprocess - Send IPC handshake with subprocess and parent_pid indicators - System Node.js will ignore the handshake message - SEA subprocess will use it to skip bootstrap
1 parent 793da1d commit a699c1c

File tree

3 files changed

+301
-182
lines changed

3 files changed

+301
-182
lines changed

packages/bootstrap/dist/bootstrap-npm.js

Lines changed: 127 additions & 87 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bootstrap/dist/bootstrap-smol.js

Lines changed: 129 additions & 89 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bootstrap/src/shared/bootstrap-shared.mjs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { homedir } from 'node:os'
88
import path from 'node:path'
99

1010
import { which } from '@socketsecurity/lib/bin'
11+
import { SOCKET_IPC_HANDSHAKE } from '@socketsecurity/lib/constants/socket'
1112
import { dlxPackage } from '@socketsecurity/lib/dlx-package'
1213
import { envAsBoolean } from '@socketsecurity/lib/env'
1314
import { logger } from '@socketsecurity/lib/logger'
@@ -98,17 +99,55 @@ export async function shouldForwardToSystemNode() {
9899
}
99100
}
100101

102+
/**
103+
* Find system Node.js binary (excluding the current SEA binary).
104+
*/
105+
async function findSystemNode() {
106+
try {
107+
const nodePath = await which('node', { all: true, nothrow: true })
108+
109+
if (!nodePath) {
110+
return undefined
111+
}
112+
113+
// which with all:true returns string[] if multiple matches, string if single match.
114+
const nodePaths = Array.isArray(nodePath) ? nodePath : [nodePath]
115+
116+
// Find first Node.js that isn't our SEA binary.
117+
const currentExecPath = process.execPath
118+
const systemNode = nodePaths.find(p => p !== currentExecPath)
119+
120+
return systemNode
121+
} catch {
122+
return undefined
123+
}
124+
}
125+
101126
/**
102127
* Execute the CLI with the given arguments.
103128
*/
104129
export async function executeCli(cliPath, args) {
105-
const result = await spawn(process.execPath, [cliPath, ...args], {
106-
env: {
107-
...process.env,
108-
PKG_EXECPATH: process.env.PKG_EXECPATH || 'PKG_INVOKE_NODEJS',
109-
},
110-
stdio: 'inherit',
130+
// Try to find system Node.js (excluding ourselves if we're a SEA binary).
131+
const systemNode = await findSystemNode()
132+
const nodePath = systemNode ?? process.execPath
133+
134+
// Always use IPC channel and send handshake.
135+
// System Node.js will ignore the handshake message.
136+
// SEA subprocess will use it to skip bootstrap.
137+
const result = await spawn(nodePath, [cliPath, ...args], {
138+
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
111139
})
140+
141+
// Send IPC handshake to subprocess.
142+
if (result.process && typeof result.process.send === 'function') {
143+
result.process.send({
144+
[SOCKET_IPC_HANDSHAKE]: {
145+
subprocess: true,
146+
parent_pid: process.pid,
147+
},
148+
})
149+
}
150+
112151
process.exit(result.code ?? 0)
113152
}
114153

0 commit comments

Comments
 (0)