@@ -361,4 +361,132 @@ describe("shell utilities", () => {
361361 expect ( result ) . toBe ( "C:\\Windows\\System32\\cmd.exe" )
362362 } )
363363 } )
364+
365+ describe ( "validateShellPath" , ( ) => {
366+ it ( "should validate string shell paths" , async ( ) => {
367+ const { validateShellPath } = await import ( "../shell" )
368+
369+ // Valid shells
370+ expect ( validateShellPath ( "/bin/bash" ) ) . toBe ( true )
371+ expect ( validateShellPath ( "/bin/zsh" ) ) . toBe ( true )
372+ expect ( validateShellPath ( "C:\\Windows\\System32\\cmd.exe" ) ) . toBe ( true )
373+ expect ( validateShellPath ( "C:\\Program Files\\PowerShell\\7\\pwsh.exe" ) ) . toBe ( true )
374+
375+ // Invalid shells
376+ expect ( validateShellPath ( "/usr/bin/malicious" ) ) . toBe ( false )
377+ expect ( validateShellPath ( "C:\\malicious\\shell.exe" ) ) . toBe ( false )
378+ } )
379+
380+ it ( "should validate array shell paths using first element" , async ( ) => {
381+ const { validateShellPath } = await import ( "../shell" )
382+
383+ // Valid array with allowed first element
384+ expect ( validateShellPath ( [ "/bin/bash" , "/bin/sh" ] ) ) . toBe ( true )
385+ expect ( validateShellPath ( [ "C:\\Windows\\System32\\cmd.exe" , "cmd" ] ) ) . toBe ( true )
386+
387+ // Invalid array with disallowed first element
388+ expect ( validateShellPath ( [ "/usr/bin/malicious" , "/bin/bash" ] ) ) . toBe ( false )
389+ expect ( validateShellPath ( [ "C:\\malicious\\shell.exe" , "C:\\Windows\\System32\\cmd.exe" ] ) ) . toBe ( false )
390+ } )
391+
392+ it ( "should handle empty arrays" , async ( ) => {
393+ const { validateShellPath } = await import ( "../shell" )
394+
395+ expect ( validateShellPath ( [ ] ) ) . toBe ( false )
396+ } )
397+
398+ it ( "should handle null and undefined" , async ( ) => {
399+ const { validateShellPath } = await import ( "../shell" )
400+
401+ expect ( validateShellPath ( null ) ) . toBe ( false )
402+ expect ( validateShellPath ( undefined ) ) . toBe ( false )
403+ } )
404+
405+ it ( "should handle nested arrays (edge case)" , async ( ) => {
406+ const { validateShellPath } = await import ( "../shell" )
407+
408+ // Nested array - should recursively check first element
409+ expect ( validateShellPath ( [ [ "/bin/bash" ] ] as any ) ) . toBe ( true )
410+ expect ( validateShellPath ( [ [ "/usr/bin/malicious" ] ] as any ) ) . toBe ( false )
411+ expect ( validateShellPath ( [ [ "C:\\Windows\\System32\\cmd.exe" ] ] as any ) ) . toBe ( true )
412+ } )
413+
414+ it ( "should handle empty strings" , async ( ) => {
415+ const { validateShellPath } = await import ( "../shell" )
416+
417+ expect ( validateShellPath ( "" ) ) . toBe ( false )
418+ expect ( validateShellPath ( [ "" ] ) ) . toBe ( false )
419+ } )
420+
421+ it ( "should handle case-insensitive comparison on Windows" , async ( ) => {
422+ // Set platform to Windows
423+ Object . defineProperty ( process , "platform" , {
424+ value : "win32" ,
425+ configurable : true ,
426+ } )
427+
428+ const { validateShellPath } = await import ( "../shell" )
429+
430+ // Different case variations should all be valid
431+ expect ( validateShellPath ( "c:\\windows\\system32\\cmd.exe" ) ) . toBe ( true )
432+ expect ( validateShellPath ( "C:\\WINDOWS\\SYSTEM32\\CMD.EXE" ) ) . toBe ( true )
433+ expect ( validateShellPath ( "C:\\Windows\\System32\\CMD.exe" ) ) . toBe ( true )
434+ } )
435+
436+ it ( "should handle case-sensitive comparison on Unix" , async ( ) => {
437+ // Set platform to Linux
438+ Object . defineProperty ( process , "platform" , {
439+ value : "linux" ,
440+ configurable : true ,
441+ } )
442+
443+ const { validateShellPath } = await import ( "../shell" )
444+
445+ // Exact case match required
446+ expect ( validateShellPath ( "/bin/bash" ) ) . toBe ( true )
447+ expect ( validateShellPath ( "/BIN/BASH" ) ) . toBe ( false )
448+ expect ( validateShellPath ( "/Bin/Bash" ) ) . toBe ( false )
449+ } )
450+
451+ it ( "should normalize paths before validation" , async ( ) => {
452+ const { validateShellPath } = await import ( "../shell" )
453+
454+ // Paths with extra slashes or dots should be normalized
455+ expect ( validateShellPath ( "/bin//bash" ) ) . toBe ( true )
456+ expect ( validateShellPath ( "/bin/./bash" ) ) . toBe ( true )
457+
458+ // Windows paths with backslashes
459+ if ( process . platform === "win32" ) {
460+ expect ( validateShellPath ( "C:/Windows/System32/cmd.exe" ) ) . toBe ( true )
461+ }
462+ } )
463+
464+ it ( "should handle arrays with mixed valid and invalid paths" , async ( ) => {
465+ const { validateShellPath } = await import ( "../shell" )
466+
467+ // Only the first element matters
468+ expect ( validateShellPath ( [ "/bin/bash" , "/usr/bin/malicious" , "/bin/sh" ] ) ) . toBe ( true )
469+ expect ( validateShellPath ( [ "/usr/bin/malicious" , "/bin/bash" , "/bin/sh" ] ) ) . toBe ( false )
470+ } )
471+
472+ it ( "should reject non-string, non-array types" , async ( ) => {
473+ const { validateShellPath } = await import ( "../shell" )
474+
475+ // Numbers, objects, etc. should be rejected
476+ expect ( validateShellPath ( 123 as any ) ) . toBe ( false )
477+ expect ( validateShellPath ( { path : "/bin/bash" } as any ) ) . toBe ( false )
478+ expect ( validateShellPath ( true as any ) ) . toBe ( false )
479+ } )
480+
481+ it ( "should handle arrays containing non-string elements" , async ( ) => {
482+ const { validateShellPath } = await import ( "../shell" )
483+
484+ // Array with null/undefined first element
485+ expect ( validateShellPath ( [ null , "/bin/bash" ] as any ) ) . toBe ( false )
486+ expect ( validateShellPath ( [ undefined , "/bin/bash" ] as any ) ) . toBe ( false )
487+
488+ // Array with number first element
489+ expect ( validateShellPath ( [ 123 , "/bin/bash" ] as any ) ) . toBe ( false )
490+ } )
491+ } )
364492} )
0 commit comments