diff --git a/pkg/validations/test-resources/config-with-some-excluded-checks.yaml b/pkg/validations/test-resources/config-with-some-excluded-checks.yaml new file mode 100644 index 00000000..7ad4f0d5 --- /dev/null +++ b/pkg/validations/test-resources/config-with-some-excluded-checks.yaml @@ -0,0 +1,18 @@ +checks: + doNotAutoAddDefaults: false + addAllBuiltIn: true + exclude: + - "unset-cpu-requirements" + - "unset-memory-requirements" + include: + - "host-ipc" + - "host-network" + - "host-pid" + - "non-isolated-pod" + - "pdb-max-unavailable" + - "pdb-min-available" + - "privilege-escalation-container" + - "privileged-container" + - "run-as-non-root" + - "unsafe-sysctls" + \ No newline at end of file diff --git a/pkg/validations/utils.go b/pkg/validations/utils.go index 3872bddc..4065cb20 100644 --- a/pkg/validations/utils.go +++ b/pkg/validations/utils.go @@ -46,7 +46,6 @@ func GetAllNamesFromRegistry(reg checkregistry.CheckRegistry) ([]string, error) AddAllBuiltIn: true, }, } - disableIncompatibleChecks(&cfg) checks, err := configresolver.GetEnabledChecksAndValidate(&cfg, reg) if err != nil { diff --git a/pkg/validations/validation_engine.go b/pkg/validations/validation_engine.go index d1e01301..c5675615 100644 --- a/pkg/validations/validation_engine.go +++ b/pkg/validations/validation_engine.go @@ -204,8 +204,6 @@ func (ve *validationEngine) processResult(result run.Result, namespaceUID string } func (ve *validationEngine) InitRegistry() error { - disableIncompatibleChecks(&ve.config) - registry, err := GetKubeLinterRegistry() if err != nil { return err @@ -331,24 +329,3 @@ func (ve *validationEngine) removeCheckFromConfig(check string) { } } } - -// disableIncompatibleChecks will forcibly update a kube-linter config -// to disable checks that are incompatible with DVO. -// the same check name may end up in the exclude list multiple times as a result of this; this is OK. -func disableIncompatibleChecks(c *config.Config) { - c.Checks.Exclude = append(c.Checks.Exclude, getIncompatibleChecks()...) -} - -// getIncompatibleChecks returns an array of kube-linter check names that are incompatible with DVO -// these checks involve kube-linter comparing properties from multiple kubernetes objects at once. -// (e.g. "non-existent-service-account" checks that all serviceaccounts referenced by deployment objects -// exist as serviceaccount objects). -// DVO currently only performs a check against a single kubernetes object at a time, -// so these checks that compare multiple objects together will always fail. -func getIncompatibleChecks() []string { - return []string{ - "dangling-service", - "non-existent-service-account", - //"non-isolated-pod", - } -} diff --git a/pkg/validations/validation_engine_test.go b/pkg/validations/validation_engine_test.go index ca6b6cfa..99977469 100644 --- a/pkg/validations/validation_engine_test.go +++ b/pkg/validations/validation_engine_test.go @@ -8,14 +8,19 @@ import ( "github.com/prometheus/client_golang/prometheus" promUtils "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" - "golang.stackrox.io/kube-linter/pkg/builtinchecks" - "golang.stackrox.io/kube-linter/pkg/checkregistry" "golang.stackrox.io/kube-linter/pkg/config" - "golang.stackrox.io/kube-linter/pkg/configresolver" appsv1 "k8s.io/api/apps/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) +const ( + customCheckName = "test-minimum-replicas" + customCheckDescription = "some description" + customCheckRemediation = "some remediation" + customCheckTemplate = "minimum-replicas" + testNamespaceUID = "1234-6789-1011-testUID" +) + func TestGetValidChecks(t *testing.T) { testCases := []struct { name string @@ -100,13 +105,6 @@ func TestRemoveCheckFromConfig(t *testing.T) { } } -const ( - customCheckName = "test-minimum-replicas" - customCheckDescription = "some description" - customCheckRemediation = "some remediation" - customCheckTemplate = "minimum-replicas" -) - func newValidationEngine(configPath string, metrics map[string]*prometheus.GaugeVec) (*validationEngine, error) { config, err := loadConfig(configPath) if err != nil { @@ -144,16 +142,6 @@ func newCustomCheck() config.Check { } } -func newEngineConfigWithAllChecks() config.Config { - return config.Config{ - CustomChecks: []config.Check{}, - Checks: config.ChecksConfig{ - AddAllBuiltIn: true, - DoNotAutoAddDefaults: false, - }, - } -} - func createTestDeployment(args testutils.TemplateArgs) (*appsv1.Deployment, error) { d, err := testutils.CreateDeploymentFromTemplate( &args) @@ -199,7 +187,6 @@ func TestUpdateConfig(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ve, err := newValidationEngine("", make(map[string]*prometheus.GaugeVec)) assert.NoError(t, err, "failed to create a new validation engine") - disableIncompatibleChecks(&tt.initialConfig) assert.Equal(t, tt.initialConfig, ve.config) ve.SetConfig(tt.updatedConfig) assert.Equal(t, tt.updatedConfig, ve.config) @@ -246,7 +233,7 @@ func TestRunValidationsForObjects(t *testing.T) { testutils.TemplateArgs{Replicas: int(tt.initialReplicaCount)}) assert.NoError(t, err, "Error creating deployment from template") request := NewRequestFromObject(deployment) - request.NamespaceUID = "1234-6789-1011-testUID" + request.NamespaceUID = testNamespaceUID // run validations with "broken" (replica=1) deployment object _, err = ve.RunValidationsForObjects([]client.Object{deployment}, request.NamespaceUID) @@ -308,7 +295,7 @@ func TestRunValidationsForObjectsAndResetMetrics(t *testing.T) { testutils.TemplateArgs{Replicas: 1, ResourceLimits: false, ResourceRequests: false}) assert.NoError(t, err, "Error creating deployment from template") request := NewRequestFromObject(deployment) - request.NamespaceUID = "1234-6789-1011-testUID" + request.NamespaceUID = testNamespaceUID // run validations with "broken" (replica=1) deployment object _, err = ve.RunValidationsForObjects([]client.Object{deployment}, request.NamespaceUID) @@ -354,40 +341,25 @@ func getMetricValue(v *validationEngine, checkName string, labels prometheus.Lab return int(promUtils.ToFloat64(metric)), nil } -func TestIncompatibleChecksAreDisabled(t *testing.T) { - // Initialize engine - ve, err := newValidationEngine("test-resources/default-config.yaml", make(map[string]*prometheus.GaugeVec)) +func TestExcludedChecksAreNotActive(t *testing.T) { + ve, err := newValidationEngine("test-resources/config-with-some-excluded-checks.yaml", + make(map[string]*prometheus.GaugeVec)) assert.NoError(t, err, "Error initializing engine") - badChecks := getIncompatibleChecks() - allKubeLinterChecks, err := getAllBuiltInKubeLinterChecks() - assert.NoError(t, err, "Got unexpected error while getting all checks built-into kube-linter") - expectedNumChecks := (len(allKubeLinterChecks) - len(badChecks)) - - enabledChecks := ve.enabledChecks - assert.Equal(t, expectedNumChecks, len(enabledChecks), - "Expected exactly %v checks to be enabled, but got '%v' checks from list '%v'", - expectedNumChecks, len(enabledChecks), enabledChecks) - - for _, badCheck := range badChecks { - assert.NotContains(t, enabledChecks, badCheck) - } -} + deployment, err := createTestDeployment( + testutils.TemplateArgs{Replicas: 1, ResourceLimits: false, ResourceRequests: false}) + assert.NoError(t, err, "Error creating deployment from template") + request := NewRequestFromObject(deployment) + request.NamespaceUID = testNamespaceUID -// getAllBuiltInKubeLinterChecks returns every check built-into kube-linter (including checks that DVO disables) -func getAllBuiltInKubeLinterChecks() ([]string, error) { - ve := validationEngine{ - config: newEngineConfigWithAllChecks(), - } - registry := checkregistry.New() - if err := builtinchecks.LoadInto(registry); err != nil { - return nil, fmt.Errorf("failed to load built-in validations: %s", err.Error()) - } + _, err = ve.RunValidationsForObjects([]client.Object{deployment}, request.NamespaceUID) + assert.NoError(t, err) - enabledChecks, err := configresolver.GetEnabledChecksAndValidate(&ve.config, registry) - if err != nil { - return nil, fmt.Errorf("error finding enabled validations: %s", err.Error()) - } + // following two checks are excluded in the corresponding config file + labels := request.ToPromLabels() + _, err = getMetricValue(ve, "unset-cpu-requirements", labels) + assert.Error(t, err, "gauge vector unset-cpu-requirements not found") - return enabledChecks, nil + _, err = getMetricValue(ve, "unset-memory-requirements", labels) + assert.Error(t, err, "gauge vector unset-memory-requirements not found") }