Repository: zegl/kube-score
Pull request #630 (2024-11-08 11:06:55)

build(deps): bump golang.org/x/term from 0.25.0 to 0.26.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.25.0 to 0.26.0.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/term/commit/b725e362a8129d135cfc48159c4c4117f2cdc3b6"><code>b725e36</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/term/commit/54df7da90da86330bfdf9c8d1b1f0711d906e64f"><code>54df7da</code></a> README: don't recommend go get</li>
<li>See full diff in <a href="https://github.com/golang/term/compare/v0.25.0...v0.26.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/term&package-manager=go_modules&previous-version=0.25.0&new-version=0.26.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

vercel[bot]: [vc]: #2At7FhA4EyKzY4B3jQ6t5InRFFfOym3wFzuivibDcPc=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJrdWJlLXNjb3JlIiwicm9vdERpcmVjdG9yeSI6bnVsbCwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2d1c3Rhdi13ZXN0bGluZ3MtcHJvamVjdHMva3ViZS1zY29yZS9Ld0JCekNRc2dFVGl0cGFyRktFRHVCMUFKMlJXIiwicHJldmlld1VybCI6Imt1YmUtc2NvcmUtZ2l0LWRlcGVuZGFib3QtZ29tby1hZGU4MDAtZ3VzdGF2LXdlc3RsaW5ncy1wcm9qZWN0cy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IlBFTkRJTkciLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoia3ViZS1zY29yZS1naXQtZGVwZW5kYWJvdC1nb21vLWFkZTgwMC1ndXN0YXYtd2VzdGxpbmdzLXByb2plY3RzLnZlcmNlbC5hcHAifX1dfQ==
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **kube-score** | 🔄 Building ([Inspect](https://vercel.com/gustav-westlings-projects/kube-score/KwBBzCQsgETitparFKEDuB1AJ2RW)) | [Visit Preview](https://vercel.live/open-feedback/kube-score-git-dependabot-gomo-ade800-gustav-westlings-projects.vercel.app?via=pr-comment-visit-preview-link&passThrough=1) | 💬 [**Add feedback**](https://vercel.live/open-feedback/kube-score-git-dependabot-gomo-ade800-gustav-westlings-projects.vercel.app?via=pr-comment-feedback-link) | Nov 8, 2024 11:06am |



Patch:
diff --git a/go.mod b/go.mod
index 0e89ae2..ef9bac9 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
 	github.com/mattn/go-isatty v0.0.20
 	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.9.0
-	golang.org/x/term v0.25.0
+	golang.org/x/term v0.26.0
 	gopkg.in/yaml.v3 v3.0.1
 	k8s.io/api v0.31.2
 	k8s.io/apimachinery v0.31.2
@@ -29,7 +29,7 @@ require (
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	golang.org/x/net v0.26.0 // indirect
-	golang.org/x/sys v0.26.0 // indirect
+	golang.org/x/sys v0.27.0 // indirect
 	golang.org/x/text v0.16.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 31f18e0..abfea67 100644
--- a/go.sum
+++ b/go.sum
@@ -75,10 +75,10 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
-golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
+golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
+golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
+golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
diff --git a/score/score.go b/score/score.go
index 390d7af..df8a06e 100644
--- a/score/score.go
+++ b/score/score.go
@@ -28,6 +28,10 @@ import (
 func RegisterAllChecks(allObjects ks.AllTypes, checksConfig *checks.Config, runConfig *config.RunConfiguration) *checks.Checks {
 	allChecks := checks.New(checksConfig)
 
+	if runConfig == nil {
+		runConfig = &config.RunConfiguration{}
+	}
+
 	deployment.Register(allChecks, allObjects)
 	ingress.Register(allChecks, allObjects)
 	cronjob.Register(allChecks)
diff --git a/score/security/security.go b/score/security/security.go
index 4262a8d..6cbc10d 100644
--- a/score/security/security.go
+++ b/score/security/security.go
@@ -109,20 +109,51 @@ func containerSecurityContextUserGroupID(ps ks.PodSpecer) (score scorecard.TestS
 	return
 }
 
-// podSeccompProfile checks that a Seccommp profile is configured for the pod
+// podSeccompProfile checks that a Seccommp profile is configured. The
+// seccompProfile can be specified either through annotation or securityContext.
+// There are two ways to specify the seccomp profile via securityContext --
+// at the pod level or  container level.
+// Pod level seccomp profile is preferred since it is applied to all containers.
 func podSeccompProfile(ps ks.PodSpecer) (score scorecard.TestScore, err error) {
 	metadata := ps.GetPodTemplateSpec().ObjectMeta
 
-	seccompAnnotated := false
+	secured := false
+
+	// Check if the seccomp profile is set via annotation
 	if metadata.Annotations != nil {
 		if _, ok := metadata.Annotations["seccomp.security.alpha.kubernetes.io/defaultProfileName"]; ok {
-			seccompAnnotated = true
+			secured = true
+		}
+	}
+
+	//Check if seccomp is set via securityContext at Pod or Container Level
+	if !secured {
+		elements := make(map[string]bool)
+		if ps.GetPodTemplateSpec().Spec.SecurityContext != nil && ps.GetPodTemplateSpec().Spec.SecurityContext.SeccompProfile != nil {
+			secured = true
+		} else {
+			// This does not check initContainers, only Containers
+			for _, container := range ps.GetPodTemplateSpec().Spec.Containers {
+				if container.SecurityContext != nil && container.SecurityContext.SeccompProfile != nil {
+					elements[container.Name] = true
+					secured = true
+				} else {
+					score.AddComment(container.Name, "The container has not configured Seccomp", "Running containers with Seccomp is recommended to reduce the kernel attack surface")
+					elements[container.Name] = false
+				}
+			}
+		}
+
+		// one unsecured container is enough to fail the test
+		for _, value := range elements {
+			if !value {
+				secured = false
+			}
 		}
 	}
 
-	if !seccompAnnotated {
+	if !secured {
 		score.Grade = scorecard.GradeWarning
-		score.AddComment(metadata.Name, "The pod has not configured Seccomp for its containers", "Running containers with Seccomp is recommended to reduce the kernel attack surface")
 	} else {
 		score.Grade = scorecard.GradeAllOK
 	}


Test patch:
diff --git a/score/security_test.go b/score/security_test.go
index 2f077ea..2c3aa6f 100644
--- a/score/security_test.go
+++ b/score/security_test.go
@@ -21,6 +21,50 @@ func TestContainerSeccompMissing(t *testing.T) {
 
 }
 
+func TestPodSecurityContextPresent(t *testing.T) {
+	t.Parallel()
+
+	structMap := make(map[string]struct{})
+	structMap["container-seccomp-profile"] = struct{}{}
+
+	testExpectedScoreWithConfig(t, []ks.NamedReader{testFile("pod-seccomp-securecontext-ok.yaml")}, nil, &config.RunConfiguration{
+		EnabledOptionalTests: structMap,
+	}, "Container Seccomp Profile", scorecard.GradeAllOK)
+}
+
+func TestContainerSecurityContextSeccompPresent(t *testing.T) {
+	t.Parallel()
+
+	structMap := make(map[string]struct{})
+	structMap["container-seccomp-profile"] = struct{}{}
+
+	testExpectedScoreWithConfig(t, []ks.NamedReader{testFile("pod-seccomp-container-securecontext-ok.yaml")}, nil, &config.RunConfiguration{
+		EnabledOptionalTests: structMap,
+	}, "Container Seccomp Profile", scorecard.GradeAllOK)
+}
+
+func TestPodSecurityContextSeccompAbsent(t *testing.T) {
+	t.Parallel()
+
+	structMap := make(map[string]struct{})
+	structMap["container-seccomp-profile"] = struct{}{}
+
+	testExpectedScoreWithConfig(t, []ks.NamedReader{testFile("pod-seccomp-securecontext-warning.yaml")}, nil, &config.RunConfiguration{
+		EnabledOptionalTests: structMap,
+	}, "Container Seccomp Profile", scorecard.GradeWarning)
+}
+
+func TestContainerSecurityContextSeccompAbsent(t *testing.T) {
+	t.Parallel()
+
+	structMap := make(map[string]struct{})
+	structMap["container-seccomp-profile"] = struct{}{}
+
+	testExpectedScoreWithConfig(t, []ks.NamedReader{testFile("pod-seccomp-container-securecontext-warning.yaml")}, nil, &config.RunConfiguration{
+		EnabledOptionalTests: structMap,
+	}, "Container Seccomp Profile", scorecard.GradeWarning)
+}
+
 func TestContainerSeccompMissingNotRunByDefault(t *testing.T) {
 	t.Parallel()
 	skipped := wasSkipped(t, []ks.NamedReader{testFile("pod-seccomp-no-annotation.yaml")}, nil, nil, "Container Seccomp Profile")
diff --git a/score/testdata/pod-seccomp-container-securecontext-ok.yaml b/score/testdata/pod-seccomp-container-securecontext-ok.yaml
new file mode 100644
index 0000000..51ea534
--- /dev/null
+++ b/score/testdata/pod-seccomp-container-securecontext-ok.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+    securityContext:
+      privileged: False
+      runAsUser: 30000
+      runAsGroup: 30000
+      readOnlyRootFilesystem: True
+      seccompProfile:
+        type: RuntimeDefault 
+
diff --git a/score/testdata/pod-seccomp-container-securecontext-warning.yaml b/score/testdata/pod-seccomp-container-securecontext-warning.yaml
new file mode 100644
index 0000000..e5bc54d
--- /dev/null
+++ b/score/testdata/pod-seccomp-container-securecontext-warning.yaml
@@ -0,0 +1,31 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+    securityContext:
+      privileged: False
+      runAsUser: 30000
+      runAsGroup: 30000
+      readOnlyRootFilesystem: True
+      seccompProfile:
+        type: RuntimeDefault 
+  - name: foobaz
+    image: foo/baz:latest
+    securityContext:
+      privileged: False
+      runAsUser: 30000
+      runAsGroup: 30000
+      readOnlyRootFilesystem: True
+  - name: foozed
+    image: foo/zed:latest
+    securityContext:
+      privileged: False
+      runAsUser: 30000
+      runAsGroup: 30000
+      readOnlyRootFilesystem: True
+      seccompProfile:
+        type: RuntimeDefault 
\ No newline at end of file
diff --git a/score/testdata/pod-seccomp-securecontext-ok.yaml b/score/testdata/pod-seccomp-securecontext-ok.yaml
new file mode 100644
index 0000000..c1eba33
--- /dev/null
+++ b/score/testdata/pod-seccomp-securecontext-ok.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+spec:
+  securityContext:
+    seccompProfile:
+      type: RuntimeDefault
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+    securityContext:
+      privileged: False
+      runAsUser: 30000
+      runAsGroup: 30000
+      readOnlyRootFilesystem: True
diff --git a/score/testdata/pod-seccomp-securecontext-warning.yaml b/score/testdata/pod-seccomp-securecontext-warning.yaml
new file mode 100644
index 0000000..26014f0
--- /dev/null
+++ b/score/testdata/pod-seccomp-securecontext-warning.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+spec:
+  securityContext:
+      privileged: False
+      runAsUser: 30000
+      runAsGroup: 30000
+      readOnlyRootFilesystem: True 
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+  - name: foobaz
+    image: foo/baz:latest