@@ -7,6 +7,15 @@ vi.mock("os", () => ({
77 userInfo : vi . fn ( ( ) => ( { shell : null } ) ) ,
88} ) )
99
10+ // Mock path module for testing
11+ vi . mock ( "path" , async ( ) => {
12+ const actual = await vi . importActual ( "path" )
13+ return {
14+ ...actual ,
15+ normalize : vi . fn ( ( p : string ) => p ) ,
16+ }
17+ } )
18+
1019describe ( "Shell Detection Tests" , ( ) => {
1120 let originalPlatform : string
1221 let originalEnv : NodeJS . ProcessEnv
@@ -106,18 +115,25 @@ describe("Shell Detection Tests", () => {
106115 expect ( getShell ( ) ) . toBe ( "C:\\Windows\\System32\\cmd.exe" )
107116 } )
108117
109- it ( "respects userInfo() if no VS Code config is available" , ( ) => {
118+ it ( "respects userInfo() if no VS Code config is available and shell is allowed" , ( ) => {
119+ vscode . workspace . getConfiguration = ( ) => ( { get : ( ) => undefined } ) as any
120+ vi . mocked ( userInfo ) . mockReturnValue ( { shell : "C:\\Program Files\\PowerShell\\7\\pwsh.exe" } as any )
121+
122+ expect ( getShell ( ) ) . toBe ( "C:\\Program Files\\PowerShell\\7\\pwsh.exe" )
123+ } )
124+
125+ it ( "falls back to safe shell when userInfo() returns non-allowlisted shell" , ( ) => {
110126 vscode . workspace . getConfiguration = ( ) => ( { get : ( ) => undefined } ) as any
111127 vi . mocked ( userInfo ) . mockReturnValue ( { shell : "C:\\Custom\\PowerShell.exe" } as any )
112128
113- expect ( getShell ( ) ) . toBe ( "C:\\Custom\\PowerShell .exe" )
129+ expect ( getShell ( ) ) . toBe ( "C:\\Windows\\System32\\cmd .exe" )
114130 } )
115131
116- it ( "respects an odd COMSPEC if no userInfo shell is available " , ( ) => {
132+ it ( "falls back to safe shell when COMSPEC is non-allowlisted " , ( ) => {
117133 vscode . workspace . getConfiguration = ( ) => ( { get : ( ) => undefined } ) as any
118134 process . env . COMSPEC = "D:\\CustomCmd\\cmd.exe"
119135
120- expect ( getShell ( ) ) . toBe ( "D :\\CustomCmd \\cmd.exe" )
136+ expect ( getShell ( ) ) . toBe ( "C :\\Windows\\System32 \\cmd.exe" )
121137 } )
122138 } )
123139
@@ -191,10 +207,10 @@ describe("Shell Detection Tests", () => {
191207 // Unknown Platform & Error Handling
192208 // --------------------------------------------------------------------------
193209 describe ( "Unknown Platform / Error Handling" , ( ) => {
194- it ( "falls back to /bin/sh for unknown platforms" , ( ) => {
210+ it ( "falls back to /bin/bash for unknown platforms" , ( ) => {
195211 Object . defineProperty ( process , "platform" , { value : "sunos" } )
196212 vscode . workspace . getConfiguration = ( ) => ( { get : ( ) => undefined } ) as any
197- expect ( getShell ( ) ) . toBe ( "/bin/sh " )
213+ expect ( getShell ( ) ) . toBe ( "/bin/bash " )
198214 } )
199215
200216 it ( "handles VS Code config errors gracefully, falling back to userInfo shell if present" , ( ) => {
@@ -228,4 +244,90 @@ describe("Shell Detection Tests", () => {
228244 expect ( getShell ( ) ) . toBe ( "/bin/bash" )
229245 } )
230246 } )
247+
248+ // --------------------------------------------------------------------------
249+ // Shell Validation Tests
250+ // --------------------------------------------------------------------------
251+ describe ( "Shell Validation" , ( ) => {
252+ it ( "should allow common Windows shells" , ( ) => {
253+ Object . defineProperty ( process , "platform" , { value : "win32" } )
254+ mockVsCodeConfig ( "windows" , "PowerShell" , {
255+ PowerShell : { path : "C:\\Program Files\\PowerShell\\7\\pwsh.exe" } ,
256+ } )
257+ expect ( getShell ( ) ) . toBe ( "C:\\Program Files\\PowerShell\\7\\pwsh.exe" )
258+ } )
259+
260+ it ( "should allow common Unix shells" , ( ) => {
261+ Object . defineProperty ( process , "platform" , { value : "linux" } )
262+ mockVsCodeConfig ( "linux" , "CustomProfile" , {
263+ CustomProfile : { path : "/usr/bin/fish" } ,
264+ } )
265+ expect ( getShell ( ) ) . toBe ( "/usr/bin/fish" )
266+ } )
267+
268+ it ( "should handle case-insensitive matching on Windows" , ( ) => {
269+ Object . defineProperty ( process , "platform" , { value : "win32" } )
270+ mockVsCodeConfig ( "windows" , "PowerShell" , {
271+ PowerShell : { path : "c:\\windows\\system32\\cmd.exe" } ,
272+ } )
273+ expect ( getShell ( ) ) . toBe ( "c:\\windows\\system32\\cmd.exe" )
274+ } )
275+
276+ it ( "should reject unknown shells and use fallback" , ( ) => {
277+ Object . defineProperty ( process , "platform" , { value : "linux" } )
278+ mockVsCodeConfig ( "linux" , "CustomProfile" , {
279+ CustomProfile : { path : "/usr/bin/malicious-shell" } ,
280+ } )
281+ expect ( getShell ( ) ) . toBe ( "/bin/bash" )
282+ } )
283+
284+ it ( "should validate shells from VS Code config" , ( ) => {
285+ Object . defineProperty ( process , "platform" , { value : "darwin" } )
286+ mockVsCodeConfig ( "osx" , "MyCustomShell" , {
287+ MyCustomShell : { path : "/usr/local/bin/custom-shell" } ,
288+ } )
289+
290+ const result = getShell ( )
291+ expect ( result ) . toBe ( "/bin/zsh" ) // macOS fallback
292+ } )
293+
294+ it ( "should validate shells from userInfo" , ( ) => {
295+ Object . defineProperty ( process , "platform" , { value : "linux" } )
296+ vscode . workspace . getConfiguration = ( ) => ( { get : ( ) => undefined } ) as any
297+ vi . mocked ( userInfo ) . mockReturnValue ( { shell : "/usr/bin/evil-shell" } as any )
298+
299+ const result = getShell ( )
300+ expect ( result ) . toBe ( "/bin/bash" ) // Linux fallback
301+ } )
302+
303+ it ( "should validate shells from environment variables" , ( ) => {
304+ Object . defineProperty ( process , "platform" , { value : "linux" } )
305+ vscode . workspace . getConfiguration = ( ) => ( { get : ( ) => undefined } ) as any
306+ vi . mocked ( userInfo ) . mockReturnValue ( { shell : null } as any )
307+ process . env . SHELL = "/opt/custom/shell"
308+
309+ const result = getShell ( )
310+ expect ( result ) . toBe ( "/bin/bash" ) // Linux fallback
311+ } )
312+
313+ it ( "should handle WSL bash correctly" , ( ) => {
314+ Object . defineProperty ( process , "platform" , { value : "win32" } )
315+ mockVsCodeConfig ( "windows" , "WSL" , {
316+ WSL : { source : "WSL" } ,
317+ } )
318+
319+ const result = getShell ( )
320+ expect ( result ) . toBe ( "/bin/bash" ) // Should be allowed
321+ } )
322+
323+ it ( "should handle empty or null shell paths" , ( ) => {
324+ Object . defineProperty ( process , "platform" , { value : "linux" } )
325+ vscode . workspace . getConfiguration = ( ) => ( { get : ( ) => undefined } ) as any
326+ vi . mocked ( userInfo ) . mockReturnValue ( { shell : "" } as any )
327+ delete process . env . SHELL
328+
329+ const result = getShell ( )
330+ expect ( result ) . toBe ( "/bin/bash" ) // Should fall back to safe default
331+ } )
332+ } )
231333} )
0 commit comments