feat(misconf): Add support for Minimum Trivy Version (#8880)

Signed-off-by: Simar <simar@linux.com>
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
Co-authored-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
simar7
2025-05-28 15:22:21 -06:00
committed by GitHub
parent 1d420e669f
commit 3b2a3976ac
16 changed files with 523 additions and 127 deletions

View File

@@ -121,17 +121,18 @@ Trivy supports extra fields in the `custom` section as described below.
If you are creating checks for your Trivy misconfiguration scans, some fields are optional as referenced in the table below. The `schemas` field should be used to enable policy validation using a built-in schema. It is recommended to use this to ensure your checks are
correct and do not reference incorrect properties/values.
| Field name | Allowed values | Default value | In table | In JSON |
|----------------------------|-------------------------------------------------------------------|:----------------------------:|:--------:|:-------:|
| title | Any characters | N/A | ✅ | ✅ |
| description | Any characters | | - | ✅ |
| schemas.input | `schema["kubernetes"]`, `schema["dockerfile"]`, `schema["cloud"]` | (applied to all input types) | - | - |
| custom.id | Any characters | N/A | ✅ | ✅ |
| custom.severity | `LOW`, `MEDIUM`, `HIGH`, `CRITICAL` | UNKNOWN | ✅ | ✅ |
| custom.recommended_actions | Any characters | | - | ✅ |
| custom.deprecated | `true`, `false` | `false` | - | ✅ |
| custom.input.selector.type | Any item(s) in [this list][source-types] | | - | ✅ |
| url | Any characters | | - | ✅ |
| Field name | Allowed values | Default value | In table | In JSON |
|------------------------------|---------------------------------------------------------------------|:----------------------------:|:--------:|:-------:|
| title | Any characters | N/A | ✅ | ✅ |
| description | Any characters | | - | ✅ |
| schemas.input | `schema["kubernetes"]`, `schema["dockerfile"]`, `schema["cloud"]` | (applied to all input types) | - | - |
| custom.id | Any characters | N/A | ✅ | ✅ |
| custom.severity | `LOW`, `MEDIUM`, `HIGH`, `CRITICAL` | UNKNOWN | ✅ | ✅ |
| custom.recommended_actions | Any characters | | - | ✅ |
| custom.deprecated | `true`, `false` | `false` | - | ✅ |
| custom.input.selector.type | Any item(s) in [this list][source-types] | | - | ✅ |
| custom.minimum_trivy_version | The minimum version of Trivy that's required to evaluate this check | | - | ✅ |
| url | Any characters | | - | ✅ |
#### custom.avd_id and custom.id

View File

@@ -305,6 +305,7 @@ func compareReports(t *testing.T, wantFile, gotFile string, override func(t *tes
if override != nil {
override(t, &want, &got)
}
assert.Equal(t, want, got)
}

View File

@@ -27,43 +27,49 @@
"Misconfigurations": [
{
"Type": "Dockerfile Security Check",
"ID": "N/A",
"Title": "N/A",
"Description": "Rego module: data.user.bar",
"ID": "AVD-BAR-0001",
"AVDID": "AVD-BAR-0001",
"Title": "Custom policy",
"Description": "Custom policy for testing",
"Message": "something bad: bar",
"Namespace": "user.bar",
"Query": "data.user.bar.deny",
"Severity": "UNKNOWN",
"Resolution": "Custom policy for testing",
"Severity": "LOW",
"Status": "FAIL",
"Layer": {},
"CauseMetadata": {
"Provider": "Generic",
"Service": "general",
"Provider": "Custom",
"Service": "custom",
"Code": {
"Lines": null
}
},
"RenderedCause": {}
}
},
{
"Type": "Dockerfile Security Check",
"ID": "N/A",
"Title": "N/A",
"Description": "Rego module: data.user.foo",
"ID": "AVD-FOO-0001",
"AVDID": "AVD-FOO-0001",
"Title": "Custom policy",
"Description": "Custom policy for testing",
"Message": "something bad: foo",
"Namespace": "user.foo",
"Query": "data.user.foo.deny",
"Severity": "UNKNOWN",
"Resolution": "Custom policy for testing",
"Severity": "LOW",
"Status": "FAIL",
"Layer": {},
"CauseMetadata": {
"Provider": "Generic",
"Service": "general",
"Provider": "Custom",
"Service": "custom",
"Code": {
"Lines": null
}
},
"RenderedCause": {}
}
}
]
}
]
}
}

View File

@@ -1,3 +1,17 @@
# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package user.bar
deny[res] {

View File

@@ -1,3 +1,17 @@
# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-FOO-0001
# avd_id: AVD-FOO-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package user.foo
deny[res] {

View File

@@ -13,6 +13,7 @@ import (
"github.com/open-policy-agent/opa/v1/bundle"
"github.com/samber/lo"
"github.com/aquasecurity/go-version/pkg/semver"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/set"
"github.com/aquasecurity/trivy/pkg/version/doc"
@@ -293,9 +294,33 @@ func (s *Scanner) handleModulesMetadata(path string, module *ast.Module) {
return
}
if metadata != nil {
s.moduleMetadata[path] = metadata
s.moduleMetadata[path] = metadata
}
func (s *Scanner) IsMinimumVersionSupported(metadata *StaticMetadata, module *ast.Module, tv semver.Version) bool {
if metadata.MinimumTrivyVersion == "" { // to ensure compatibility with old modules without minimum trivy version
return true
}
mmsv, err := semver.Parse(metadata.MinimumTrivyVersion)
if err != nil {
s.logger.Warn(
"Failed to parse minimum trivy version - skipping as cannot confirm if module will work with current version",
log.FilePath(module.Package.Location.File),
log.Err(err),
)
return false
}
if tv.LessThan(mmsv) {
s.logger.Warn(
"Module will be skipped as current version of Trivy is older than minimum trivy version required - please update Trivy to use this module",
log.FilePath(module.Package.Location.File),
log.String("minimum_trivy_version", metadata.MinimumTrivyVersion),
)
return false
}
return true
}
// moduleHasLegacyMetadataFormat checks if the module has a legacy metadata format.
@@ -325,8 +350,22 @@ func (s *Scanner) filterModules() error {
return fmt.Errorf("retrieve metadata for module %s: %w", name, err)
}
if s.isModuleApplicable(module, metadata, name) {
filtered[name] = module
if metadata != nil {
tv, err := semver.Parse(s.trivyVersion)
if err != nil {
s.logger.Warn(
"Failed to parse Trivy version - cannot confirm if module will work with current version",
log.String("trivy_version", s.trivyVersion),
log.FilePath(module.Package.Location.File),
log.Err(err),
)
} else if !s.IsMinimumVersionSupported(metadata, module, tv) {
continue
}
if s.isModuleApplicable(module, metadata, name) {
filtered[name] = module
}
}
}

View File

@@ -15,6 +15,7 @@ import (
checks "github.com/aquasecurity/trivy-checks"
"github.com/aquasecurity/trivy/pkg/iac/rego"
"github.com/aquasecurity/trivy/pkg/iac/types"
"github.com/aquasecurity/trivy/pkg/log"
)
@@ -273,3 +274,93 @@ deny := some_func(input)
err := scanner.LoadPolicies(nil)
require.NoError(t, err)
}
func TestIsMinimumTrivyVersion(t *testing.T) {
testCases := []struct {
name string
trivyVersion string
MinimumTrivyVersion string
expectedResults int
expectedErr string
}{
{
name: "trivy version is newer than the check version",
trivyVersion: "1.2.3",
MinimumTrivyVersion: "1.2.0",
expectedResults: 1,
},
{
name: "trivy version is older than the check version",
trivyVersion: "1.2.0",
MinimumTrivyVersion: "1.2.3",
expectedResults: 0,
},
{
name: "trivy version is equal to the check version",
trivyVersion: "1.2.3",
MinimumTrivyVersion: "1.2.3",
expectedResults: 1,
},
{
name: "check version is not a valid semver",
trivyVersion: "1.2.3",
MinimumTrivyVersion: "invalid",
expectedResults: 0,
},
{
name: "trivy version is not a valid semver", // if we cannot parse the version, we fail open to allow the check to run
trivyVersion: "invalid",
MinimumTrivyVersion: "1.2.3",
expectedResults: 1,
},
{
name: "check version is not set",
trivyVersion: "1.2.3",
MinimumTrivyVersion: "",
expectedResults: 1,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fsys := fstest.MapFS{
"check.rego": &fstest.MapFile{Data: []byte(fmt.Sprintf(`# METADATA
# title: "dummy title"
# description: "some description"
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# minimum_trivy_version: "%s"
package builtin.foo.ABC123
deny {
input.evil
}`, tc.MinimumTrivyVersion))},
}
scanner := rego.NewScanner(
rego.WithPolicyDirs("."),
rego.WithEmbeddedLibraries(false),
rego.WithEmbeddedPolicies(false),
rego.WithPolicyFilesystem(fsys),
rego.WithTrivyVersion(tc.trivyVersion),
)
err := scanner.LoadPolicies(nil)
require.NoError(t, err, tc.name)
results, err := scanner.ScanInput(t.Context(), types.SourceJSON, rego.Input{
Path: "/check.rego",
Contents: map[string]any{
"evil": true,
},
FS: fsys,
})
if tc.expectedErr != "" {
assert.ErrorContains(t, err, tc.expectedErr, tc.name)
} else {
require.NoError(t, err)
require.Len(t, results, tc.expectedResults, tc.name)
}
})
}
}

View File

@@ -23,26 +23,27 @@ import (
const annotationScopePackage = "package"
type StaticMetadata struct {
Deprecated bool
ID string
AVDID string
Title string
ShortCode string
Aliases []string
Description string
Severity string
RecommendedActions string
PrimaryURL string
References []string
InputOptions InputOptions
Package string
Frameworks map[framework.Framework][]string
Provider string
Service string
Library bool
CloudFormation *scan.EngineMetadata
Terraform *scan.EngineMetadata
Examples string
Deprecated bool
ID string
AVDID string
Title string
ShortCode string
Aliases []string
Description string
Severity string
RecommendedActions string
PrimaryURL string
References []string
InputOptions InputOptions
Package string
Frameworks map[framework.Framework][]string
Provider string
Service string
Library bool
CloudFormation *scan.EngineMetadata
Terraform *scan.EngineMetadata
Examples string
MinimumTrivyVersion string
}
func NewStaticMetadata(pkgPath string, inputOpt InputOptions) *StaticMetadata {
@@ -80,6 +81,7 @@ func (sm *StaticMetadata) populate(meta map[string]any) error {
upd(&sm.RecommendedActions, "recommended_actions")
upd(&sm.RecommendedActions, "recommended_action")
upd(&sm.Examples, "examples")
upd(&sm.MinimumTrivyVersion, "minimum_trivy_version")
if raw, ok := meta["deprecated"]; ok {
if dep, ok := raw.(bool); ok {
@@ -87,6 +89,10 @@ func (sm *StaticMetadata) populate(meta map[string]any) error {
}
}
if raw, ok := meta["minimum_trivy_version"]; ok {
sm.MinimumTrivyVersion = raw.(string)
}
if raw, ok := meta["severity"]; ok {
sm.Severity = strings.ToUpper(fmt.Sprintf("%s", raw))
}
@@ -265,23 +271,24 @@ func (sm *StaticMetadata) ToRule() scan.Rule {
}
return scan.Rule{
Deprecated: sm.Deprecated,
AVDID: sm.AVDID,
Aliases: append(sm.Aliases, sm.ID),
ShortCode: sm.ShortCode,
Summary: sm.Title,
Explanation: sm.Description,
Impact: "",
Resolution: sm.RecommendedActions,
Provider: providers.Provider(provider),
Service: cmp.Or(sm.Service, "general"),
Links: sm.References,
Severity: severity.Severity(sm.Severity),
RegoPackage: sm.Package,
Frameworks: sm.Frameworks,
CloudFormation: sm.CloudFormation,
Terraform: sm.Terraform,
Examples: sm.Examples,
Deprecated: sm.Deprecated,
AVDID: sm.AVDID,
Aliases: append(sm.Aliases, sm.ID),
ShortCode: sm.ShortCode,
Summary: sm.Title,
Explanation: sm.Description,
Impact: "",
Resolution: sm.RecommendedActions,
Provider: providers.Provider(provider),
Service: cmp.Or(sm.Service, "general"),
Links: sm.References,
Severity: severity.Severity(sm.Severity),
RegoPackage: sm.Package,
Frameworks: sm.Frameworks,
CloudFormation: sm.CloudFormation,
Terraform: sm.Terraform,
Examples: sm.Examples,
MinimumTrivyVersion: sm.MinimumTrivyVersion,
}
}

View File

@@ -14,20 +14,21 @@ import (
func Test_UpdateStaticMetadata(t *testing.T) {
t.Run("happy", func(t *testing.T) {
sm := StaticMetadata{
ID: "i",
AVDID: "a",
Title: "t",
ShortCode: "sc",
Aliases: []string{"a", "b", "c"},
Description: "d",
Severity: "s",
RecommendedActions: "ra",
PrimaryURL: "pu",
References: []string{"r"},
Package: "pkg",
Provider: "pr",
Service: "srvc",
Library: false,
ID: "i",
AVDID: "a",
Title: "t",
ShortCode: "sc",
Aliases: []string{"a", "b", "c"},
Description: "d",
Severity: "s",
RecommendedActions: "ra",
PrimaryURL: "pu",
References: []string{"r"},
Package: "pkg",
Provider: "pr",
Service: "srvc",
Library: false,
MinimumTrivyVersion: "v1.2.3",
}
require.NoError(t, sm.populate(
@@ -47,24 +48,26 @@ func Test_UpdateStaticMetadata(t *testing.T) {
"frameworks": map[string]any{
"all": []any{"aa"},
},
"minimum_trivy_version": "v1.2.3",
},
))
expected := StaticMetadata{
ID: "i_n",
AVDID: "a_n",
Title: "t_n",
ShortCode: "sc_n",
Aliases: []string{"a", "b", "c", "a_n", "b_n", "c_n"},
Description: "d_n",
Severity: "S_N",
RecommendedActions: "ra_n",
PrimaryURL: "pu",
References: []string{"r", "r_n"},
Package: "pkg",
Provider: "pr_n",
Service: "srvc_n",
Library: true,
ID: "i_n",
AVDID: "a_n",
Title: "t_n",
ShortCode: "sc_n",
Aliases: []string{"a", "b", "c", "a_n", "b_n", "c_n"},
Description: "d_n",
Severity: "S_N",
RecommendedActions: "ra_n",
PrimaryURL: "pu",
MinimumTrivyVersion: "v1.2.3",
References: []string{"r", "r_n"},
Package: "pkg",
Provider: "pr_n",
Service: "srvc_n",
Library: true,
Frameworks: map[framework.Framework][]string{
framework.ALL: {"aa"},
},
@@ -248,6 +251,7 @@ func TestMetadataFromAnnotations(t *testing.T) {
# id: test-001
# avd_id: test-001
# severity: LOW
# minimum_trivy_version: 1.2.3
# input:
# selector:
# - type: yaml
@@ -265,7 +269,8 @@ package user.test
},
},
},
Package: "data.user.test",
MinimumTrivyVersion: "1.2.3",
Package: "data.user.test",
Frameworks: map[framework.Framework][]string{
"default": {},
},

View File

@@ -130,3 +130,11 @@ func WithFrameworks(frameworks ...framework.Framework) options.ScannerOption {
}
}
}
func WithTrivyVersion(version string) options.ScannerOption {
return func(s options.ConfigurableScanner) {
if ss, ok := s.(*Scanner); ok {
ss.trivyVersion = version
}
}
}

View File

@@ -61,6 +61,7 @@ type Scanner struct {
includeDeprecatedChecks bool
includeEmbeddedPolicies bool
includeEmbeddedLibraries bool
trivyVersion string
embeddedLibs map[string]*ast.Module
embeddedChecks map[string]*ast.Module

View File

@@ -34,6 +34,21 @@ func Test_RegoScanning_Deny(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny {
@@ -67,7 +82,21 @@ func Test_RegoScanning_AbsolutePolicyPath_Deny(t *testing.T) {
tmp := t.TempDir()
require.NoError(t, os.Mkdir(filepath.Join(tmp, "policies"), 0o755))
require.NoError(t, os.WriteFile(filepath.Join(tmp, "policies", "test.rego"), []byte(`package defsec.test
require.NoError(t, os.WriteFile(filepath.Join(tmp, "policies", "test.rego"), []byte(`# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny {
input.evil
@@ -98,7 +127,21 @@ deny {
func Test_RegoScanning_Allow(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny {
@@ -132,7 +175,21 @@ func Test_RegoScanning_WithRuntimeValues(t *testing.T) {
t.Setenv("DEFSEC_RUNTIME_VAL", "AOK")
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny_evil {
@@ -162,7 +219,21 @@ deny_evil {
func Test_RegoScanning_WithDenyMessage(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny[msg] {
@@ -196,6 +267,21 @@ deny[msg] {
func Test_RegoScanning_WithDenyMetadata_ImpliedPath(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny[res] {
@@ -236,6 +322,21 @@ deny[res] {
func Test_RegoScanning_WithDenyMetadata_PersistedPath(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny[res] {
@@ -337,7 +438,21 @@ deny[res] {
func Test_RegoScanning_WithMatchingInputSelector(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
__rego_input__ := {
@@ -405,7 +520,21 @@ deny {
func Test_RegoScanning_NoTracingByDefault(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny {
@@ -437,7 +566,21 @@ deny {
func Test_RegoScanning_GlobalTracingEnabled(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny {
@@ -473,7 +616,20 @@ deny {
func Test_RegoScanning_PerResultTracingEnabled(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
deny {
@@ -689,7 +845,21 @@ deny {
func Test_RegoScanning_CustomData(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
import data.settings.DS123.foo_bar_baz
@@ -728,7 +898,21 @@ deny {
func Test_RegoScanning_InvalidFS(t *testing.T) {
srcFS := CreateFS(t, map[string]string{
"policies/test.rego": `
"policies/test.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package defsec.test
import data.settings.DS123.foo_bar_baz

View File

@@ -36,25 +36,26 @@ type TerraformCustomCheck struct {
}
type Rule struct {
Deprecated bool `json:"deprecated"`
AVDID string `json:"avd_id"`
Aliases []string `json:"aliases"`
ShortCode string `json:"short_code"`
Summary string `json:"summary"`
Explanation string `json:"explanation"`
Impact string `json:"impact"`
Resolution string `json:"resolution"`
Provider providers.Provider `json:"provider"`
Service string `json:"service"`
Links []string `json:"links"`
Severity severity.Severity `json:"severity"`
Terraform *EngineMetadata `json:"terraform,omitempty"`
CloudFormation *EngineMetadata `json:"cloud_formation,omitempty"`
Examples string `json:"-"`
CustomChecks CustomChecks `json:"-"`
RegoPackage string `json:"-"`
Frameworks map[framework.Framework][]string `json:"frameworks"`
Check CheckFunc `json:"-"`
Deprecated bool `json:"deprecated"`
AVDID string `json:"avd_id"`
Aliases []string `json:"aliases"`
ShortCode string `json:"short_code"`
Summary string `json:"summary"`
Explanation string `json:"explanation"`
Impact string `json:"impact"`
Resolution string `json:"resolution"`
Provider providers.Provider `json:"provider"`
Service string `json:"service"`
Links []string `json:"links"`
Severity severity.Severity `json:"severity"`
Terraform *EngineMetadata `json:"terraform,omitempty"`
CloudFormation *EngineMetadata `json:"cloud_formation,omitempty"`
Examples string `json:"-"`
CustomChecks CustomChecks `json:"-"`
RegoPackage string `json:"-"`
Frameworks map[framework.Framework][]string `json:"frameworks"`
Check CheckFunc `json:"-"`
MinimumTrivyVersion string `json:"minimum_trivy_version"`
}
func (r Rule) IsDeprecated() bool {

View File

@@ -133,7 +133,14 @@ deny[res] {
func Test_YamlWithSeparator(t *testing.T) {
fsys := buildFS(map[string]string{
"check.rego": `package defsec
"check.rego": `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
package defsec
deny[res] {
input.kind == "Pod"

View File

@@ -972,7 +972,22 @@ resource "aws_s3_bucket_versioning" "test" {
`)},
}
check := `package test
check := `# METADATA
# title: Custom policy
# description: Custom policy for testing
# scope: package
# schemas:
# - input: schema["input"]
# custom:
# id: AVD-BAR-0001
# avd_id: AVD-BAR-0001
# provider: custom
# service: custom
# severity: LOW
# short_code: custom-policy
# recommended_action: Custom policy for testing
package test
import rego.v1
deny contains res if {

View File

@@ -34,6 +34,7 @@ import (
tfpjsonscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/tfjson"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/mapfs"
"github.com/aquasecurity/trivy/pkg/version/app"
_ "embed"
)
@@ -246,6 +247,7 @@ func initRegoOptions(opt ScannerOption) ([]options.ScannerOption, error) {
rego.WithEmbeddedLibraries(!opt.DisableEmbeddedLibraries),
rego.WithIncludeDeprecatedChecks(opt.IncludeDeprecatedChecks),
rego.WithDisabledCheckIDs(disabledCheckIDs...),
rego.WithTrivyVersion(app.Version()),
}
policyFS, policyPaths, err := CreatePolicyFS(opt.PolicyPaths)