|
1 | | -import { describe, test, expect, beforeEach, afterAll, mock } from 'bun:test' |
2 | | - |
3 | | -// Mock state - these control what the mocked functions return |
4 | | -let mockBwrapInstalled = true |
5 | | -let mockSocatInstalled = true |
6 | | -let mockBpfPath: string | null = null |
7 | | -let mockApplyPath: string | null = null |
8 | | - |
9 | | -// Store original Bun.which to restore later |
10 | | -const originalBunWhich = globalThis.Bun.which |
11 | | - |
12 | | -// Mock Bun.which directly - this avoids mock.module which affects other test files |
13 | | -globalThis.Bun.which = ((bin: string): string | null => { |
14 | | - if (bin === 'bwrap') { |
15 | | - return mockBwrapInstalled ? '/usr/bin/bwrap' : null |
16 | | - } |
17 | | - if (bin === 'socat') { |
18 | | - return mockSocatInstalled ? '/usr/bin/socat' : null |
19 | | - } |
20 | | - // For other binaries, use the original implementation |
21 | | - return originalBunWhich(bin) |
22 | | -}) as typeof globalThis.Bun.which |
23 | | - |
24 | | -// Mock seccomp path functions - controls whether seccomp binaries are "found" |
25 | | -void mock.module('../../src/sandbox/generate-seccomp-filter.js', () => ({ |
26 | | - getPreGeneratedBpfPath: () => mockBpfPath, |
27 | | - getApplySeccompBinaryPath: () => mockApplyPath, |
28 | | - generateSeccompFilter: () => null, |
29 | | - cleanupSeccompFilter: () => {}, |
30 | | -})) |
31 | | - |
32 | | -// Dynamic import AFTER mocking - this is required for mocks to take effect |
33 | | -const { checkLinuxDependencies, getLinuxDependencyStatus } = await import( |
34 | | - '../../src/sandbox/linux-sandbox-utils.js' |
35 | | -) |
36 | | - |
37 | | -// Restore original Bun.which and module mocks after all tests in this file |
38 | | -afterAll(() => { |
39 | | - globalThis.Bun.which = originalBunWhich |
40 | | - mock.restore() |
41 | | -}) |
42 | | - |
43 | | -describe('checkLinuxDependencies', () => { |
44 | | - // Reset all mocks to "everything installed" state before each test |
45 | | - beforeEach(() => { |
46 | | - mockBwrapInstalled = true |
47 | | - mockSocatInstalled = true |
48 | | - mockBpfPath = '/path/to/filter.bpf' |
49 | | - mockApplyPath = '/path/to/apply-seccomp' |
50 | | - }) |
51 | | - |
| 1 | +import { describe, test, expect } from 'bun:test' |
| 2 | +import { |
| 3 | + dependencyStatusToCheck, |
| 4 | + type LinuxDependencyStatus, |
| 5 | +} from '../../src/sandbox/linux-sandbox-utils.js' |
| 6 | + |
| 7 | +const allPresent: LinuxDependencyStatus = { |
| 8 | + hasBwrap: true, |
| 9 | + hasSocat: true, |
| 10 | + hasSeccompBpf: true, |
| 11 | + hasSeccompApply: true, |
| 12 | +} |
| 13 | + |
| 14 | +describe('dependencyStatusToCheck', () => { |
52 | 15 | test('returns no errors or warnings when all dependencies present', () => { |
53 | | - const result = checkLinuxDependencies() |
| 16 | + const result = dependencyStatusToCheck(allPresent) |
54 | 17 |
|
55 | 18 | expect(result.errors).toEqual([]) |
56 | 19 | expect(result.warnings).toEqual([]) |
57 | 20 | }) |
58 | 21 |
|
59 | 22 | test('returns error when bwrap missing', () => { |
60 | | - mockBwrapInstalled = false |
61 | | - |
62 | | - const result = checkLinuxDependencies() |
| 23 | + const result = dependencyStatusToCheck({ ...allPresent, hasBwrap: false }) |
63 | 24 |
|
64 | | - expect(result.errors).toContain('bubblewrap (bwrap) not installed') |
65 | | - expect(result.errors.length).toBe(1) |
| 25 | + expect(result.errors).toEqual(['bubblewrap (bwrap) not installed']) |
| 26 | + expect(result.warnings).toEqual([]) |
66 | 27 | }) |
67 | 28 |
|
68 | 29 | test('returns error when socat missing', () => { |
69 | | - mockSocatInstalled = false |
70 | | - |
71 | | - const result = checkLinuxDependencies() |
| 30 | + const result = dependencyStatusToCheck({ ...allPresent, hasSocat: false }) |
72 | 31 |
|
73 | | - expect(result.errors).toContain('socat not installed') |
74 | | - expect(result.errors.length).toBe(1) |
| 32 | + expect(result.errors).toEqual(['socat not installed']) |
| 33 | + expect(result.warnings).toEqual([]) |
75 | 34 | }) |
76 | 35 |
|
77 | 36 | test('returns multiple errors when both bwrap and socat missing', () => { |
78 | | - mockBwrapInstalled = false |
79 | | - mockSocatInstalled = false |
80 | | - |
81 | | - const result = checkLinuxDependencies() |
| 37 | + const result = dependencyStatusToCheck({ |
| 38 | + ...allPresent, |
| 39 | + hasBwrap: false, |
| 40 | + hasSocat: false, |
| 41 | + }) |
82 | 42 |
|
83 | 43 | expect(result.errors).toContain('bubblewrap (bwrap) not installed') |
84 | 44 | expect(result.errors).toContain('socat not installed') |
85 | 45 | expect(result.errors.length).toBe(2) |
86 | 46 | }) |
87 | 47 |
|
88 | | - test('returns warning (not error) when seccomp missing', () => { |
89 | | - mockBpfPath = null |
90 | | - mockApplyPath = null |
91 | | - |
92 | | - const result = checkLinuxDependencies() |
| 48 | + test('returns warning (not error) when seccomp bpf missing', () => { |
| 49 | + const result = dependencyStatusToCheck({ |
| 50 | + ...allPresent, |
| 51 | + hasSeccompBpf: false, |
| 52 | + }) |
93 | 53 |
|
94 | | - expect(result.warnings).toContain( |
| 54 | + expect(result.errors).toEqual([]) |
| 55 | + expect(result.warnings).toEqual([ |
95 | 56 | 'seccomp not available - unix socket access not restricted', |
96 | | - ) |
| 57 | + ]) |
97 | 58 | }) |
98 | 59 |
|
99 | | - test('returns warning when only bpf file present (no apply binary)', () => { |
100 | | - mockBpfPath = '/path/to/filter.bpf' |
101 | | - mockApplyPath = null |
102 | | - |
103 | | - const result = checkLinuxDependencies() |
| 60 | + test('returns warning when seccomp apply binary missing', () => { |
| 61 | + const result = dependencyStatusToCheck({ |
| 62 | + ...allPresent, |
| 63 | + hasSeccompApply: false, |
| 64 | + }) |
104 | 65 |
|
105 | 66 | expect(result.errors).toEqual([]) |
106 | | - expect(result.warnings.length).toBe(1) |
| 67 | + expect(result.warnings).toEqual([ |
| 68 | + 'seccomp not available - unix socket access not restricted', |
| 69 | + ]) |
107 | 70 | }) |
108 | 71 |
|
109 | | - // This verifies the config parameter is actually passed through |
110 | | - test('uses custom seccomp paths when provided', () => { |
111 | | - // Default paths return null (not found) |
112 | | - mockBpfPath = null |
113 | | - mockApplyPath = null |
114 | | - |
115 | | - // But we're passing custom paths - the mock ignores them, |
116 | | - // so this still returns warnings. The point is it doesn't crash |
117 | | - // and the structure is correct. Real path validation happens in the mock. |
118 | | - const result = checkLinuxDependencies({ |
119 | | - bpfPath: '/custom/path.bpf', |
120 | | - applyPath: '/custom/apply', |
| 72 | + test('returns single warning when both seccomp pieces missing', () => { |
| 73 | + const result = dependencyStatusToCheck({ |
| 74 | + ...allPresent, |
| 75 | + hasSeccompBpf: false, |
| 76 | + hasSeccompApply: false, |
121 | 77 | }) |
122 | 78 |
|
123 | | - expect(Array.isArray(result.errors)).toBe(true) |
124 | | - expect(Array.isArray(result.warnings)).toBe(true) |
125 | | - }) |
126 | | -}) |
127 | | - |
128 | | -describe('getLinuxDependencyStatus', () => { |
129 | | - beforeEach(() => { |
130 | | - mockBwrapInstalled = true |
131 | | - mockSocatInstalled = true |
132 | | - mockBpfPath = '/path/to/filter.bpf' |
133 | | - mockApplyPath = '/path/to/apply-seccomp' |
134 | | - }) |
135 | | - |
136 | | - // All deps installed = all flags true |
137 | | - test('reports all available when everything installed', () => { |
138 | | - const status = getLinuxDependencyStatus() |
139 | | - |
140 | | - expect(status.hasBwrap).toBe(true) |
141 | | - expect(status.hasSocat).toBe(true) |
142 | | - expect(status.hasSeccompBpf).toBe(true) |
143 | | - expect(status.hasSeccompApply).toBe(true) |
144 | | - }) |
145 | | - |
146 | | - // Each missing dep should show as false independently |
147 | | - test('reports bwrap unavailable when not installed', () => { |
148 | | - mockBwrapInstalled = false |
149 | | - |
150 | | - const status = getLinuxDependencyStatus() |
151 | | - |
152 | | - expect(status.hasBwrap).toBe(false) |
153 | | - expect(status.hasSocat).toBe(true) // others unaffected |
154 | | - }) |
155 | | - |
156 | | - test('reports socat unavailable when not installed', () => { |
157 | | - mockSocatInstalled = false |
158 | | - |
159 | | - const status = getLinuxDependencyStatus() |
160 | | - |
161 | | - expect(status.hasSocat).toBe(false) |
162 | | - expect(status.hasBwrap).toBe(true) // others unaffected |
| 79 | + expect(result.errors).toEqual([]) |
| 80 | + expect(result.warnings.length).toBe(1) |
163 | 81 | }) |
164 | 82 |
|
165 | | - test('reports seccomp unavailable when files missing', () => { |
166 | | - mockBpfPath = null |
167 | | - mockApplyPath = null |
168 | | - |
169 | | - const status = getLinuxDependencyStatus() |
| 83 | + test('reports both errors and warnings when everything missing', () => { |
| 84 | + const result = dependencyStatusToCheck({ |
| 85 | + hasBwrap: false, |
| 86 | + hasSocat: false, |
| 87 | + hasSeccompBpf: false, |
| 88 | + hasSeccompApply: false, |
| 89 | + }) |
170 | 90 |
|
171 | | - expect(status.hasSeccompBpf).toBe(false) |
172 | | - expect(status.hasSeccompApply).toBe(false) |
173 | | - expect(status.hasBwrap).toBe(true) // others unaffected |
174 | | - expect(status.hasSocat).toBe(true) |
| 91 | + expect(result.errors.length).toBe(2) |
| 92 | + expect(result.warnings.length).toBe(1) |
175 | 93 | }) |
176 | 94 | }) |
0 commit comments