Skip to content

Commit 190b8b6

Browse files
committed
fix(build): externalize Socket dependencies and add bundle validation test
- Add @socketsecurity/lib, @socketsecurity/packageurl-js, and @socketsecurity/sdk to external array in esbuild config to prevent bundling pre-built distributions - Add bundle validation test to detect absolute paths and bundled external dependencies in build output - Set global Socket theme in cli-entry.mts for consistent CLI branding This prevents the second occurrence of hardcoded absolute paths in bundles and ensures future builds are validated automatically.
1 parent 2931b47 commit 190b8b6

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

packages/cli/.config/esbuild.cli.build.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ const config = {
175175
external: [
176176
'node-gyp', // Required for require.resolve('node-gyp/package.json')
177177
'@socketsecurity/registry', // Optional registry package (dev dependency only)
178+
'@socketsecurity/lib', // Referenced by socket-packageurl-js dist
179+
'@socketsecurity/packageurl-js', // Prevent re-bundling dist files
180+
'@socketsecurity/sdk', // Prevent re-bundling dist files
178181
],
179182

180183
// Suppress warnings for intentional CommonJS compatibility code.

packages/cli/src/cli-entry.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
// Load Intl polyfill for --with-intl=none builds.
44
import './polyfills/intl-stub.mts'
55

6+
// Set global Socket theme for consistent CLI branding.
7+
import { setTheme } from '@socketsecurity/lib/themes'
8+
setTheme('socket')
9+
610
import process from 'node:process'
711
import { fileURLToPath, pathToFileURL } from 'node:url'
812

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* @fileoverview Bundle validation tests to ensure build output quality.
3+
* Verifies that dist files don't contain absolute paths or unexpected bundled dependencies.
4+
*/
5+
6+
import { promises as fs } from 'node:fs'
7+
import path from 'node:path'
8+
import { fileURLToPath } from 'node:url'
9+
10+
import { describe, expect, it } from 'vitest'
11+
12+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
13+
const packagePath = path.resolve(__dirname, '..', '..')
14+
const buildPath = path.join(packagePath, 'build')
15+
16+
/**
17+
* Check if content contains absolute paths.
18+
* Detects paths like /Users/, C:\, /home/, etc.
19+
*/
20+
function hasAbsolutePaths(content: string): {
21+
hasIssue: boolean
22+
matches: string[]
23+
} {
24+
// Match absolute paths but exclude URLs and node: protocol.
25+
const patterns = [
26+
// Match require('/abs/path') or require('C:\\path').
27+
/require\(["'](?:\/[^"'\n]+|[A-Z]:\\[^"'\n]+)["']\)/g,
28+
// Match import from '/abs/path'.
29+
/import\s+.*?from\s+["'](?:\/[^"'\n]+|[A-Z]:\\[^"'\n]+)["']/g,
30+
]
31+
32+
const matches: string[] = []
33+
for (const pattern of patterns) {
34+
const found = content.match(pattern)
35+
if (found) {
36+
matches.push(...found)
37+
}
38+
}
39+
40+
return {
41+
hasIssue: matches.length > 0,
42+
matches,
43+
}
44+
}
45+
46+
/**
47+
* Check if content contains bundled code that should be external.
48+
* Looks for signs that dependencies were bundled inline instead of kept external.
49+
*/
50+
function checkForBundledDependencies(content: string): {
51+
bundledDeps: string[]
52+
hasNoBundledDeps: boolean
53+
} {
54+
// Dependencies that should remain external (not bundled inline).
55+
// We check if their package code is bundled by looking for their exports.
56+
const externalDeps = [
57+
{
58+
name: '@socketsecurity/registry',
59+
// Look for characteristic exports from this package.
60+
pattern: /\/\/ @socketsecurity\/registry/,
61+
},
62+
]
63+
64+
const bundledDeps: string[] = []
65+
66+
for (const dep of externalDeps) {
67+
// If we find evidence that the package's code is bundled inline.
68+
if (dep.pattern.test(content)) {
69+
bundledDeps.push(dep.name)
70+
}
71+
}
72+
73+
return {
74+
bundledDeps,
75+
hasNoBundledDeps: bundledDeps.length === 0,
76+
}
77+
}
78+
79+
describe('Bundle validation', () => {
80+
it('should not contain absolute paths in build/cli.js', async () => {
81+
const cliPath = path.join(buildPath, 'cli.js')
82+
const content = await fs.readFile(cliPath, 'utf8')
83+
84+
const result = hasAbsolutePaths(content)
85+
86+
if (result.hasIssue) {
87+
console.error('Found absolute paths in bundle:')
88+
for (const match of result.matches) {
89+
console.error(` - ${match}`)
90+
}
91+
}
92+
93+
expect(
94+
result.hasIssue,
95+
'Bundle should not contain absolute paths',
96+
).toBe(false)
97+
})
98+
99+
it('should not bundle external dependencies inline', async () => {
100+
const cliPath = path.join(buildPath, 'cli.js')
101+
const content = await fs.readFile(cliPath, 'utf8')
102+
103+
const result = checkForBundledDependencies(content)
104+
105+
if (!result.hasNoBundledDeps) {
106+
console.error('Found bundled code from external dependencies:')
107+
for (const dep of result.bundledDeps) {
108+
console.error(` - ${dep}`)
109+
}
110+
}
111+
112+
expect(
113+
result.hasNoBundledDeps,
114+
'External dependencies should not be bundled inline',
115+
).toBe(true)
116+
})
117+
})

0 commit comments

Comments
 (0)