@@ -10,6 +10,7 @@ import (
1010 "testing"
1111 "time"
1212
13+ "github.com/Microsoft/hcsshim/pkg/annotations"
1314 "github.com/containerd/errdefs"
1415 "github.com/opencontainers/runtime-spec/specs-go"
1516)
@@ -322,96 +323,153 @@ func Test_hcsTask_DeleteExec_2ndExecID_ExitedState_Success(t *testing.T) {
322323}
323324
324325func Test_handleProcessArgsForIsolatedJobContainer (t * testing.T ) {
326+ ntAuthorityUser := `NT AUTHORITY\SYSTEM`
327+ testUserName := "testUser"
328+
325329 tests := []struct {
326- name string
327- specs * specs.Process
328- expectedCmdLine string
329- expectedArgs []string
330+ name string
331+ taskAnnotations map [string ]string
332+ specs * specs.Process
333+ expectedCmdLine string
334+ expectedArgs []string
335+ initialUsername string
336+ expectedUsername string
330337 }{
331338 {
332339 name : "CommandLine starts with 'cmd' (lowercase) – unchanged" ,
333340 specs : & specs.Process {CommandLine : "cmd /c dir" },
334341 expectedCmdLine : "cmd /c dir" ,
335- expectedArgs : nil ,
336342 },
337343 {
338344 name : "CommandLine starts with 'CMD' (uppercase) – unchanged" ,
339345 specs : & specs.Process {CommandLine : "CMD /C whoami" },
340346 expectedCmdLine : "CMD /C whoami" ,
341- expectedArgs : nil ,
342347 },
343348 {
344349 name : "CommandLine starts with 'cmd.exe' – unchanged" ,
345350 specs : & specs.Process {CommandLine : "cmd.exe /c ipconfig" },
346351 expectedCmdLine : "cmd.exe /c ipconfig" ,
347- expectedArgs : nil ,
348352 },
349353 {
350354 name : "CommandLine plain – gets prefixed with 'cmd /c '" ,
351355 specs : & specs.Process {CommandLine : "echo hello" },
352356 expectedCmdLine : "cmd /c echo hello" ,
353- expectedArgs : nil ,
354357 },
355358 {
356359 name : "CommandLine mixed case 'CmD' – unchanged" ,
357360 specs : & specs.Process {CommandLine : "CmD /c ping 127.0.0.1" },
358361 expectedCmdLine : "CmD /c ping 127.0.0.1" ,
359- expectedArgs : nil ,
360362 },
361363 {
362- name : "Args plain – gets ['cmd','/c',...] prefix" ,
363- specs : & specs.Process {Args : []string {"echo" , "hello" }},
364- expectedCmdLine : "" ,
365- expectedArgs : []string {"cmd" , "/c" , "echo" , "hello" },
364+ name : "CommandLine has leading spaces before 'cmd' – unchanged" ,
365+ specs : & specs.Process {CommandLine : " cmd /c echo spaced" },
366+ expectedCmdLine : " cmd /c echo spaced" ,
366367 },
367368 {
368- name : "Args already start with 'CMD' (uppercase) – unchanged" ,
369- specs : & specs.Process {Args : []string {"CMD" , "/C" , "echo" , "hi" }},
370- expectedCmdLine : "" ,
371- expectedArgs : []string {"CMD" , "/C" , "echo" , "hi" },
369+ name : "CommandLine has leading spaces before 'CMD' – unchanged" ,
370+ specs : & specs.Process {CommandLine : " CMD /C echo spaced" },
371+ expectedCmdLine : " CMD /C echo spaced" ,
372372 },
373373 {
374- name : "Args already start with 'cmd' (lowercase) – unchanged" ,
375- specs : & specs.Process {Args : []string {"cmd" , "/c" , "type" , "file.txt" }},
376- expectedCmdLine : "" ,
377- expectedArgs : []string {"cmd" , "/c" , "type" , "file.txt" },
374+ name : "CommandLine whitespace-only – gets prefixed preserving spaces" ,
375+ specs : & specs.Process {CommandLine : " " },
376+ expectedCmdLine : "cmd /c " ,
377+ },
378+ {
379+ name : "Args plain – gets ['cmd','/c',...] prefix" ,
380+ specs : & specs.Process {Args : []string {"echo" , "hello" }},
381+ expectedArgs : []string {"cmd" , "/c" , "echo" , "hello" },
382+ },
383+ {
384+ name : "Args already start with 'CMD' (uppercase) – unchanged" ,
385+ specs : & specs.Process {Args : []string {"CMD" , "/C" , "echo" , "hi" }},
386+ expectedArgs : []string {"CMD" , "/C" , "echo" , "hi" },
387+ },
388+ {
389+ name : "Args already start with 'cmd' (lowercase) – unchanged" ,
390+ specs : & specs.Process {Args : []string {"cmd" , "/c" , "type" , "file.txt" }},
391+ expectedArgs : []string {"cmd" , "/c" , "type" , "file.txt" },
392+ },
393+ {
394+ name : "Args first element mixed case 'Cmd' – unchanged" ,
395+ specs : & specs.Process {Args : []string {"Cmd" , "/c" , "echo" , "hi" }},
396+ expectedArgs : []string {"Cmd" , "/c" , "echo" , "hi" },
397+ },
398+ {
399+ name : "Args first element has leading/trailing spaces ' CMD ' – unchanged (trimmed comparison)" ,
400+ specs : & specs.Process {Args : []string {" CMD " , "/C" , "echo" , "trimmed" }},
401+ expectedArgs : []string {" CMD " , "/C" , "echo" , "trimmed" },
378402 },
379403 {
380404 name : "Empty CommandLine and empty Args – unchanged" ,
381405 specs : & specs.Process {},
382406 expectedCmdLine : "" ,
383- expectedArgs : nil ,
384407 },
385408 {
386409 name : "Empty CommandLine and empty slice Args – unchanged (empty slice preserved)" ,
387410 specs : & specs.Process {Args : []string {}},
388411 expectedCmdLine : "" ,
389412 expectedArgs : []string {},
390413 },
414+ // --- User inheritance behavior ---
391415 {
392- name : "CommandLine has leading spaces before 'cmd' – treated as not starting with cmd - unchanged " ,
393- specs : & specs. Process { CommandLine : " cmd /c echo spaced " },
394- expectedCmdLine : " cmd /c echo spaced" ,
395- expectedArgs : nil ,
416+ name : "HostProcessInheritUser=true – sets Username to NT AUTHORITY \\ SYSTEM " ,
417+ taskAnnotations : map [ string ] string { annotations . HostProcessInheritUser : "true " },
418+ specs : & specs. Process {} ,
419+ expectedUsername : ntAuthorityUser ,
396420 },
397421 {
398- name : "Args first element mixed case 'Cmd' – unchanged" ,
399- specs : & specs.Process {Args : []string {"Cmd" , "/c" , "echo" , "hi" }},
400- expectedCmdLine : "" ,
401- expectedArgs : []string {"Cmd" , "/c" , "echo" , "hi" },
422+ name : "HostProcessInheritUser=false – does not set Username" ,
423+ taskAnnotations : map [string ]string {annotations .HostProcessInheritUser : "false" },
424+ specs : & specs.Process {User : specs.User {Username : testUserName }},
425+ expectedUsername : testUserName ,
426+ },
427+ {
428+ name : "HostProcessInheritUser missing – does not set Username" ,
429+ taskAnnotations : map [string ]string {},
430+ specs : & specs.Process {User : specs.User {Username : testUserName }},
431+ expectedUsername : testUserName ,
432+ },
433+ {
434+ name : "HostProcessInheritUser=true – overrides preexisting Username" ,
435+ taskAnnotations : map [string ]string {annotations .HostProcessInheritUser : "true" },
436+ specs : & specs.Process {User : specs.User {Username : testUserName }},
437+ expectedUsername : ntAuthorityUser ,
438+ },
439+ {
440+ name : "HostProcessInheritUser=false – preserves preexisting Username" ,
441+ taskAnnotations : map [string ]string {annotations .HostProcessInheritUser : "false" },
442+ specs : & specs.Process {User : specs.User {Username : testUserName }},
443+ expectedUsername : testUserName ,
444+ },
445+ {
446+ name : "Nil annotation map – safely no change to Username" ,
447+ // Note: Annotations=nil is fine; indexing a nil map returns zero value
448+ taskAnnotations : nil ,
449+ specs : & specs.Process {User : specs.User {Username : testUserName }},
450+ expectedUsername : testUserName ,
402451 },
403452 }
404453
405454 for _ , tt := range tests {
406455 t .Run (tt .name , func (t * testing.T ) {
407- handleProcessArgsForIsolatedJobContainer (tt .specs )
456+ taskSpec := & specs.Spec {Annotations : tt .taskAnnotations }
457+ // Ensure initial Username is set if provided
458+ if tt .initialUsername != "" {
459+ tt .specs .User .Username = tt .initialUsername
460+ }
461+
462+ handleProcessArgsForIsolatedJobContainer (taskSpec , tt .specs )
408463
409464 if tt .specs .CommandLine != tt .expectedCmdLine {
410465 t .Errorf ("CommandLine mismatch: got: %q want: %q" , tt .specs .CommandLine , tt .expectedCmdLine )
411466 }
412467 if ! reflect .DeepEqual (tt .specs .Args , tt .expectedArgs ) {
413468 t .Errorf ("Args mismatch: got: %#v want: %#v" , tt .specs .Args , tt .expectedArgs )
414469 }
470+ if tt .specs .User .Username != tt .expectedUsername {
471+ t .Errorf ("Username mismatch: got: %q want: %q" , tt .specs .User .Username , tt .expectedUsername )
472+ }
415473 })
416474 }
417475}
0 commit comments