Change:
func TestNonRootValidate(t *testing.T) { goodUID := types.UnixUserID(1) badUID := types.UnixUserID(0) <ins> untrue := false unfalse := true </ins> s, err := NewRunAsNonRoot(&extensions.RunAsUserStrategyOptions{}) if err != nil { t.Fatalf("unexpected error initializing NewMustRunAs %v", err) } <del> container := &api.Container{ SecurityContext: &api.SecurityContext{ RunAsUser: &badUID, </del> <ins> tests := []struct { container   *api.Container expectedErr bool msg         string }{ { container: &api.Container{ SecurityContext: &api.SecurityContext{ RunAsUser: &badUID, }, }, expectedErr: true, msg:         "in test case %d, expected errors from root uid but got none: %v", }, { container: &api.Container{ SecurityContext: &api.SecurityContext{ RunAsUser: &goodUID, }, }, expectedErr: false, msg:         "in test case %d, expected no errors from non-root uid but got %v", }, { container: &api.Container{ SecurityContext: &api.SecurityContext{ RunAsNonRoot: &untrue, }, }, expectedErr: true, msg:         "in test case %d, expected errors from RunAsNonRoot but got none: %v", }, { container: &api.Container{ SecurityContext: &api.SecurityContext{ RunAsNonRoot: &unfalse, RunAsUser:    &goodUID, }, }, expectedErr: false, msg:         "in test case %d, expected no errors from non-root uid but got %v", }, { container: &api.Container{ SecurityContext: &api.SecurityContext{ RunAsNonRoot: &unfalse, RunAsUser:    &badUID, }, }, expectedErr: true, msg:         "in test case %d, expected errors from root uid but got %v", </ins> }, } <del> errs := s.Validate(nil, container) if len(errs) == 0 { t.Errorf("expected errors from root uid but got none") } container.SecurityContext.RunAsUser = &goodUID errs = s.Validate(nil, container) if len(errs) != 0 { t.Errorf("expected no errors from non-root uid but got %v", errs) } container.SecurityContext.RunAsUser = nil errs = s.Validate(nil, container) if len(errs) != 0 { t.Errorf("expected no errors from nil uid but got %v", errs) </del> <ins> for i, tc := range tests { errs := s.Validate(nil, tc.container) if (len(errs) == 0) == tc.expectedErr { t.Errorf(tc.msg, i, errs) } </ins> } }

Discussion:
What keywords did you search in Kubernetes issues before filing this one? (If you have found any duplicates, you should instead reply there.): PodSecurityPolicy RunAsNonRoot Is this a BUG REPORT or FEATURE REQUEST? (choose one): BUG REPORT <!-- If this is a BUG REPORT, please: Fill in as much of the template below as you can. If you leave out information, we can't help you as well. If this is a FEATURE REQUEST, please: Describe in detail the feature/behavior/change you'd like to see. In both cases, be ready for followup questions, and please respond in a timely manner. If we can't reproduce a bug or think a feature already exists, we might close your issue. If we're wrong, PLEASE feel free to reopen it and explain why. --Kubernetes version (use ): 1.7.0-beta, 1.8.0 (HEAD) Environment: Enable PodSecurityPolicy Cloud provider or hardware configuration: gce, probably any OS (e.g. from /etc/os-release): gci Kernel (e.g. ): Install tools: Others: What happened: The PSP admission controller ignores the specified RunAsNonRoot, and overwrites it. What you expected to happen: the admission controller is not supposed to overwrite user specified fields in the podsecuritycontext and securitycontext. How to reproduce it (as minimally and precisely as possible): enable psp, and create a pod with [only] RunAsNonRoot=false specified in a securitycontext. Anything else we need to know:
/sig auth
there are actually 2 bugs here. fails to properly restrict this field when matching against a PSP, which is a latent bug as long as we overwrite the value anyway. overwrites the user-supplied setting for the securitycontext/podsecuritycontext. I suspect the best fix will be to use the API's deep copy function. We are also doing a couple other sketchy things: assigning the "copy" built-in as a variable, and creating an "sc" shadow variable.

I have a half fix in but we should probably fix it in a separate PR, because we may want to patch 1.6.
the effect is that PSP can overly restrict a pod that wanted to run as root, but expressed that as instead of since the workaround is easy (set in your pod if you want to run as root), I don't anticipate backporting the fix.
SGTM. I'll try and get the unit tests in after the GKE summit (on friday).