Skip to content

Commit 399bba9

Browse files
committed
Added unit tests for updateConfigForHostProcessContainer method
This commit adds thorough unit tests for the updateConfigForHostProcessContainer method. We test the following functionality- - Reject privileged container in unprivileged sandbox (isolated HPC) — return error when container requests microsoft.com/hostprocess-container=true but the pod lacks it. - Allow privileged container in privileged sandbox (isolated HPC) — ensure no unexpected mutations when no passthrough annotations are present. - Block normal process-isolated container in process-isolated HPC pod — enforce constraint that all containers in a process HPC pod must also be job containers (error on mixing). - Allow normal hypervisor-isolated container in hypervisor-isolated HPC pod. - Passthrough annotations to privileged containers — propagate HostProcessInheritUser and HostProcessRootfsLocation from pod → container for: hypervisor-isolated HPC pods with privileged containers, and process-isolated HPC pods with privileged containers. - No passthrough for normal containers — verify annotations aren’t propagated when the container is non-privileged. - Set SYSTEM user for hypervisor-isolated privileged containers — when HostProcessInheritUser=true, set Process.User.Username to NT AUTHORITY\SYSTEM. - Do not change user for normal containers — ensure container user remains unchanged even if the pod has HostProcessInheritUser=true. - Force HostProcessInheritUser to "false" for normal containers — in hypervisor-isolated privileged pods, if a non-privileged container sets the inherit annotation, flip it to "false".
1 parent fc45ea3 commit 399bba9

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed

cmd/containerd-shim-runhcs-v1/pod_test.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import (
66
"context"
77
"fmt"
88
"math/rand"
9+
"reflect"
910
"strconv"
1011
"sync"
1112
"testing"
1213

14+
"github.com/Microsoft/hcsshim/pkg/annotations"
1315
task "github.com/containerd/containerd/api/runtime/task/v2"
1416
"github.com/containerd/errdefs"
1517
specs "github.com/opencontainers/runtime-spec/specs-go"
@@ -388,3 +390,174 @@ func Test_pod_DeleteTask_TaskID_Not_Created(t *testing.T) {
388390
err := p.KillTask(context.Background(), strconv.Itoa(rand.Int()), "", 0xf, true)
389391
verifyExpectedError(t, nil, err, errdefs.ErrNotFound)
390392
}
393+
394+
func getWCOWSpecsWithAnnotations(annotation map[string]string, isIsolated bool, processUser string) *specs.Spec {
395+
spec := &specs.Spec{
396+
Windows: &specs.Windows{},
397+
Annotations: annotation,
398+
Process: &specs.Process{
399+
User: specs.User{Username: processUser},
400+
},
401+
}
402+
403+
if isIsolated {
404+
spec.Windows.HyperV = &specs.WindowsHyperV{}
405+
}
406+
return spec
407+
}
408+
409+
func Test_pod_UpdateConfigForHostProcessContainer(t *testing.T) {
410+
ntAuthorityUser := `NT AUTHORITY\SYSTEM`
411+
412+
testCases := []struct {
413+
testName string
414+
podSpec *specs.Spec
415+
containerSpec *specs.Spec
416+
expectedContainerSpec *specs.Spec
417+
expectedError string
418+
}{
419+
{
420+
testName: "privileged container in unprivileged pod (isolated hpc)",
421+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{}, true, ""),
422+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{
423+
annotations.HostProcessContainer: "true",
424+
}, true, ""),
425+
expectedContainerSpec: nil,
426+
expectedError: "cannot create a host process container inside sandbox which has missing annotation: microsoft.com/hostprocess-container",
427+
},
428+
{
429+
testName: "privileged container in privileged pod (isolated hpc)",
430+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
431+
annotations.HostProcessContainer: "true",
432+
}, true, ""),
433+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{
434+
annotations.HostProcessContainer: "true",
435+
}, true, ""),
436+
expectedContainerSpec: getWCOWSpecsWithAnnotations(map[string]string{
437+
annotations.HostProcessContainer: "true",
438+
}, true, ""),
439+
expectedError: "",
440+
},
441+
{
442+
testName: "normal container in privileged pod (process hpc)",
443+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
444+
annotations.HostProcessContainer: "true",
445+
}, false, ""),
446+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{}, false, ""),
447+
expectedContainerSpec: nil,
448+
expectedError: "cannot create a normal process isolated container if the pod sandbox is a job container running on host",
449+
},
450+
{
451+
testName: "normal container in privileged pod (isolated hpc)",
452+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
453+
annotations.HostProcessContainer: "true",
454+
}, true, ""),
455+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{}, false, ""),
456+
expectedContainerSpec: getWCOWSpecsWithAnnotations(map[string]string{}, false, ""),
457+
expectedError: "",
458+
},
459+
{
460+
testName: "annotations passthrough (isolated hpc)",
461+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
462+
annotations.HostProcessContainer: "true",
463+
annotations.HostProcessInheritUser: "true",
464+
annotations.HostProcessRootfsLocation: "C:\\test",
465+
}, true, ""),
466+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{
467+
annotations.HostProcessContainer: "true",
468+
}, true, ""),
469+
expectedContainerSpec: getWCOWSpecsWithAnnotations(map[string]string{
470+
annotations.HostProcessContainer: "true",
471+
annotations.HostProcessInheritUser: "true",
472+
annotations.HostProcessRootfsLocation: "C:\\test",
473+
}, true, ntAuthorityUser),
474+
expectedError: "",
475+
},
476+
{
477+
testName: "annotations passthrough (process hpc)",
478+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
479+
annotations.HostProcessContainer: "true",
480+
annotations.HostProcessInheritUser: "true",
481+
annotations.HostProcessRootfsLocation: "C:\\test",
482+
}, false, ""),
483+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{
484+
annotations.HostProcessContainer: "true",
485+
}, false, ""),
486+
expectedContainerSpec: getWCOWSpecsWithAnnotations(map[string]string{
487+
annotations.HostProcessContainer: "true",
488+
annotations.HostProcessInheritUser: "true",
489+
annotations.HostProcessRootfsLocation: "C:\\test",
490+
}, false, ""),
491+
expectedError: "",
492+
},
493+
{
494+
testName: "no annotation passthrough for normal containers (isolated hpc)",
495+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
496+
annotations.HostProcessInheritUser: "true",
497+
annotations.HostProcessRootfsLocation: "C:\\test",
498+
}, true, ""),
499+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{}, true, ""),
500+
expectedContainerSpec: getWCOWSpecsWithAnnotations(map[string]string{}, true, ""),
501+
expectedError: "",
502+
},
503+
{
504+
testName: "set user process for inherit annotation (isolated hpc)",
505+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
506+
annotations.HostProcessContainer: "true",
507+
annotations.HostProcessInheritUser: "true",
508+
}, true, ""),
509+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{
510+
annotations.HostProcessContainer: "true",
511+
}, true, ""),
512+
expectedContainerSpec: getWCOWSpecsWithAnnotations(map[string]string{
513+
annotations.HostProcessContainer: "true",
514+
annotations.HostProcessInheritUser: "true",
515+
}, true, ntAuthorityUser),
516+
expectedError: "",
517+
},
518+
{
519+
testName: "no changes in user process for normal containers (isolated hpc)",
520+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
521+
annotations.HostProcessContainer: "true",
522+
annotations.HostProcessInheritUser: "true",
523+
}, true, ""),
524+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{}, true, ""),
525+
expectedContainerSpec: getWCOWSpecsWithAnnotations(map[string]string{}, true, ""),
526+
expectedError: "",
527+
},
528+
{
529+
testName: "set inherit user annotation to false for normal containers (isolated hpc)",
530+
podSpec: getWCOWSpecsWithAnnotations(map[string]string{
531+
annotations.HostProcessContainer: "true",
532+
}, true, ""),
533+
containerSpec: getWCOWSpecsWithAnnotations(map[string]string{
534+
annotations.HostProcessInheritUser: "true",
535+
}, true, ""),
536+
expectedContainerSpec: getWCOWSpecsWithAnnotations(map[string]string{
537+
annotations.HostProcessInheritUser: "false",
538+
}, true, ""),
539+
expectedError: "",
540+
},
541+
}
542+
543+
for _, tc := range testCases {
544+
t.Run(tc.testName, func(t *testing.T) {
545+
p := &pod{spec: tc.podSpec}
546+
547+
err := p.updateConfigForHostProcessContainer(tc.containerSpec)
548+
if err == nil && tc.expectedError != "" {
549+
t.Fatalf("should have failed with '%s'", tc.expectedError)
550+
}
551+
if err != nil && err.Error() != tc.expectedError {
552+
t.Fatalf("should have failed with '%s', actual: '%s'", tc.expectedError, err.Error())
553+
}
554+
555+
if tc.expectedContainerSpec != nil {
556+
equal := reflect.DeepEqual(tc.containerSpec, tc.expectedContainerSpec)
557+
if !equal {
558+
t.Fatalf("containerSpec expected: %+v, got: %+v", tc.expectedContainerSpec, tc.containerSpec)
559+
}
560+
}
561+
})
562+
}
563+
}

0 commit comments

Comments
 (0)