mirror of
https://github.com/aquasecurity/trivy.git
synced 2026-01-31 13:53:14 +08:00
feat(misconf): support for ignoring by inline comments for Dockerfile (#8115)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
@@ -449,9 +449,9 @@ From the Terraform [docs](https://developer.hashicorp.com/terraform/cli/config/c
|
||||
If multiple variables evaluate to the same hostname, Trivy will choose the environment variable name where the dashes have not been encoded as double underscores.
|
||||
|
||||
|
||||
### Skipping resources by inline comments
|
||||
### Skipping detected misconfigurations by inline comments
|
||||
|
||||
Trivy supports ignoring misconfigured resources by inline comments for Terraform, CloudFormation and Helm configuration files only.
|
||||
Trivy supports ignoring detected misconfigurations by inline comments for Terraform, CloudFormation (YAML), Helm and Dockerfile configuration files only.
|
||||
|
||||
In cases where Trivy can detect comments of a specific format immediately adjacent to resource definitions, it is possible to ignore findings from a single source of resource definition (in contrast to `.trivyignore`, which has a directory-wide scope on all of the files scanned). The format for these comments is `trivy:ignore:<rule>` immediately following the format-specific line-comment [token](https://developer.hashicorp.com/terraform/language/syntax/configuration#comments).
|
||||
|
||||
@@ -519,6 +519,13 @@ Example for Helm:
|
||||
imagePullPolicy: "Always"
|
||||
```
|
||||
|
||||
Example for Dockerfile:
|
||||
```Dockerfile
|
||||
FROM scratch
|
||||
# trivy:ignore:AVD-DS-0022
|
||||
MAINTAINER moby@example.com
|
||||
```
|
||||
|
||||
#### Expiration Date
|
||||
|
||||
You can specify the expiration date of the ignore rule in `yyyy-mm-dd` format. This is a useful feature when you want to make sure that an ignored issue is not forgotten and worth revisiting in the future. For example:
|
||||
|
||||
@@ -3,7 +3,9 @@ package dockerfile_test
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -630,3 +632,73 @@ COPY --from=dep /binary /`
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_IgnoreByInlineComments(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
src string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "without ignore rule",
|
||||
src: `FROM scratch
|
||||
MAINTAINER moby@example.com`,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "with ignore rule",
|
||||
src: `FROM scratch
|
||||
# trivy:ignore:USER-TEST-0001
|
||||
MAINTAINER moby@example.com`,
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
check := `# METADATA
|
||||
# title: test
|
||||
# schemas:
|
||||
# - input: schema["dockerfile"]
|
||||
# custom:
|
||||
# avd_id: USER-TEST-0001
|
||||
# short_code: maintainer-deprecated
|
||||
# input:
|
||||
# selector:
|
||||
# - type: dockerfile
|
||||
package user.test0001
|
||||
|
||||
import rego.v1
|
||||
|
||||
get_maintainer contains cmd if {
|
||||
cmd := input.Stages[_].Commands[_]
|
||||
cmd.Cmd == "maintainer"
|
||||
}
|
||||
|
||||
deny contains res if {
|
||||
cmd := get_maintainer[_]
|
||||
msg := sprintf("MAINTAINER should not be used: 'MAINTAINER %s'", [cmd.Value[0]])
|
||||
res := result.new(msg, cmd)
|
||||
}
|
||||
`
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fsys := fstest.MapFS{
|
||||
"Dockerfile": &fstest.MapFile{Data: []byte(tt.src)},
|
||||
}
|
||||
|
||||
scanner := dockerfile.NewScanner(
|
||||
rego.WithPolicyReader(strings.NewReader(check)),
|
||||
rego.WithPolicyNamespaces("user"),
|
||||
rego.WithEmbeddedLibraries(true),
|
||||
rego.WithRegoErrorLimits(0),
|
||||
)
|
||||
results, err := scanner.ScanFS(context.TODO(), fsys, ".")
|
||||
require.NoError(t, err)
|
||||
if tt.expected {
|
||||
testutil.AssertRuleFound(t, "dockerfile-general-maintainer-deprecated", results, "")
|
||||
} else {
|
||||
testutil.AssertRuleNotFailed(t, "dockerfile-general-maintainer-deprecated", results, "")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,10 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/samber/lo"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/iac/ignore"
|
||||
"github.com/aquasecurity/trivy/pkg/iac/rego"
|
||||
"github.com/aquasecurity/trivy/pkg/iac/scan"
|
||||
"github.com/aquasecurity/trivy/pkg/iac/scanners/options"
|
||||
@@ -122,9 +124,18 @@ func (s *GenericScanner) ScanFS(ctx context.Context, fsys fs.FS, dir string) (sc
|
||||
return nil, err
|
||||
}
|
||||
results.SetSourceAndFilesystem("", fsys, false)
|
||||
|
||||
if err := s.applyIgnoreRules(fsys, results); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (s *GenericScanner) supportsIgnoreRules() bool {
|
||||
return s.source == types.SourceDockerfile
|
||||
}
|
||||
|
||||
func (s *GenericScanner) parseFS(ctx context.Context, fsys fs.FS, path string) (map[string]any, error) {
|
||||
files := make(map[string]any)
|
||||
if err := fs.WalkDir(fsys, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error {
|
||||
@@ -173,6 +184,27 @@ func (s *GenericScanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) {
|
||||
return regoScanner, nil
|
||||
}
|
||||
|
||||
func (s *GenericScanner) applyIgnoreRules(fsys fs.FS, results scan.Results) error {
|
||||
if !s.supportsIgnoreRules() {
|
||||
return nil
|
||||
}
|
||||
|
||||
uniqueFiles := lo.Uniq(lo.Map(results.GetFailed(), func(res scan.Result, _ int) string {
|
||||
return res.Metadata().Range().GetFilename()
|
||||
}))
|
||||
|
||||
for _, filename := range uniqueFiles {
|
||||
content, err := fs.ReadFile(fsys, filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ignoreRules := ignore.Parse(string(content), filename, "")
|
||||
results.Ignore(ignoreRules, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseJson(ctx context.Context, r io.Reader, _ string) (any, error) {
|
||||
var target any
|
||||
if err := json.NewDecoder(r).Decode(&target); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user