Repository: zegl/kube-score
Pull request #477 (2022-06-14 13:46:19)

Implement feature request: Annotation in the manifest can be used to specify optional
Fixes: #476

## Behavior

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: optional-test-manifest-deployment
  labels:
    app: optional-test-manifest
  annotations:
    kube-score/ignore: pod-networkpolicy,container-resources,container-image-pull-policy,container-security-context-privileged,container-security-context-user-group-id,container-security-context-readonlyrootfilesystem,container-ephemeral-storage-request-and-limit
    kube-score/optional: container-seccomp-profile
spec:
  replicas: 1
  selector:
    matchLabels:
      app: optional-test-manifest
  template:
    metadata:
      labels:
        app: optional-test-manifest
    spec:
      containers:
      - name: optional-test-manifest
        image: busybox:1.34
        command:
        - /bin/sh
        - -c
        - date; env; tail -f /dev/null
```

```
$ kube-score score manifest.yaml
apps/v1/Deployment optional-test-manifest-deployment                          🤔
    [WARNING] Container Seccomp Profile
        · The pod has not configured Seccomp for its containers
            Running containers with Seccomp is recommended to reduce the kernel attack surface
```

### Annotations ignore

```
$ kube-score score manifest.yaml --disable-optional-checks-annotations
apps/v1/Deployment optional-test-manifest-deployment                          ✅
```

### (FYI) Both defined

It will be marked to `ignored`

```yaml
  annotations:
    kube-score/ignore: container-seccomp-profile
    kube-score/optional: container-seccomp-profile
```

```
$ kube-score score manifest.yaml --output-format ci | grep seccomp
[SKIPPED] optional-test-manifest-deployment apps/v1/Deployment: Skipped because container-seccomp-profile is ignored
```



Patch:
diff --git a/README.md b/README.md
index 568b943..11af8ac 100644
--- a/README.md
+++ b/README.md
@@ -102,6 +102,7 @@ Actions:
 
 Flags for score:
       --disable-ignore-checks-annotations   Set to true to disable the effect of the 'kube-score/ignore' annotations
+      --disable-optional-checks-annotations Set to true to disable the effect of the 'kube-score/enable' annotations
       --enable-optional-test strings        Enable an optional test, can be set multiple times
       --exit-one-on-warning                 Exit with code 1 in case of warnings
       --help                                Print help
@@ -143,6 +144,47 @@ spec:
   type: NodePort
 ```
 
+### Enabling a optional test
+
+Optional tests can be enabled in the whole run of the program, with the `--enable-optional-test` flag.
+
+A test can also be enabled on a per-object basis, by adding the annotation `kube-score/enable` to the object.
+The value should be a comma separated string of the [test IDs](README_CHECKS.md).
+
+Example:
+
+Testing this object will enable the `container-seccomp-profile` test.
+Also multiple tests defined by `kube-score/ignore` are also ignored at the same.
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: optional-test-manifest-deployment
+  labels:
+    app: optional-test-manifest
+  annotations:
+    kube-score/ignore: pod-networkpolicy,container-resources,container-image-pull-policy,container-security-context-privileged,container-security-context-user-group-id,container-security-context-readonlyrootfilesystem,container-ephemeral-storage-request-and-limit
+    kube-score/enable: container-seccomp-profile
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: optional-test-manifest
+  template:
+    metadata:
+      labels:
+        app: optional-test-manifest
+    spec:
+      containers:
+      - name: optional-test-manifest
+        image: busybox:1.34
+        command:
+        - /bin/sh
+        - -c
+        - date; env; tail -f /dev/null
+```
+
 ## Building from source
 
 `kube-score` requires [Go](https://golang.org/) `1.11` or later to build. Clone this repository, and then:
diff --git a/cmd/kube-score/main.go b/cmd/kube-score/main.go
index 920ae6c..d4eca8a 100644
--- a/cmd/kube-score/main.go
+++ b/cmd/kube-score/main.go
@@ -109,6 +109,7 @@ func scoreFiles(binName string, args []string) error {
 	optionalTests := fs.StringSlice("enable-optional-test", []string{}, "Enable an optional test, can be set multiple times")
 	ignoreTests := fs.StringSlice("ignore-test", []string{}, "Disable a test, can be set multiple times")
 	disableIgnoreChecksAnnotation := fs.Bool("disable-ignore-checks-annotations", false, "Set to true to disable the effect of the 'kube-score/ignore' annotations")
+	disableOptionalChecksAnnotation := fs.Bool("disable-optional-checks-annotations", false, "Set to true to disable the effect of the 'kube-score/enable' annotations")
 	kubernetesVersion := fs.String("kubernetes-version", "v1.18", "Setting the kubernetes-version will affect the checks ran against the manifests. Set this to the version of Kubernetes that you're using in production for the best results.")
 	setDefault(fs, binName, "score", false)
 
@@ -172,6 +173,7 @@ Use "-" as filename to read from STDIN.`, execName(binName))
 		IgnoredTests:                          ignoredTests,
 		EnabledOptionalTests:                  enabledOptionalTests,
 		UseIgnoreChecksAnnotation:             !*disableIgnoreChecksAnnotation,
+		UseOptionalChecksAnnotation:           !*disableOptionalChecksAnnotation,
 		KubernetesVersion:                     kubeVer,
 	}
 
diff --git a/config/config.go b/config/config.go
index e5d2d3f..6d0a4ee 100644
--- a/config/config.go
+++ b/config/config.go
@@ -17,6 +17,7 @@ type Configuration struct {
 	IgnoredTests                          map[string]struct{}
 	EnabledOptionalTests                  map[string]struct{}
 	UseIgnoreChecksAnnotation             bool
+	UseOptionalChecksAnnotation           bool
 	KubernetesVersion                     Semver
 }
 
diff --git a/go.mod b/go.mod
index 483126f..e19a781 100644
--- a/go.mod
+++ b/go.mod
@@ -5,11 +5,11 @@ require (
 	github.com/fatih/color v1.13.0
 	github.com/google/go-cmp v0.5.8
 	github.com/spf13/pflag v1.0.5
-	github.com/stretchr/testify v1.7.3
+	github.com/stretchr/testify v1.7.2
 	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
 	gopkg.in/yaml.v3 v3.0.1
-	k8s.io/api v0.24.2
-	k8s.io/apimachinery v0.24.2
+	k8s.io/api v0.24.1
+	k8s.io/apimachinery v0.24.1
 	sigs.k8s.io/yaml v1.3.0 // indirect
 )
 
diff --git a/go.sum b/go.sum
index 8a4e7ba..b68edc5 100644
--- a/go.sum
+++ b/go.sum
@@ -110,13 +110,11 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.3 h1:dAm0YRdRQlWojc3CrCRgPBzG5f941d0zvAKu7qY4e+I=
-github.com/stretchr/testify v1.7.3/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -237,10 +235,10 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-k8s.io/api v0.24.2 h1:g518dPU/L7VRLxWfcadQn2OnsiGWVOadTLpdnqgY2OI=
-k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg=
-k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM=
-k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
+k8s.io/api v0.24.1 h1:BjCMRDcyEYz03joa3K1+rbshwh1Ay6oB53+iUx2H8UY=
+k8s.io/api v0.24.1/go.mod h1:JhoOvNiLXKTPQ60zh2g0ewpA+bnEYf5q44Flhquh4vQ=
+k8s.io/apimachinery v0.24.1 h1:ShD4aDxTQKN5zNf8K1RQ2u98ELLdIW7jEnlO9uAMX/I=
+k8s.io/apimachinery v0.24.1/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
 k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
 k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
diff --git a/score/checks/checks.go b/score/checks/checks.go
index e1809fd..e0fffd6 100644
--- a/score/checks/checks.go
+++ b/score/checks/checks.go
@@ -123,22 +123,9 @@ type Checks struct {
 	cnf config.Configuration
 }
 
-func (c Checks) isIgnored(id string) bool {
-	_, ok := c.cnf.IgnoredTests[id]
-	return ok
-}
-
 func (c Checks) isEnabled(check ks.Check) bool {
-	if c.isIgnored(check.ID) {
-		return false
-	}
-
-	if !check.Optional {
-		return true
-	}
-
-	_, ok := c.cnf.EnabledOptionalTests[check.ID]
-	return ok
+	_, ok := c.cnf.IgnoredTests[check.ID]
+	return !ok
 }
 
 func (c *Checks) RegisterMetaCheck(name, comment string, fn MetaCheckFn) {
diff --git a/score/score.go b/score/score.go
index 71e0100..32f918b 100644
--- a/score/score.go
+++ b/score/score.go
@@ -48,7 +48,7 @@ func Score(allObjects ks.AllTypes, cnf config.Configuration) (*scorecard.Scoreca
 	scoreCard := scorecard.New()
 
 	newObject := func(typeMeta metav1.TypeMeta, objectMeta metav1.ObjectMeta) *scorecard.ScoredObject {
-		return scoreCard.NewObject(typeMeta, objectMeta, cnf.UseIgnoreChecksAnnotation)
+		return scoreCard.NewObject(typeMeta, objectMeta, cnf)
 	}
 
 	for _, ingress := range allObjects.Ingresses() {
diff --git a/scorecard/scorecard.go b/scorecard/scorecard.go
index 23ddc60..f44b5e1 100644
--- a/scorecard/scorecard.go
+++ b/scorecard/scorecard.go
@@ -4,12 +4,14 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/zegl/kube-score/config"
 	ks "github.com/zegl/kube-score/domain"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
 const (
-	ignoredChecksAnnotation = "kube-score/ignore"
+	ignoredChecksAnnotation  = "kube-score/ignore"
+	optionalChecksAnnotation = "kube-score/enable"
 )
 
 // if this, then that
@@ -24,11 +26,13 @@ func New() Scorecard {
 	return make(Scorecard)
 }
 
-func (s Scorecard) NewObject(typeMeta metav1.TypeMeta, objectMeta metav1.ObjectMeta, useIgnoreChecksAnnotation bool) *ScoredObject {
+func (s Scorecard) NewObject(typeMeta metav1.TypeMeta, objectMeta metav1.ObjectMeta, cnf config.Configuration) *ScoredObject {
 	o := &ScoredObject{
-		TypeMeta:   typeMeta,
-		ObjectMeta: objectMeta,
-		Checks:     make([]TestScore, 0),
+		TypeMeta:       typeMeta,
+		ObjectMeta:     objectMeta,
+		Checks:         make([]TestScore, 0),
+		ignoredChecks:  make(map[string]struct{}),
+		optionalChecks: make(map[string]struct{}),
 	}
 
 	// If this object already exists, return the previous version
@@ -36,10 +40,17 @@ func (s Scorecard) NewObject(typeMeta metav1.TypeMeta, objectMeta metav1.ObjectM
 		return object
 	}
 
-	if useIgnoreChecksAnnotation {
+	if cnf.UseIgnoreChecksAnnotation {
 		o.setIgnoredTests()
 	}
 
+	if cnf.UseOptionalChecksAnnotation {
+		o.setOptionalTests()
+	}
+	for id, ot := range cnf.EnabledOptionalTests {
+		o.optionalChecks[id] = ot
+	}
+
 	s[o.resourceRefKey()] = o
 	return o
 }
@@ -59,7 +70,8 @@ type ScoredObject struct {
 	FileLocation ks.FileLocation
 	Checks       []TestScore
 
-	ignoredChecks map[string]struct{}
+	ignoredChecks  map[string]struct{}
+	optionalChecks map[string]struct{}
 }
 
 func (s ScoredObject) AnyBelowOrEqualToGrade(threshold Grade) bool {
@@ -86,6 +98,16 @@ func (so *ScoredObject) setIgnoredTests() {
 	so.ignoredChecks = ignoredMap
 }
 
+func (so *ScoredObject) setOptionalTests() {
+	optionalMap := make(map[string]struct{})
+	if optionalCSV, ok := so.ObjectMeta.Annotations[optionalChecksAnnotation]; ok {
+		for _, optional := range strings.Split(optionalCSV, ",") {
+			optionalMap[strings.TrimSpace(optional)] = struct{}{}
+		}
+	}
+	so.optionalChecks = optionalMap
+}
+
 func (so ScoredObject) resourceRefKey() string {
 	return so.TypeMeta.Kind + "/" + so.TypeMeta.APIVersion + "/" + so.ObjectMeta.Namespace + "/" + so.ObjectMeta.Name
 }
@@ -103,6 +125,10 @@ func (so *ScoredObject) Add(ts TestScore, check ks.Check, locationer ks.FileLoca
 	ts.Check = check
 	so.FileLocation = locationer.FileLocation()
 
+	if _, ok := so.optionalChecks[check.ID]; ts.Check.Optional && !ok {
+		return
+	}
+
 	// This test is ignored (via annotations), don't save the score
 	if _, ok := so.ignoredChecks[check.ID]; ok {
 		ts.Skipped = true


Test patch:
diff --git a/score/score_test.go b/score/score_test.go
index b2e9154..719fbb3 100644
--- a/score/score_test.go
+++ b/score/score_test.go
@@ -153,6 +153,15 @@ func TestPodContainerResourceRequestsEqualLimitsNoLimits(t *testing.T) {
 	}, "Container Resource Requests Equal Limits", scorecard.GradeCritical)
 }
 
+func TestPodContainerResourceRequestsEqualLimitsNoLimitsAnnotation(t *testing.T) {
+	t.Parallel()
+
+	testExpectedScoreWithConfig(t, config.Configuration{
+		AllFiles:                    []ks.NamedReader{testFile("pod-test-resources-no-limits-annotation-optional.yaml")},
+		UseOptionalChecksAnnotation: true,
+	}, "Container Resource Requests Equal Limits", scorecard.GradeCritical)
+}
+
 func TestPodContainerMemoryRequestsEqualLimitsNoLimits(t *testing.T) {
 	t.Parallel()
 
@@ -165,6 +174,15 @@ func TestPodContainerMemoryRequestsEqualLimitsNoLimits(t *testing.T) {
 	}, "Container Memory Requests Equal Limits", scorecard.GradeCritical)
 }
 
+func TestPodContainerMemoryRequestsEqualLimitsNoLimitsAnnotation(t *testing.T) {
+	t.Parallel()
+
+	testExpectedScoreWithConfig(t, config.Configuration{
+		AllFiles:                    []ks.NamedReader{testFile("pod-test-resources-no-limits-annotation-optional.yaml")},
+		UseOptionalChecksAnnotation: true,
+	}, "Container Memory Requests Equal Limits", scorecard.GradeCritical)
+}
+
 func TestPodContainerCPURequestsEqualLimitsNoLimits(t *testing.T) {
 	t.Parallel()
 
@@ -177,6 +195,15 @@ func TestPodContainerCPURequestsEqualLimitsNoLimits(t *testing.T) {
 	}, "Container CPU Requests Equal Limits", scorecard.GradeCritical)
 }
 
+func TestPodContainerCPURequestsEqualLimitsNoLimitsAnnotation(t *testing.T) {
+	t.Parallel()
+
+	testExpectedScoreWithConfig(t, config.Configuration{
+		AllFiles:                    []ks.NamedReader{testFile("pod-test-resources-no-limits-annotation-optional.yaml")},
+		UseOptionalChecksAnnotation: true,
+	}, "Container CPU Requests Equal Limits", scorecard.GradeCritical)
+}
+
 func TestDeploymentResources(t *testing.T) {
 	t.Parallel()
 	testExpectedScore(t, "deployment-test-resources.yaml", "Container Resources", scorecard.GradeWarning)
@@ -345,6 +372,15 @@ func TestPodContainerStorageEphemeralRequestNoMatchLimit(t *testing.T) {
 	}, "Container Ephemeral Storage Request Equals Limit", scorecard.GradeCritical)
 }
 
+func TestPodContainerStorageEphemeralRequestNoMatchLimitAnnotation(t *testing.T) {
+	t.Parallel()
+
+	testExpectedScoreWithConfig(t, config.Configuration{
+		AllFiles:                    []ks.NamedReader{testFile("pod-ephemeral-storage-request-nomatch-limit-annotation-optional.yaml")},
+		UseOptionalChecksAnnotation: true,
+	}, "Container Ephemeral Storage Request Equals Limit", scorecard.GradeCritical)
+}
+
 func TestPodContainerStorageEphemeralIgnoreAnnotation(t *testing.T) {
 
 	t.Parallel()
@@ -381,6 +417,15 @@ func TestPodContainerPortsContainerPortMissing(t *testing.T) {
 	}, "Container Ports Check", scorecard.GradeCritical)
 }
 
+func TestPodContainerPortsContainerPortMissingAnnotation(t *testing.T) {
+	t.Parallel()
+
+	testExpectedScoreWithConfig(t, config.Configuration{
+		AllFiles:                    []ks.NamedReader{testFile("pod-container-ports-missing-containerport-annotation-optional.yaml")},
+		UseOptionalChecksAnnotation: true,
+	}, "Container Ports Check", scorecard.GradeCritical)
+}
+
 func TestPodContainerPortsDuplicateNames(t *testing.T) {
 	t.Parallel()
 
diff --git a/score/security_test.go b/score/security_test.go
index 58060f9..5e9574d 100644
--- a/score/security_test.go
+++ b/score/security_test.go
@@ -33,6 +33,15 @@ func TestContainerSeccompAllGood(t *testing.T) {
 	}, "Container Seccomp Profile", scorecard.GradeAllOK)
 }
 
+func TestContainerSeccompAllGoodAnnotation(t *testing.T) {
+	t.Parallel()
+
+	testExpectedScoreWithConfig(t, config.Configuration{
+		AllFiles:                    []ks.NamedReader{testFile("pod-seccomp-annotated-annotation-optional.yaml")},
+		UseOptionalChecksAnnotation: true,
+	}, "Container Seccomp Profile", scorecard.GradeAllOK)
+}
+
 func TestContainerSecurityContextUserGroupIDAllGood(t *testing.T) {
 	t.Parallel()
 	structMap := make(map[string]struct{})
diff --git a/score/testdata/pod-container-ports-missing-containerport-annotation-optional.yaml b/score/testdata/pod-container-ports-missing-containerport-annotation-optional.yaml
new file mode 100644
index 0000000..099fa8e
--- /dev/null
+++ b/score/testdata/pod-container-ports-missing-containerport-annotation-optional.yaml
@@ -0,0 +1,30 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: app
+  labels:
+    app: app
+  annotations:
+    kube-score/enable: container-ports-check
+spec:
+  selector:
+    matchLabels:
+      app: app
+  template:
+    metadata:
+      labels:
+        app: app
+    spec:
+      nodeSelector:
+        beta.kubernetes.io/os: linux
+      containers:
+      - name: app
+        image: app:dev
+        imagePullPolicy: "Always"
+        ports:
+        - name: app
+          containerPort: 80
+          protocol: TCP
+        - name: smtp
+          containerPort: 
+          protocol: TCP
diff --git a/score/testdata/pod-ephemeral-storage-request-nomatch-limit-annotation-optional.yaml b/score/testdata/pod-ephemeral-storage-request-nomatch-limit-annotation-optional.yaml
new file mode 100644
index 0000000..61bd36a
--- /dev/null
+++ b/score/testdata/pod-ephemeral-storage-request-nomatch-limit-annotation-optional.yaml
@@ -0,0 +1,19 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  annotations:
+    kube-score/enable: container-ephemeral-storage-request-equals-limit
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:123
+    resources:
+      limits:
+        cpu: 200m
+        memory: 1Gi
+        ephemeral-storage: 2Gi
+      requests:
+        cpu: 200m
+        memory: 1Gi
+        ephemeral-storage: 1Gi
diff --git a/score/testdata/pod-seccomp-annotated-annotation-optional.yaml b/score/testdata/pod-seccomp-annotated-annotation-optional.yaml
new file mode 100644
index 0000000..46e7cdb
--- /dev/null
+++ b/score/testdata/pod-seccomp-annotated-annotation-optional.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  annotations:
+    seccomp.security.alpha.kubernetes.io/defaultProfileName:  'runtime/default'
+    kube-score/enable: container-seccomp-profile
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest
+    
\ No newline at end of file
diff --git a/score/testdata/pod-test-resources-no-limits-annotation-optional.yaml b/score/testdata/pod-test-resources-no-limits-annotation-optional.yaml
new file mode 100644
index 0000000..66a0d60
--- /dev/null
+++ b/score/testdata/pod-test-resources-no-limits-annotation-optional.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  annotations:
+    kube-score/enable: container-memory-requests-equal-limits,container-cpu-requests-equal-limits,container-resource-requests-equal-limits
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:123
+    resources:
+      requests:
+        cpu: 200m
+        memory: 1Gi