-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathcli-dispatch.mts
More file actions
executable file
·109 lines (94 loc) · 3.13 KB
/
cli-dispatch.mts
File metadata and controls
executable file
·109 lines (94 loc) · 3.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* Unified Socket CLI entry point.
*
* This single file handles all Socket CLI commands by detecting how it was
* invoked: - socket (main CLI) - socket-npm (npm wrapper) - socket-npx (npx
* wrapper)
*
* Perfect for SEA packaging and single-file distribution.
*
* Bootstrap Logic: When running as a SEA binary, we use IPC handshake to detect
* subprocess mode: - Initial entry (no IPC): Bootstrap to system Node.js or
* self with IPC - Subprocess entry (has IPC): Bypass bootstrap, act as regular
* Node.js.
*/
import path from 'node:path'
import { getDefaultLogger } from '@socketsecurity/lib-stable/logger/default'
import { waitForBootstrapHandshake } from './util/sea/boot.mjs'
const logger = getDefaultLogger()
// Detect how this binary was invoked.
export function getInvocationMode(): string {
// Check environment variable first (for explicit mode).
const envMode = process.env['SOCKET_CLI_MODE']
if (envMode) {
return envMode
}
// Check process.argv[1] for the actual script name.
const scriptPath = process.argv[1]
if (scriptPath) {
const scriptName = path
.basename(scriptPath)
.replace(/\.(cjs|exe|js|mjs)$/i, '')
// Map script names to modes.
if (scriptName.endsWith('-npm') || scriptName === 'npm') {
return 'npm'
}
if (scriptName.endsWith('-npx') || scriptName === 'npx') {
return 'npx'
}
if (scriptName.endsWith('-pnpm') || scriptName === 'pnpm') {
return 'pnpm'
}
if (scriptName.endsWith('-yarn') || scriptName === 'yarn') {
return 'yarn'
}
// For 'cli' or anything containing 'socket', default to socket mode.
if (scriptName.includes('socket') || scriptName === 'cli') {
return 'socket'
}
}
// Check process.argv0 as fallback.
const argv0 = path
.basename(process.argv0 || process.execPath)
.replace(/\.exe$/i, '')
if (argv0.endsWith('npm')) {
return 'npm'
}
if (argv0.endsWith('npx')) {
return 'npx'
}
if (argv0.endsWith('pnpm')) {
return 'pnpm'
}
if (argv0.endsWith('yarn')) {
return 'yarn'
}
// Default to main Socket CLI.
return 'socket'
}
// Route to the appropriate CLI based on invocation mode.
async function main() {
// If we're a subprocess with IPC, wait for handshake.
// This validates we're running in the correct context.
// Note: The handshake is used by Socket Firewall (sfw) operations to pass
// configuration (API token, bin name, etc.) to the subprocess.
try {
await waitForBootstrapHandshake(1000) // 1 second timeout.
// Handshake received - we're a validated subprocess.
} catch {
// No handshake received, or we're not a subprocess.
// This is normal for initial entry.
}
const mode = getInvocationMode()
// Set environment variable for child processes.
process.env['SOCKET_CLI_MODE'] = mode
// Import and run the appropriate CLI function.
// All wrapper modes now route through the main CLI entry with the mode set.
// The CLI will detect the mode and run the appropriate command.
await import('./cli-entry.mjs')
}
// Run the appropriate CLI.
main().catch(error => {
logger.error('Socket CLI Error:', error)
process.exit(1)
})