From 10bfc7d513e1497c6fb1cc2becbf85a28554071f Mon Sep 17 00:00:00 2001 From: nikpivkin Date: Wed, 18 Sep 2024 15:00:18 +0600 Subject: [PATCH 1/3] feat(misconf): add ability to disable checks by ID Signed-off-by: nikpivkin --- pkg/iac/rego/load.go | 4 +++ pkg/iac/rego/options.go | 11 +++++++ pkg/iac/rego/scanner.go | 15 +++++---- pkg/iac/rego/scanner_test.go | 59 ++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/pkg/iac/rego/load.go b/pkg/iac/rego/load.go index a1c29d163fae..7959d7f69e01 100644 --- a/pkg/iac/rego/load.go +++ b/pkg/iac/rego/load.go @@ -295,6 +295,10 @@ func (s *Scanner) filterModules(retriever *MetadataRetriever) error { continue } + if _, disabled := s.disabledCheckIDs[meta.ID]; disabled { + continue + } + if len(meta.InputOptions.Selectors) == 0 { s.logger.Warn( "Module has no input selectors - it will be loaded for all inputs!", diff --git a/pkg/iac/rego/options.go b/pkg/iac/rego/options.go index d4b622a68c16..5cc60284abdb 100644 --- a/pkg/iac/rego/options.go +++ b/pkg/iac/rego/options.go @@ -106,3 +106,14 @@ func WithCustomSchemas(schemas map[string][]byte) options.ScannerOption { } } } + +// WithDisabledCheckIDs disables checks by their ID (ID field in metadata) +func WithDisabledCheckIDs(ids ...string) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + for _, id := range ids { + ss.disabledCheckIDs[id] = struct{}{} + } + } + } +} diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index a8e1caf525b3..9cf80fc83da0 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -69,6 +69,8 @@ type Scanner struct { embeddedLibs map[string]*ast.Module embeddedChecks map[string]*ast.Module customSchemas map[string][]byte + + disabledCheckIDs map[string]struct{} } func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { @@ -109,12 +111,13 @@ func NewScanner(source types.Source, opts ...options.ScannerOption) *Scanner { } s := &Scanner{ - regoErrorLimit: ast.CompileErrorLimitDefault, - sourceType: source, - ruleNamespaces: make(map[string]struct{}), - runtimeValues: addRuntimeValues(), - logger: log.WithPrefix("rego"), - customSchemas: make(map[string][]byte), + regoErrorLimit: ast.CompileErrorLimitDefault, + sourceType: source, + ruleNamespaces: make(map[string]struct{}), + runtimeValues: addRuntimeValues(), + logger: log.WithPrefix("rego"), + customSchemas: make(map[string][]byte), + disabledCheckIDs: make(map[string]struct{}), } maps.Copy(s.ruleNamespaces, builtinNamespaces) diff --git a/pkg/iac/rego/scanner_test.go b/pkg/iac/rego/scanner_test.go index 73ef55223f14..a1b47ee14fad 100644 --- a/pkg/iac/rego/scanner_test.go +++ b/pkg/iac/rego/scanner_test.go @@ -1153,3 +1153,62 @@ deny { }) } } + +func Test_RegoScanner_WithDisabledCheckIDs(t *testing.T) { + + check := `# METADATA +# custom: +# id: TEST-001 +# avd_id: AVD-TEST-001 +# severity: LOW +# provider: aws +# service: s3 +# short_code: test +package user.test + +deny { + true +} +` + + tests := []struct { + name string + disabledChecks []string + expected bool + }{ + { + name: "no disabled checks", + expected: true, + }, + { + name: "disable check by ID", + disabledChecks: []string{"TEST-001"}, + }, + { + name: "disabling a non-existent check", + disabledChecks: []string{"FOO"}, + expected: true, + }, + { + name: "one of the identifiers does not exist", + disabledChecks: []string{"FOO", "TEST-001"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + scanner := rego.NewScanner( + types.SourceYAML, + rego.WithPolicyNamespaces("user"), + rego.WithPolicyReader(strings.NewReader(check)), + rego.WithDisabledCheckIDs(tt.disabledChecks...), + ) + + require.NoError(t, scanner.LoadPolicies(nil)) + results, err := scanner.ScanInput(context.TODO(), rego.Input{}) + require.NoError(t, err) + + require.Equal(t, tt.expected, len(results.GetFailed()) > 0) + }) + } +} From 74c92977cc70a6126410c68694464a19d4d58cb4 Mon Sep 17 00:00:00 2001 From: Simar Date: Wed, 25 Sep 2024 23:16:02 -0600 Subject: [PATCH 2/3] check user namespace --- pkg/iac/rego/load.go | 6 +++-- pkg/iac/rego/scanner_test.go | 45 +++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/pkg/iac/rego/load.go b/pkg/iac/rego/load.go index 7959d7f69e01..8f1033ecfa2d 100644 --- a/pkg/iac/rego/load.go +++ b/pkg/iac/rego/load.go @@ -295,8 +295,10 @@ func (s *Scanner) filterModules(retriever *MetadataRetriever) error { continue } - if _, disabled := s.disabledCheckIDs[meta.ID]; disabled { - continue + if IsBuiltinNamespace(getModuleNamespace(module)) { + if _, disabled := s.disabledCheckIDs[meta.ID]; disabled { // ignore builtin disabled checks + continue + } } if len(meta.InputOptions.Selectors) == 0 { diff --git a/pkg/iac/rego/scanner_test.go b/pkg/iac/rego/scanner_test.go index a1b47ee14fad..072f45aaf034 100644 --- a/pkg/iac/rego/scanner_test.go +++ b/pkg/iac/rego/scanner_test.go @@ -10,6 +10,7 @@ import ( "testing" "testing/fstest" + "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/liamg/memoryfs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1164,7 +1165,7 @@ func Test_RegoScanner_WithDisabledCheckIDs(t *testing.T) { # provider: aws # service: s3 # short_code: test -package user.test +package builtin.test deny { true @@ -1174,34 +1175,66 @@ deny { tests := []struct { name string disabledChecks []string + inputCheck string expected bool }{ { - name: "no disabled checks", - expected: true, + name: "no disabled checks", + expected: true, + inputCheck: check, }, { name: "disable check by ID", disabledChecks: []string{"TEST-001"}, + inputCheck: check, }, { name: "disabling a non-existent check", disabledChecks: []string{"FOO"}, expected: true, + inputCheck: check, }, { name: "one of the identifiers does not exist", disabledChecks: []string{"FOO", "TEST-001"}, + inputCheck: check, + }, + { + name: "do not disable user checks with builtin IDs", + inputCheck: `# METADATA +# custom: +# id: TEST-001 +# avd_id: AVD-TEST-001 +# severity: LOW +# provider: aws +# service: s3 +# short_code: test +package user.test + +deny { + true +} +`, + disabledChecks: []string{"TEST-001"}, + expected: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + + opts := []options.ScannerOption{ + rego.WithPolicyReader(strings.NewReader(tt.inputCheck)), + rego.WithDisabledCheckIDs(tt.disabledChecks...), + } + + if tt.inputCheck != "" { + opts = append(opts, rego.WithPolicyNamespaces("user")) + } + scanner := rego.NewScanner( types.SourceYAML, - rego.WithPolicyNamespaces("user"), - rego.WithPolicyReader(strings.NewReader(check)), - rego.WithDisabledCheckIDs(tt.disabledChecks...), + opts..., ) require.NoError(t, scanner.LoadPolicies(nil)) From 7246de40f7ec4f0a0ac7bc1659461c6d6d32aedb Mon Sep 17 00:00:00 2001 From: nikpivkin Date: Thu, 26 Sep 2024 11:44:15 +0600 Subject: [PATCH 3/3] fix test Signed-off-by: nikpivkin --- pkg/iac/rego/scanner_test.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/pkg/iac/rego/scanner_test.go b/pkg/iac/rego/scanner_test.go index 072f45aaf034..1310e56d2ec4 100644 --- a/pkg/iac/rego/scanner_test.go +++ b/pkg/iac/rego/scanner_test.go @@ -10,7 +10,6 @@ import ( "testing" "testing/fstest" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/liamg/memoryfs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1223,18 +1222,11 @@ deny { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - opts := []options.ScannerOption{ - rego.WithPolicyReader(strings.NewReader(tt.inputCheck)), - rego.WithDisabledCheckIDs(tt.disabledChecks...), - } - - if tt.inputCheck != "" { - opts = append(opts, rego.WithPolicyNamespaces("user")) - } - scanner := rego.NewScanner( types.SourceYAML, - opts..., + rego.WithPolicyReader(strings.NewReader(tt.inputCheck)), + rego.WithDisabledCheckIDs(tt.disabledChecks...), + rego.WithPolicyNamespaces("user"), ) require.NoError(t, scanner.LoadPolicies(nil))