Skip to content

Commit c002327

Browse files
authored
feat(misconf): support for ignoring by inline comments for Dockerfile (#8115)
Signed-off-by: nikpivkin <[email protected]>
1 parent 6d84e0c commit c002327

File tree

3 files changed

+113
-2
lines changed

3 files changed

+113
-2
lines changed

docs/docs/scanner/misconfiguration/index.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,9 @@ From the Terraform [docs](https://developer.hashicorp.com/terraform/cli/config/c
449449
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.
450450
451451
452-
### Skipping resources by inline comments
452+
### Skipping detected misconfigurations by inline comments
453453
454-
Trivy supports ignoring misconfigured resources by inline comments for Terraform, CloudFormation and Helm configuration files only.
454+
Trivy supports ignoring detected misconfigurations by inline comments for Terraform, CloudFormation (YAML), Helm and Dockerfile configuration files only.
455455
456456
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).
457457
@@ -519,6 +519,13 @@ Example for Helm:
519519
imagePullPolicy: "Always"
520520
```
521521
522+
Example for Dockerfile:
523+
```Dockerfile
524+
FROM scratch
525+
# trivy:ignore:AVD-DS-0022
526+
527+
```
528+
522529
#### Expiration Date
523530
524531
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:

pkg/iac/scanners/dockerfile/scanner_test.go

+72
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package dockerfile_test
33
import (
44
"bytes"
55
"context"
6+
"strings"
67
"testing"
8+
"testing/fstest"
79

810
"github.com/stretchr/testify/assert"
911
"github.com/stretchr/testify/require"
@@ -630,3 +632,73 @@ COPY --from=dep /binary /`
630632
}
631633

632634
}
635+
636+
func Test_IgnoreByInlineComments(t *testing.T) {
637+
tests := []struct {
638+
name string
639+
src string
640+
expected bool
641+
}{
642+
{
643+
name: "without ignore rule",
644+
src: `FROM scratch
645+
MAINTAINER [email protected]`,
646+
expected: true,
647+
},
648+
{
649+
name: "with ignore rule",
650+
src: `FROM scratch
651+
# trivy:ignore:USER-TEST-0001
652+
MAINTAINER [email protected]`,
653+
expected: false,
654+
},
655+
}
656+
657+
check := `# METADATA
658+
# title: test
659+
# schemas:
660+
# - input: schema["dockerfile"]
661+
# custom:
662+
# avd_id: USER-TEST-0001
663+
# short_code: maintainer-deprecated
664+
# input:
665+
# selector:
666+
# - type: dockerfile
667+
package user.test0001
668+
669+
import rego.v1
670+
671+
get_maintainer contains cmd if {
672+
cmd := input.Stages[_].Commands[_]
673+
cmd.Cmd == "maintainer"
674+
}
675+
676+
deny contains res if {
677+
cmd := get_maintainer[_]
678+
msg := sprintf("MAINTAINER should not be used: 'MAINTAINER %s'", [cmd.Value[0]])
679+
res := result.new(msg, cmd)
680+
}
681+
`
682+
683+
for _, tt := range tests {
684+
t.Run(tt.name, func(t *testing.T) {
685+
fsys := fstest.MapFS{
686+
"Dockerfile": &fstest.MapFile{Data: []byte(tt.src)},
687+
}
688+
689+
scanner := dockerfile.NewScanner(
690+
rego.WithPolicyReader(strings.NewReader(check)),
691+
rego.WithPolicyNamespaces("user"),
692+
rego.WithEmbeddedLibraries(true),
693+
rego.WithRegoErrorLimits(0),
694+
)
695+
results, err := scanner.ScanFS(context.TODO(), fsys, ".")
696+
require.NoError(t, err)
697+
if tt.expected {
698+
testutil.AssertRuleFound(t, "dockerfile-general-maintainer-deprecated", results, "")
699+
} else {
700+
testutil.AssertRuleNotFailed(t, "dockerfile-general-maintainer-deprecated", results, "")
701+
}
702+
})
703+
}
704+
}

pkg/iac/scanners/generic/scanner.go

+32
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import (
1212
"sync"
1313

1414
"github.com/BurntSushi/toml"
15+
"github.com/samber/lo"
1516
"gopkg.in/yaml.v3"
1617

18+
"github.com/aquasecurity/trivy/pkg/iac/ignore"
1719
"github.com/aquasecurity/trivy/pkg/iac/rego"
1820
"github.com/aquasecurity/trivy/pkg/iac/scan"
1921
"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
122124
return nil, err
123125
}
124126
results.SetSourceAndFilesystem("", fsys, false)
127+
128+
if err := s.applyIgnoreRules(fsys, results); err != nil {
129+
return nil, err
130+
}
131+
125132
return results, nil
126133
}
127134

135+
func (s *GenericScanner) supportsIgnoreRules() bool {
136+
return s.source == types.SourceDockerfile
137+
}
138+
128139
func (s *GenericScanner) parseFS(ctx context.Context, fsys fs.FS, path string) (map[string]any, error) {
129140
files := make(map[string]any)
130141
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) {
173184
return regoScanner, nil
174185
}
175186

187+
func (s *GenericScanner) applyIgnoreRules(fsys fs.FS, results scan.Results) error {
188+
if !s.supportsIgnoreRules() {
189+
return nil
190+
}
191+
192+
uniqueFiles := lo.Uniq(lo.Map(results.GetFailed(), func(res scan.Result, _ int) string {
193+
return res.Metadata().Range().GetFilename()
194+
}))
195+
196+
for _, filename := range uniqueFiles {
197+
content, err := fs.ReadFile(fsys, filename)
198+
if err != nil {
199+
return err
200+
}
201+
202+
ignoreRules := ignore.Parse(string(content), filename, "")
203+
results.Ignore(ignoreRules, nil)
204+
}
205+
return nil
206+
}
207+
176208
func parseJson(ctx context.Context, r io.Reader, _ string) (any, error) {
177209
var target any
178210
if err := json.NewDecoder(r).Decode(&target); err != nil {

0 commit comments

Comments
 (0)