From ccb96953b7a9e2ce631ab8d7c84ea99ce04960bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Mon, 24 Jul 2023 15:23:39 +0200 Subject: [PATCH 01/10] fix: Don't emit both Info & Error logs for PolicyReports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this fix, we were doing log.Info().Err(err), which emits a one-line log that is both info and error: {"level":"info","error":"resource not found","namespace":"demo2","time":"2023-07-24T15:23:17+02:00","message":"no pre-existing PolicyReport, will create one at the end of the scan"} Signed-off-by: Víctor Cuadrado Juan --- internal/scanner/scanner.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go index e9b6190c..e419ecc5 100644 --- a/internal/scanner/scanner.go +++ b/internal/scanner/scanner.go @@ -94,9 +94,12 @@ func (s *Scanner) ScanNamespace(nsName string) error { namespacedsReport.Summary.Skip = skippedNum // old policy report to be used as cache previousNamespacedReport, err := s.reportStore.GetPolicyReport(nsName) - if err != nil { - log.Info().Err(err).Str("namespace", nsName). - Msg("no pre-existing PolicyReport, will create one at the end of the scan") + if errors.Is(err, constants.ErrResourceNotFound) { + log.Info().Str("namespace", nsName). + Msg("no pre-existing PolicyReport, will create one at end of the scan if needed") + } else if err != nil { + log.Err(err).Str("namespace", nsName). + Msg("error when obtaining PolicyReport") } // Iterate through all auditableResources. Each item contains a list of resources and the policies that would need From 478f74fd621fb4860a5c2255948b966320c15570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Mon, 24 Jul 2023 15:28:56 +0200 Subject: [PATCH 02/10] fix: Skip clusterwide resources in getResourcesForPolicies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are looking for namespaced resources, clusterwide resources get checked in getClusterWideResourcesForPolicies() Signed-off-by: Víctor Cuadrado Juan --- internal/resources/fetcher.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/internal/resources/fetcher.go b/internal/resources/fetcher.go index 8a75d9ca..c8b3508c 100644 --- a/internal/resources/fetcher.go +++ b/internal/resources/fetcher.go @@ -59,7 +59,8 @@ func NewFetcher(kubewardenNamespace string, policyServerURL string) (*Fetcher, e return &Fetcher{dynamicClient, kubewardenNamespace, policyServerURL, clientset}, nil } -// GetResourcesForPolicies fetches all resources that must be audited and returns them in an AuditableResources array. +// GetResourcesForPolicies fetches all namespaced resources that must be audited +// in a specific namespace and returns them in an AuditableResources array. // Iterates through all the rules in the policies to find all relevant resources. It creates a GVR (Group Version Resource) // array for each rule defined in a policy. Then fetches and aggregates the GVRs for all the policies. // Returns an array of AuditableResources. Each entry of the array will contain and array of resources of the same kind, and an array of @@ -69,6 +70,21 @@ func (f *Fetcher) GetResourcesForPolicies(ctx context.Context, policies []polici auditableResources := []AuditableResources{} gvrMap := createGVRPolicyMap(policies) for resourceFilter, policies := range gvrMap { + isNamespaced, err := f.isNamespacedResource(resourceFilter.groupVersionResource) + if err != nil { + if errors.Is(err, constants.ErrResourceNotFound) { + log.Warn(). + Str("resource GVK", resourceFilter.groupVersionResource.String()). + Msg("API resource not found") + continue + } + return nil, err + } + if !isNamespaced { + // continue if resource is clusterwide + continue + } + resources, err := f.getResourcesDynamically(ctx, &resourceFilter, namespace) // continue if resource doesn't exist. if apimachineryerrors.IsNotFound(err) { From 6682cbd733333ff2c24a516d77c2b78295f07580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Mon, 24 Jul 2023 15:54:22 +0200 Subject: [PATCH 03/10] fix: Warn instead of panic when API resource not found or forbidden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When policies are configured with a spec.rules GVK, if resource doesn't exist because it has an incorrect GVK, or if because it is a CRD that we don't know about, emit warning and skip resource from scan. The same for when policies are configured with a spec.rules GVK that the audit-scanner lacks permissions for, emit warning and skip resource from scan. Signed-off-by: Víctor Cuadrado Juan --- internal/resources/fetcher.go | 38 ++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/internal/resources/fetcher.go b/internal/resources/fetcher.go index c8b3508c..89d761d4 100644 --- a/internal/resources/fetcher.go +++ b/internal/resources/fetcher.go @@ -8,6 +8,7 @@ import ( "github.com/kubewarden/audit-scanner/internal/constants" policiesv1 "github.com/kubewarden/kubewarden-controller/pkg/apis/policies/v1" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" apimachineryerrors "k8s.io/apimachinery/pkg/api/errors" @@ -86,8 +87,23 @@ func (f *Fetcher) GetResourcesForPolicies(ctx context.Context, policies []polici } resources, err := f.getResourcesDynamically(ctx, &resourceFilter, namespace) - // continue if resource doesn't exist. if apimachineryerrors.IsNotFound(err) { + // continue if resource doesn't exist + log.Warn(). + Dict("dict", zerolog.Dict(). + Str("resource GVK", resourceFilter.groupVersionResource.String()). + Str("ns", namespace), + ).Msg("API resource not found") + continue + } + if apimachineryerrors.IsForbidden(err) { + // continue if ServiceAccount lacks permissions, GVK may not exist, or + // policies may be misconfigured + log.Warn(). + Dict("dict", zerolog.Dict(). + Str("resource GVK", resourceFilter.groupVersionResource.String()). + Str("ns", namespace), + ).Msg("API resource forbidden, unknown GVK or ServiceAccount lacks permissions") continue } if err != nil { @@ -135,7 +151,9 @@ func (f *Fetcher) GetClusterWideResourcesForPolicies(ctx context.Context, polici isNamespaced, err := f.isNamespacedResource(resourceFilter.groupVersionResource) if err != nil { if errors.Is(err, constants.ErrResourceNotFound) { - log.Warn().Msg(fmt.Sprintf("API resource (%s) not found", resourceFilter.groupVersionResource.String())) + log.Warn(). + Str("resource GVK", resourceFilter.groupVersionResource.String()). + Msg("API resource not found") continue } return nil, err @@ -144,10 +162,24 @@ func (f *Fetcher) GetClusterWideResourcesForPolicies(ctx context.Context, polici continue } resources, err := f.getClusterWideResourcesDynamically(ctx, &resourceFilter) - // continue if resource doesn't exist. if apimachineryerrors.IsNotFound(err) { + // continue if resource doesn't exist + log.Warn(). + Dict("dict", zerolog.Dict(). + Str("resource GVK", resourceFilter.groupVersionResource.String()), + ).Msg("API resource not found") continue } + if apimachineryerrors.IsForbidden(err) { + // continue if ServiceAccount lacks permissions, GVK may not exist, or + // policies may be misconfigured + log.Warn(). + Dict("dict", zerolog.Dict(). + Str("resource GVK", resourceFilter.groupVersionResource.String()), + ).Msg("API resource forbidden, unknown GVK or ServiceAccount lacks permissions") + continue + } + if err != nil { return nil, err } From 4de1fafbbf87f8ac765e28e2a8e13787595ba8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Mon, 24 Jul 2023 15:57:08 +0200 Subject: [PATCH 04/10] docs: locally run with a specific ServiceAccount MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Víctor Cuadrado Juan --- CONTRIBUTING.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4466d79b..e87da912 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ PolicyReports CRDs. And the audit feature is disabled by default. Then: -``` console +```console kubectl port-forward -n kubewarden service/policy-server-default 3000:8443 ./bin/audit-scanner \ @@ -16,9 +16,34 @@ kubectl port-forward -n kubewarden service/policy-server-default 3000:8443 or to get results in JSON: -``` console +```console ./bin/audit-scanner \ -k kubewarden --namespace default \ --policy-server-url https://localhost:3000 \ -l debug --print ``` + +### Run against audit-scanner SA + +To run with the `audit-scanner` ServiceAccount, install `kubewarden-controller` +chart, and, with the help of the kubectl [view-serviceaccount-kubeconfig](https://github.com/superbrothers/kubectl-view-serviceaccount-kubeconfig-plugin) +plugin: + +```console +kubectl create token audit-scanner -n kubewarden | kubectl view-serviceaccount-kubeconfig > ./kubeconfig +``` + +If needed, patch the resulting kubeconfig, adding the missing +`certificate-authority`. E.g: + +```yaml +clusters: +- cluster: + certificate-authority: /home/vic/.minikube/ca.crt +``` + +And use it: + +```console +export KUBECONFIG=./kubeconfig +``` From 3ee10864c912d172010907f1eaf1fe4db3ed35a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Tue, 25 Jul 2023 12:00:52 +0200 Subject: [PATCH 05/10] chore: Reword info message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Víctor Cuadrado Juan --- internal/scanner/scanner.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go index e419ecc5..ea25d6b9 100644 --- a/internal/scanner/scanner.go +++ b/internal/scanner/scanner.go @@ -210,7 +210,7 @@ func auditClusterResource(resource *resources.AuditableResources, resourcesFetch Str("policyUID", string(policy.GetUID())). Str("resource", resource.GetName()). Str("resourceResourceVersion", resource.GetResourceVersion()), - ).Msg("Previous result found. Reuse result") + ).Msg("Previous result found. Reusing result") continue } admissionRequest := resources.GenerateAdmissionReview(resource) @@ -259,7 +259,7 @@ func auditResource(toBeAudited *resources.AuditableResources, resourcesFetcher R Str("policyUID", string(policy.GetUID())). Str("resource", resource.GetName()). Str("resourceResourceVersion", resource.GetResourceVersion()), - ).Msg("Previous result found. Reuse result") + ).Msg("Previous result found. Reusing result") continue } From c41a12a08e71659ff64e29fe804004d56afc7a66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Tue, 25 Jul 2023 13:15:32 +0200 Subject: [PATCH 06/10] tests: Add fakeClient now that we check if res are namespaced MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed, as we need a client when we do `fetcher.isNamespacedResource()`. Signed-off-by: Víctor Cuadrado Juan --- internal/resources/fetcher_test.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/internal/resources/fetcher_test.go b/internal/resources/fetcher_test.go index a32ea161..982dbe06 100644 --- a/internal/resources/fetcher_test.go +++ b/internal/resources/fetcher_test.go @@ -115,6 +115,26 @@ func TestGetResourcesForPolicies(t *testing.T) { dynamicClient := fake.NewSimpleDynamicClient(customScheme, &policy1, &pod1, &pod2, &pod3, &deployment1) + apiResourceList := metav1.APIResourceList{ + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + { + Name: "namespaces", + SingularName: "namespace", + Kind: "Namespace", + Namespaced: false, + }, + { + Name: "pods", + SingularName: "pod", + Kind: "Pod", + Namespaced: true, + }, + }, + } + fakeClientSet := fakekubernetes.NewSimpleClientset() + fakeClientSet.Resources = []*metav1.APIResourceList{&apiResourceList} + unstructuredPod1 := map[string]interface{}{ "apiVersion": "v1", "kind": "Pod", @@ -155,7 +175,7 @@ func TestGetResourcesForPolicies(t *testing.T) { Resources: []unstructured.Unstructured{{Object: unstructuredPod3}}, }} - fetcher := Fetcher{dynamicClient, "", "", nil} + fetcher := Fetcher{dynamicClient, "", "", fakeClientSet} tests := []struct { name string From 925e0186c93bae626a83df84f0a6498f0137d5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Tue, 25 Jul 2023 13:17:18 +0200 Subject: [PATCH 07/10] tests: Add test for incorrect GVKs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Víctor Cuadrado Juan --- internal/resources/fetcher_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/internal/resources/fetcher_test.go b/internal/resources/fetcher_test.go index 982dbe06..573c5fba 100644 --- a/internal/resources/fetcher_test.go +++ b/internal/resources/fetcher_test.go @@ -21,6 +21,7 @@ import ( ) // policies for testing + var policy1 = policiesv1.AdmissionPolicy{ Spec: policiesv1.AdmissionPolicySpec{PolicySpec: policiesv1.PolicySpec{ Rules: []admissionregistrationv1.RuleWithOperations{{ @@ -35,6 +36,7 @@ var policy1 = policiesv1.AdmissionPolicy{ }}, } +// used to test incorrect or unknown GVKs var policy2 = policiesv1.ClusterAdmissionPolicy{ Spec: policiesv1.ClusterAdmissionPolicySpec{PolicySpec: policiesv1.PolicySpec{ Rules: []admissionregistrationv1.RuleWithOperations{{ @@ -79,6 +81,21 @@ var policy4 = policiesv1.AdmissionPolicy{ }}, } +// used to test incorrect or unknown GVKs +var policyIncorrectRules = policiesv1.ClusterAdmissionPolicy{ + Spec: policiesv1.ClusterAdmissionPolicySpec{PolicySpec: policiesv1.PolicySpec{ + Rules: []admissionregistrationv1.RuleWithOperations{{ + Operations: nil, + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{""}, + APIVersions: []string{"v1"}, + Resources: []string{"pods", "Unexistent"}, + }, + }, + }, + }}, +} + func TestGetResourcesForPolicies(t *testing.T) { pod1 := v1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -175,6 +192,11 @@ func TestGetResourcesForPolicies(t *testing.T) { Resources: []unstructured.Unstructured{{Object: unstructuredPod3}}, }} + expectedPIncorrectRules := []AuditableResources{{ + Policies: []policiesv1.Policy{&policyIncorrectRules}, + Resources: []unstructured.Unstructured{{Object: unstructuredPod1}}, + // note that the resource "Unexistent" is correctly missing here + }} fetcher := Fetcher{dynamicClient, "", "", fakeClientSet} tests := []struct { @@ -186,6 +208,7 @@ func TestGetResourcesForPolicies(t *testing.T) { {"policy1 (just pods)", []policiesv1.Policy{&policy1}, expectedP1, "default"}, {"no policies", []policiesv1.Policy{}, []AuditableResources{}, "default"}, {"policy with label filter", []policiesv1.Policy{&policy4}, expectedP4, "kubewarden"}, + {"we skip incorrect GVKs", []policiesv1.Policy{&policyIncorrectRules}, expectedPIncorrectRules, "default"}, } for _, test := range tests { From ff99749c71e64547179d6e18fa01221bffd6ef3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Tue, 25 Jul 2023 13:17:44 +0200 Subject: [PATCH 08/10] tests: Add test to show clusterwide res are skipped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Víctor Cuadrado Juan --- internal/resources/fetcher_test.go | 31 +++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/internal/resources/fetcher_test.go b/internal/resources/fetcher_test.go index 573c5fba..dfc92eeb 100644 --- a/internal/resources/fetcher_test.go +++ b/internal/resources/fetcher_test.go @@ -96,6 +96,21 @@ var policyIncorrectRules = policiesv1.ClusterAdmissionPolicy{ }}, } +// used to test skipping of clusterwide resources +var policyPodsNamespaces = policiesv1.ClusterAdmissionPolicy{ + Spec: policiesv1.ClusterAdmissionPolicySpec{PolicySpec: policiesv1.PolicySpec{ + Rules: []admissionregistrationv1.RuleWithOperations{{ + Operations: nil, + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{""}, + APIVersions: []string{"v1"}, + Resources: []string{"pods", "namespaces"}, + }, + }, + }, + }}, +} + func TestGetResourcesForPolicies(t *testing.T) { pod1 := v1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -126,11 +141,17 @@ func TestGetResourcesForPolicies(t *testing.T) { }, Spec: appsv1.DeploymentSpec{}, } + namespace1 := v1.Namespace{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-namespace", + }, + } customScheme := scheme.Scheme customScheme.AddKnownTypes(policiesv1.GroupVersion, &policiesv1.ClusterAdmissionPolicy{}, &policiesv1.AdmissionPolicy{}, &policiesv1.ClusterAdmissionPolicyList{}, &policiesv1.AdmissionPolicyList{}) metav1.AddToGroupVersion(customScheme, policiesv1.GroupVersion) - dynamicClient := fake.NewSimpleDynamicClient(customScheme, &policy1, &pod1, &pod2, &pod3, &deployment1) + dynamicClient := fake.NewSimpleDynamicClient(customScheme, &policy1, &pod1, &pod2, &pod3, &deployment1, &namespace1) apiResourceList := metav1.APIResourceList{ GroupVersion: "v1", @@ -197,6 +218,13 @@ func TestGetResourcesForPolicies(t *testing.T) { Resources: []unstructured.Unstructured{{Object: unstructuredPod1}}, // note that the resource "Unexistent" is correctly missing here }} + + expectedPPodsNamespaces := []AuditableResources{{ + Policies: []policiesv1.Policy{&policyPodsNamespaces}, + Resources: []unstructured.Unstructured{{Object: unstructuredPod1}}, + // note that the namespacej resource is correctly missing here + }} + fetcher := Fetcher{dynamicClient, "", "", fakeClientSet} tests := []struct { @@ -209,6 +237,7 @@ func TestGetResourcesForPolicies(t *testing.T) { {"no policies", []policiesv1.Policy{}, []AuditableResources{}, "default"}, {"policy with label filter", []policiesv1.Policy{&policy4}, expectedP4, "kubewarden"}, {"we skip incorrect GVKs", []policiesv1.Policy{&policyIncorrectRules}, expectedPIncorrectRules, "default"}, + {"we skip clusterwide resources", []policiesv1.Policy{&policyPodsNamespaces}, expectedPPodsNamespaces, "default"}, // namespaces get filtered } for _, test := range tests { From 04c72ca52a8343df86e56b17322dce8bbec113ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Tue, 25 Jul 2023 15:34:37 +0200 Subject: [PATCH 09/10] tests: Add TestLackOfPermsWhenGettingResources() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a test that checks that we don't error nor panic when trying to filter resources that are forbidden (because the client lacks permissions, normally because the ServiceAccount is insufficient). Signed-off-by: Víctor Cuadrado Juan --- internal/resources/fetcher_test.go | 85 +++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/internal/resources/fetcher_test.go b/internal/resources/fetcher_test.go index dfc92eeb..0f8efb0a 100644 --- a/internal/resources/fetcher_test.go +++ b/internal/resources/fetcher_test.go @@ -11,13 +11,17 @@ import ( admissionregistrationv1 "k8s.io/api/admissionregistration/v1" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" + + apimachineryerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic/fake" + fakekubernetes "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/scheme" + clienttesting "k8s.io/client-go/testing" ) // policies for testing @@ -708,3 +712,82 @@ func TestIsNamespacedResource(t *testing.T) { }) } } + +func TestLackOfPermsWhenGettingResources(t *testing.T) { + pod1 := v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "podDefault", + Namespace: "default", + }, + Spec: v1.PodSpec{}, + } + namespace1 := v1.Namespace{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-namespace", + }, + } + customScheme := scheme.Scheme + customScheme.AddKnownTypes(policiesv1.GroupVersion, &policiesv1.ClusterAdmissionPolicy{}, &policiesv1.AdmissionPolicy{}, &policiesv1.ClusterAdmissionPolicyList{}, &policiesv1.AdmissionPolicyList{}) + metav1.AddToGroupVersion(customScheme, policiesv1.GroupVersion) + + dynamicClient := fake.NewSimpleDynamicClient(customScheme, &policy1, &pod1, &namespace1) + // simulate lacking permissions when listing pods or namespaces. This should + // make the filtering skip these resources, and produce no error + dynamicClient.PrependReactor("list", "pods", + func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, apimachineryerrors.NewForbidden(schema.GroupResource{ + Resource: "pods", + }, "", errors.New("reason")) + }) + dynamicClient.PrependReactor("list", "namespaces", + func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, apimachineryerrors.NewForbidden(schema.GroupResource{ + Resource: "namespaces", + }, "", errors.New("reason")) + }) + + apiResourceList := metav1.APIResourceList{ + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + { + Name: "namespaces", + SingularName: "namespace", + Kind: "Namespace", + Namespaced: false, + }, + { + Name: "pods", + SingularName: "pod", + Kind: "Pod", + Namespaced: true, + }, + }, + } + fakeClientSet := fakekubernetes.NewSimpleClientset() + fakeClientSet.Resources = []*metav1.APIResourceList{&apiResourceList} + + // the pairs policies,resources should be empty, as pods,namespaces have + // been skipped because of lack of permissions + expectedP1 := []AuditableResources{} + + fetcher := Fetcher{dynamicClient, "", "", fakeClientSet} + + resources, err := fetcher.GetResourcesForPolicies(context.Background(), []policiesv1.Policy{&policy1}, "default") + if err != nil { + t.Errorf("error shouldn't have happened " + err.Error()) + } + if !cmp.Equal(resources, expectedP1) { + diff := cmp.Diff(expectedP1, resources) + t.Errorf("Invalid resources: %s", diff) + } + + resources, err = fetcher.GetClusterWideResourcesForPolicies(context.Background(), []policiesv1.Policy{&policy1}) + if err != nil { + t.Errorf("error shouldn't have happened " + err.Error()) + } + if !cmp.Equal(resources, expectedP1) { + diff := cmp.Diff(expectedP1, resources) + t.Errorf("Invalid resources: %s", diff) + } +} From 91944ce9bd0261056015e9daffe182b3e4fc78af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Cuadrado=20Juan?= Date: Tue, 25 Jul 2023 15:45:20 +0200 Subject: [PATCH 10/10] chore: Make golint-ci happy, and me a bit less MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Víctor Cuadrado Juan --- internal/policies/fetcher.go | 2 +- internal/resources/fetcher_test.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/policies/fetcher.go b/internal/policies/fetcher.go index 744d28be..aa9a13dd 100644 --- a/internal/policies/fetcher.go +++ b/internal/policies/fetcher.go @@ -194,7 +194,7 @@ func (f *Fetcher) getAdmissionPolicies(namespace string) ([]policiesv1.Admission return policies.Items, nil } -func newClient() (client.Client, error) { //nolint +func newClient() (client.Client, error) { //nolint:ireturn config := ctrl.GetConfigOrDie() customScheme := scheme.Scheme customScheme.AddKnownTypes( diff --git a/internal/resources/fetcher_test.go b/internal/resources/fetcher_test.go index 0f8efb0a..001f8bdb 100644 --- a/internal/resources/fetcher_test.go +++ b/internal/resources/fetcher_test.go @@ -735,13 +735,13 @@ func TestLackOfPermsWhenGettingResources(t *testing.T) { // simulate lacking permissions when listing pods or namespaces. This should // make the filtering skip these resources, and produce no error dynamicClient.PrependReactor("list", "pods", - func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { + func(action clienttesting.Action) (bool, runtime.Object, error) { return true, nil, apimachineryerrors.NewForbidden(schema.GroupResource{ Resource: "pods", }, "", errors.New("reason")) }) dynamicClient.PrependReactor("list", "namespaces", - func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { + func(action clienttesting.Action) (bool, runtime.Object, error) { return true, nil, apimachineryerrors.NewForbidden(schema.GroupResource{ Resource: "namespaces", }, "", errors.New("reason")) @@ -767,7 +767,7 @@ func TestLackOfPermsWhenGettingResources(t *testing.T) { fakeClientSet := fakekubernetes.NewSimpleClientset() fakeClientSet.Resources = []*metav1.APIResourceList{&apiResourceList} - // the pairs policies,resources should be empty, as pods,namespaces have + // the pairs (policies,resources) should be empty, as (pods,namespaces) have // been skipped because of lack of permissions expectedP1 := []AuditableResources{}