Repository: doitintl/kube-no-trouble
Pull request #171 (2021-06-14 12:13:03)

feat: Cover deprecated `node.k8s.io/v1beta1` API group
This PR adds coverage of deprecated `node.k8s.io/v1beta1` API group - `RuntimeClass` resource.

As per https://kubernetes.io/docs/reference/using-api/deprecation-guide.

Part of #135


Patch:
diff --git a/.gitignore b/.gitignore
index 978e18b..a935d3a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 bin/
 release-artifacts/
 debug.test
+fmtcoverage.html
 
 # Dependency directories (remove the comment below to include it)
 # vendor/
diff --git a/fixtures/runtimeclass-v1beta1.yaml b/fixtures/runtimeclass-v1beta1.yaml
new file mode 100644
index 0000000..89d9344
--- /dev/null
+++ b/fixtures/runtimeclass-v1beta1.yaml
@@ -0,0 +1,5 @@
+apiVersion: node.k8s.io/v1beta1
+kind: RuntimeClass
+metadata:
+  name: my-class
+handler: my-cri
diff --git a/pkg/collector/cluster.go b/pkg/collector/cluster.go
index c1e9bc3..d8e633e 100644
--- a/pkg/collector/cluster.go
+++ b/pkg/collector/cluster.go
@@ -98,6 +98,7 @@ func (c *ClusterCollector) Get() ([]map[string]interface{}, error) {
 		schema.GroupVersionResource{Group: "apiextensions.k8s.io", Version: "v1", Resource: "customresourcedefinitions"},
 		schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1", Resource: "mutatingwebhookconfigurations"},
 		schema.GroupVersionResource{Group: "admissionregistration.k8s.io", Version: "v1", Resource: "validatingwebhookconfigurations"},
+		schema.GroupVersionResource{Group: "node.k8s.io", Version: "v1", Resource: "runtimeclasses"},
 	}
 	gvrs = append(gvrs, c.additionalResources...)
 
diff --git a/pkg/rules/rego/deprecated-1-22.rego b/pkg/rules/rego/deprecated-1-22.rego
index 8f1eb25..7fe745b 100644
--- a/pkg/rules/rego/deprecated-1-22.rego
+++ b/pkg/rules/rego/deprecated-1-22.rego
@@ -1,4 +1,4 @@
-package deprecated120
+package deprecated122
 
 main[return] {
 	resource := input[_]
diff --git a/pkg/rules/rego/deprecated-1-25.rego b/pkg/rules/rego/deprecated-1-25.rego
new file mode 100644
index 0000000..c67adcd
--- /dev/null
+++ b/pkg/rules/rego/deprecated-1-25.rego
@@ -0,0 +1,42 @@
+package deprecated125
+
+main[return] {
+	resource := input[_]
+	api := deprecated_resource(resource)
+	return := {
+		"Name": resource.metadata.name,
+		# Namespace does not have to be defined in case of local manifests
+		"Namespace": get_default(resource.metadata, "namespace", "<undefined>"),
+		"Kind": resource.kind,
+		"ApiVersion": api.old,
+		"ReplaceWith": api.new,
+		"RuleSet": "Deprecated APIs removed in 1.25",
+		"Since": api.since,
+	}
+}
+
+deprecated_resource(r) = api {
+	api := deprecated_api(r.kind, r.apiVersion)
+}
+
+deprecated_api(kind, api_version) = api {
+	deprecated_apis = {"RuntimeClass": {
+		"old": ["node.k8s.io/v1beta1"],
+		"new": "node.k8s.io/v1",
+		"since": "1.20",
+	}}
+
+	deprecated_apis[kind].old[_] == api_version
+
+	api := {
+		"old": api_version,
+		"new": deprecated_apis[kind].new,
+		"since": deprecated_apis[kind].since,
+	}
+}
+
+get_default(val, key, _) = val[key]
+
+get_default(val, key, fallback) = fallback {
+	not val[key]
+}


Test patch:
diff --git a/test/helper.go b/test/helper.go
new file mode 100644
index 0000000..1c93c69
--- /dev/null
+++ b/test/helper.go
@@ -0,0 +1,40 @@
+package test
+
+import (
+	"testing"
+
+	"github.com/doitintl/kube-no-trouble/pkg/collector"
+)
+
+type resourceFixtureTestCase struct {
+	name          string
+	fixturePaths  []string
+	expectedKinds []string
+}
+
+func testReourcesUsingFixtures(t *testing.T, testCases []resourceFixtureTestCase) {
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			c, err := collector.NewFileCollector(
+				&collector.FileOpts{Filenames: tc.fixturePaths},
+			)
+
+			if err != nil {
+				t.Errorf("Expected to succeed for %s, failed: %s", tc.fixturePaths, err)
+			}
+
+			manifests, err := c.Get()
+			if err != nil {
+				t.Errorf("Expected to succeed for %s, failed: %s", tc.fixturePaths, err)
+			} else if len(manifests) != len(tc.expectedKinds) {
+				t.Errorf("Expected to get %d, got %d", len(tc.expectedKinds), len(manifests))
+			}
+
+			for i := range manifests {
+				if manifests[i]["kind"] != tc.expectedKinds[i] {
+					t.Errorf("Expected to get %s, instead got: %s", tc.expectedKinds[i], manifests[i]["kind"])
+				}
+			}
+		})
+	}
+}
diff --git a/test/rules_122_test.go b/test/rules_122_test.go
index af16a18..f6a16dc 100644
--- a/test/rules_122_test.go
+++ b/test/rules_122_test.go
@@ -2,16 +2,10 @@ package test
 
 import (
 	"testing"
-
-	"github.com/doitintl/kube-no-trouble/pkg/collector"
 )
 
 func TestRego122(t *testing.T) {
-	testCases := []struct {
-		name          string
-		manifests     []string
-		expectedKinds []string // kinds of objects
-	}{
+	testCases := []resourceFixtureTestCase{
 		{"ClusterRole", []string{"../fixtures/clusterrole-v1beta1.yaml"}, []string{"ClusterRole"}},
 		{"ClusterRoleBinding", []string{"../fixtures/clusterrolebinding-v1beta1.yaml"}, []string{"ClusterRoleBinding"}},
 		{"CSIDriver", []string{"../fixtures/csidriver-v1beta1.yaml"}, []string{"CSIDriver"}},
@@ -35,28 +29,5 @@ func TestRego122(t *testing.T) {
 		{"ValidatingWebhookConfiguration", []string{"../fixtures/validatingwebhookconfiguration-v1beta1.yaml"}, []string{"ValidatingWebhookConfiguration"}},
 	}
 
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			c, err := collector.NewFileCollector(
-				&collector.FileOpts{Filenames: tc.manifests},
-			)
-
-			if err != nil {
-				t.Errorf("Expected to succeed for %s, failed: %s", tc.manifests, err)
-			}
-
-			manifests, err := c.Get()
-			if err != nil {
-				t.Errorf("Expected to succeed for %s, failed: %s", tc.manifests, err)
-			} else if len(manifests) != len(tc.expectedKinds) {
-				t.Errorf("Expected to get %d, got %d", len(tc.expectedKinds), len(manifests))
-			}
-
-			for i := range manifests {
-				if manifests[i]["kind"] != tc.expectedKinds[i] {
-					t.Errorf("Expected to get %s, instead got: %s", tc.expectedKinds[i], manifests[i]["kind"])
-				}
-			}
-		})
-	}
+	testReourcesUsingFixtures(t, testCases)
 }
diff --git a/test/rules_125_test.go b/test/rules_125_test.go
new file mode 100644
index 0000000..31944e4
--- /dev/null
+++ b/test/rules_125_test.go
@@ -0,0 +1,13 @@
+package test
+
+import (
+	"testing"
+)
+
+func TestRego125(t *testing.T) {
+	testCases := []resourceFixtureTestCase{
+		{"RuntimeClass", []string{"../fixtures/runtimeclass-v1beta1.yaml"}, []string{"RuntimeClass"}},
+	}
+
+	testReourcesUsingFixtures(t, testCases)
+}