Skip to content

Commit d0aa26d

Browse files
committed
fix(sea): use relative paths in sea-config and update SDK
- Update Node.js version requirement from 25.5.0 to 25.8.0 - Use relative paths in sea-config.json (binject requires relative paths) - Remove update-config.json generation (update config is embedded in sea-config) - Remove unused safeDelete import from builder.mjs - Update @socketsecurity/sdk to 3.3.1 with new createRepository API - Fix createRepository call signature (orgSlug, repoName, params) - Add missing external tools to EXTERNAL_TOOLS array - Fix visibility type to 'private' | 'public'
1 parent 6810de8 commit d0aa26d

File tree

11 files changed

+70
-111
lines changed

11 files changed

+70
-111
lines changed

.node-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
25.5.0
1+
25.8.0

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "socket-cli-monorepo",
33
"version": "0.0.0",
4-
"packageManager": "pnpm@10.30.2",
4+
"packageManager": "pnpm@10.31.0",
55
"private": true,
66
"engines": {
77
"node": ">=25.5.0",

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@
129129
"zod": "catalog:"
130130
},
131131
"engines": {
132-
"node": ">=25.5.0",
132+
"node": ">=25.8.0",
133133
"pnpm": ">=10.22.0"
134134
},
135135
"repository": {

packages/cli/scripts/sea-build-utils/builder.mjs

Lines changed: 35 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import { existsSync, promises as fs } from 'node:fs'
1212
import path from 'node:path'
1313

14-
import { safeDelete, safeMkdir } from '@socketsecurity/lib/fs'
14+
import { safeMkdir } from '@socketsecurity/lib/fs'
1515
import { normalizePath } from '@socketsecurity/lib/paths/normalize'
1616
import { spawn } from '@socketsecurity/lib/spawn'
1717

@@ -51,19 +51,20 @@ import { SOCKET_CLI_SEA_BUILD_DIR } from '../constants/paths.mjs'
5151
*/
5252
export async function generateSeaConfig(entryPoint, outputPath) {
5353
const outputName = path.basename(outputPath, path.extname(outputPath))
54+
const configDir = path.dirname(outputPath)
5455
const configPath = normalizePath(
55-
path.join(path.dirname(outputPath), `sea-config-${outputName}.json`),
56-
)
57-
const blobPath = normalizePath(
58-
path.join(path.dirname(outputPath), `sea-blob-${outputName}.blob`),
56+
path.join(configDir, `sea-config-${outputName}.json`),
5957
)
58+
// Use relative paths in sea-config.json (binject requires relative paths).
59+
const blobPathRelative = `sea-blob-${outputName}.blob`
60+
const mainPathRelative = path.relative(configDir, entryPoint)
6061

6162
const config = {
6263
// No assets to minimize size.
6364
assets: {},
6465
disableExperimentalSEAWarning: true,
65-
main: entryPoint,
66-
output: blobPath,
66+
main: mainPathRelative,
67+
output: blobPathRelative,
6768
// Enable code cache for ~13% faster startup (~22ms improvement).
6869
// Pre-compiles JavaScript code during build time for instant execution.
6970
useCodeCache: true,
@@ -97,7 +98,7 @@ export async function generateSeaConfig(entryPoint, outputPath) {
9798
// which is critical for useCodeCache support (code cache is version-specific).
9899
//
99100
// This eliminates the Node.js version mismatch issue where we were using the host
100-
// Node.js (e.g., v25.5.0) to generate blobs for node-smol targets (e.g., v24.10.0).
101+
// Node.js to generate blobs for node-smol targets with different Node.js versions.
101102
//
102103
// See injectSeaBlob() below for the config-based blob generation implementation.
103104

@@ -109,9 +110,8 @@ export async function generateSeaConfig(entryPoint, outputPath) {
109110
* Inject SEA blob and optional VFS assets into a Node.js binary using binject.
110111
*
111112
* This function performs the core SEA binary build step by:
112-
* 1. Generating an update-config.json for embedded update checking (binject --update-config).
113-
* 2. Invoking binject to inject the SEA blob into the Node.js binary.
114-
* 3. Optionally embedding security tools via VFS compression (binject --vfs).
113+
* 1. Invoking binject to inject the SEA blob into the Node.js binary.
114+
* 2. Optionally embedding security tools via VFS compression (binject --vfs).
115115
*
116116
* Config-Based Blob Generation:
117117
* Instead of pre-generating the SEA blob with `node --experimental-sea-config`, binject
@@ -123,11 +123,6 @@ export async function generateSeaConfig(entryPoint, outputPath) {
123123
* tools into the binary. This achieves ~70% compression compared to Node.js SEA assets.
124124
* If vfsTarGz is omitted, --vfs-compat mode is used (no actual VFS bundling).
125125
*
126-
* Update Config Embedding:
127-
* The function generates an update-config.json that node-smol's C stub uses for built-in
128-
* update checking. This enables SEA binaries to check GitHub releases and notify users of
129-
* available updates without needing TypeScript-based update checking.
130-
*
131126
* @param {string} nodeBinary - Path to the node-smol binary to inject into.
132127
* @param {string} configPath - Path to the sea-config.json file for config-based blob generation.
133128
* @param {string} outputPath - Path to the output SEA binary (may be same as nodeBinary).
@@ -215,72 +210,32 @@ export async function injectSeaBlob(
215210
env['SOCKET_DLX_DIR'] = uniqueCacheDir
216211
}
217212

218-
// Generate update-config.json for embedded update checking.
219-
const updateConfigPath = normalizePath(
220-
path.join(path.dirname(configPath), 'update-config.json'),
221-
)
222-
const updateConfig = {
223-
binname: 'socket',
224-
command: 'self-update',
225-
interval: 86_400_000,
226-
notify_interval: 86_400_000,
227-
prompt: false,
228-
prompt_default: 'n',
229-
skip_env: 'SOCKET_CLI_SKIP_UPDATE_CHECK',
230-
tag: 'socket-cli-*',
231-
url: 'https://api.github.com/repos/SocketDev/socket-cli/releases',
213+
// Inject SEA blob into Node binary using binject.
214+
const args = [
215+
'inject',
216+
'--executable',
217+
nodeBinary,
218+
'--output',
219+
outputPath,
220+
'--sea',
221+
configPath,
222+
]
223+
224+
// Add VFS if provided (compressed tar.gz), otherwise use vfs-compat mode.
225+
if (vfsTarGz && existsSync(vfsTarGz)) {
226+
args.push('--vfs', vfsTarGz)
227+
} else {
228+
args.push('--vfs-compat')
232229
}
233-
await fs.writeFile(updateConfigPath, JSON.stringify(updateConfig, null, 2))
234230

235-
try {
236-
// Inject SEA blob into Node binary using binject.
237-
//
238-
// Config-Based Blob Generation:
239-
// When --sea points to a .json file (sea-config.json), binject reads the config
240-
// and generates the blob automatically. This is more efficient than pre-generating
241-
// with `node --experimental-sea-config`.
242-
//
243-
// VFS Compression:
244-
// If vfsTarGz is provided, we use --vfs to embed compressed security tools.
245-
// binject decompresses the tar.gz and injects the files into the binary's VFS.
246-
// This achieves ~70% compression (460 MB → 140 MB for security tools).
247-
//
248-
// Without VFS (vfs-compat mode):
249-
// If vfsTarGz is omitted, --vfs-compat mode is used, which injects only the SEA
250-
// blob without any additional VFS data. This is useful for minimal CLI-only builds.
251-
const args = [
252-
'inject',
253-
'--executable',
254-
nodeBinary,
255-
'--output',
256-
outputPath,
257-
'--sea',
258-
configPath,
259-
]
231+
const result = await spawn(binjectPath, args, { env, stdio: 'inherit' })
260232

261-
// Add VFS if provided (compressed tar.gz), otherwise use vfs-compat mode.
262-
if (vfsTarGz && existsSync(vfsTarGz)) {
263-
args.push('--vfs', vfsTarGz)
264-
} else {
265-
args.push('--vfs-compat')
266-
}
267-
268-
args.push('--update-config', updateConfigPath)
269-
270-
const result = await spawn(binjectPath, args, { env, stdio: 'inherit' })
271-
272-
if (
273-
result &&
274-
typeof result === 'object' &&
275-
'exitCode' in result &&
276-
result.exitCode !== 0
277-
) {
278-
throw new Error(`binject failed with exit code ${result.exitCode}`)
279-
}
280-
} finally {
281-
// Clean up update config file (keep in debug mode for troubleshooting).
282-
if (!process.env['DEBUG']) {
283-
await safeDelete(updateConfigPath).catch(() => {})
284-
}
233+
if (
234+
result &&
235+
typeof result === 'object' &&
236+
'exitCode' in result &&
237+
result.exitCode !== 0
238+
) {
239+
throw new Error(`binject failed with exit code ${result.exitCode}`)
285240
}
286241
}

packages/cli/src/commands/repository/cmd-repository-create.mts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ export const cmdRepositoryCreate = createRepositoryCommand({
2929
},
3030
},
3131
handler: async ({ flags, orgSlug, outputKind, repoName }) => {
32+
const visibility = String(flags['visibility'] || 'private')
3233
await handleCreateRepo(
3334
{
3435
defaultBranch: String(flags['defaultBranch'] || ''),
3536
description: String(flags['repoDescription'] || ''),
3637
homepage: String(flags['homepage'] || ''),
3738
orgSlug,
3839
repoName: String(repoName),
39-
visibility: String(flags['visibility'] || 'private'),
40+
visibility: visibility === 'public' ? 'public' : 'private',
4041
},
4142
outputKind,
4243
)

packages/cli/src/commands/repository/fetch-create-repo.mts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export type FetchCreateRepoConfig = {
1111
homepage: string
1212
orgSlug: string
1313
repoName: string
14-
visibility: string
14+
visibility: 'private' | 'public'
1515
}
1616

1717
export type FetchCreateRepoOptions = {
@@ -44,11 +44,10 @@ export async function fetchCreateRepo(
4444
const sockSdk = sockSdkCResult.data
4545

4646
return await handleApiCall<'createRepository'>(
47-
sockSdk.createRepository(orgSlug, {
47+
sockSdk.createRepository(orgSlug, repoName, {
4848
default_branch: defaultBranch,
4949
description,
5050
homepage,
51-
name: repoName,
5251
visibility,
5352
}),
5453
{

packages/cli/src/commands/repository/handle-create-repo.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export async function handleCreateRepo(
1919
description: string
2020
homepage: string
2121
defaultBranch: string
22-
visibility: string
22+
visibility: 'private' | 'public'
2323
},
2424
outputKind: OutputKind,
2525
): Promise<void> {

packages/cli/src/utils/basics/vfs-extract.mts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,15 @@
1313
*/
1414

1515
import { createHash } from 'node:crypto'
16-
import { existsSync, promises as fs } from 'node:fs'
1716
import { homedir } from 'node:os'
1817
import path from 'node:path'
1918

20-
import { debug } from '@socketsecurity/lib/debug'
21-
import { safeDelete, safeMkdir } from '@socketsecurity/lib/fs'
2219
import { getDefaultLogger } from '@socketsecurity/lib/logger'
2320
import { normalizePath } from '@socketsecurity/lib/paths/normalize'
2421
import { spawn } from '@socketsecurity/lib/spawn'
2522

2623
import { UPDATE_STORE_DIR } from '../../constants/paths.mts'
27-
import { getOpengrepVersion } from '../../env/opengrep-version.mts'
28-
import { getPyCliVersion } from '../../env/pycli-version.mts'
2924
import { getPythonMajorMinor } from '../../env/python-version.mts'
30-
import { getTrivyVersion } from '../../env/trivy-version.mts'
31-
import { getTrufflehogVersion } from '../../env/trufflehog-version.mts'
3225
import { isSeaBinary } from '../sea/detect.mts'
3326

3427
const logger = getDefaultLogger()
@@ -183,9 +176,11 @@ export async function extractBasicsTools(
183176
logger.group('Validating extracted basics tools...')
184177

185178
const pythonExe = isPlatWin ? 'python3.exe' : 'python3'
186-
const pythonPath = normalizePath(
187-
path.join(extractedPaths.python, 'bin', pythonExe),
188-
)
179+
const pythonDir = extractedPaths['python']
180+
if (!pythonDir) {
181+
throw new Error('Python extraction path not found')
182+
}
183+
const pythonPath = normalizePath(path.join(pythonDir, 'bin', pythonExe))
189184

190185
const validateResult = await spawn(pythonPath, ['--version'], {
191186
stdio: 'pipe',
@@ -226,7 +221,7 @@ export async function extractBasicsTools(
226221

227222
logger.success('Basics tools extracted and validated')
228223
// Return the Python directory path for backward compatibility.
229-
return extractedPaths.python
224+
return extractedPaths['python'] ?? null
230225
} catch (e) {
231226
logger.error('VFS extraction failed')
232227
throw e

packages/cli/src/utils/dlx/vfs-extract.mts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,13 @@ import { isSeaBinary } from '../sea/detect.mts'
7979
const logger = getDefaultLogger()
8080

8181
// External tool names bundled in VFS.
82-
// Currently only includes standalone binaries that are packaged in the VFS tarball.
83-
// npm packages (cdxgen, coana, socket-patch, synp) will be added in future updates.
82+
// Includes standalone binaries and npm packages that are packaged in the VFS tarball.
8483
export const EXTERNAL_TOOLS = [
84+
'cdxgen',
85+
'coana',
8586
'sfw',
87+
'socket-patch',
88+
'synp',
8689
] as const
8790

8891
export type ExternalTool = (typeof EXTERNAL_TOOLS)[number]

pnpm-lock.yaml

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

0 commit comments

Comments
 (0)