diff --git a/integration/fs_test.go b/integration/fs_test.go index dc052bf79783..06f086e8a326 100644 --- a/integration/fs_test.go +++ b/integration/fs_test.go @@ -23,6 +23,7 @@ func TestFilesystem(t *testing.T) { listAllPkgs bool input string secretConfig string + filePatterns []string } tests := []struct { name string @@ -79,6 +80,16 @@ func TestFilesystem(t *testing.T) { }, golden: "testdata/dockerfile.json.golden", }, + { + name: "dockerfile with custom file pattern", + args: args{ + securityChecks: "config", + input: "testdata/fixtures/fs/dockerfile_file_pattern", + namespaces: []string{"testing"}, + filePatterns: []string{"dockerfile:Customfile"}, + }, + golden: "testdata/dockerfile_file_pattern.json.golden", + }, { name: "dockerfile with rule exception", args: args{ @@ -178,6 +189,12 @@ func TestFilesystem(t *testing.T) { defer os.Remove(trivyIgnore) } + if len(tt.args.filePatterns) != 0 { + for _, filePattern := range tt.args.filePatterns { + osArgs = append(osArgs, "--file-patterns", filePattern) + } + } + // Setup the output file outputFile := filepath.Join(t.TempDir(), "output.json") if *update { diff --git a/integration/testdata/dockerfile_file_pattern.json.golden b/integration/testdata/dockerfile_file_pattern.json.golden new file mode 100644 index 000000000000..f6c727c351ff --- /dev/null +++ b/integration/testdata/dockerfile_file_pattern.json.golden @@ -0,0 +1,56 @@ +{ + "SchemaVersion": 2, + "ArtifactName": "testdata/fixtures/fs/dockerfile_file_pattern", + "ArtifactType": "filesystem", + "Metadata": { + "ImageConfig": { + "architecture": "", + "created": "0001-01-01T00:00:00Z", + "os": "", + "rootfs": { + "type": "", + "diff_ids": null + }, + "config": {} + } + }, + "Results": [ + { + "Target": "Customfile", + "Class": "config", + "Type": "dockerfile", + "MisconfSummary": { + "Successes": 21, + "Failures": 1, + "Exceptions": 0 + }, + "Misconfigurations": [ + { + "Type": "Dockerfile Security Check", + "ID": "DS002", + "Title": "Image user should not be 'root'", + "Description": "Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.", + "Message": "Specify at least 1 USER command in Dockerfile with non-root user as argument", + "Namespace": "builtin.dockerfile.DS002", + "Query": "data.builtin.dockerfile.DS002.deny", + "Resolution": "Add 'USER \u003cnon root user name\u003e' line to the Dockerfile", + "Severity": "HIGH", + "PrimaryURL": "https://avd.aquasec.com/misconfig/ds002", + "References": [ + "https://docs.docker.com/develop/develop-images/dockerfile_best-practices/", + "https://avd.aquasec.com/misconfig/ds002" + ], + "Status": "FAIL", + "Layer": {}, + "CauseMetadata": { + "Provider": "Dockerfile", + "Service": "general", + "Code": { + "Lines": null + } + } + } + ] + } + ] +} diff --git a/integration/testdata/fixtures/fs/dockerfile_file_pattern/Customfile b/integration/testdata/fixtures/fs/dockerfile_file_pattern/Customfile new file mode 100644 index 000000000000..c390060f0464 --- /dev/null +++ b/integration/testdata/fixtures/fs/dockerfile_file_pattern/Customfile @@ -0,0 +1 @@ +FROM alpine:3.13 \ No newline at end of file diff --git a/pkg/fanal/handler/misconf/misconf.go b/pkg/fanal/handler/misconf/misconf.go index 4fc924bdc3fb..c5c3425c997e 100644 --- a/pkg/fanal/handler/misconf/misconf.go +++ b/pkg/fanal/handler/misconf/misconf.go @@ -39,7 +39,8 @@ func init() { const version = 1 type misconfPostHandler struct { - scanners map[string]scanners.Scanner + filePatterns []string + scanners map[string]scanners.Scanner } // for a given set of paths, find the most specific filesystem path that contains all the descendants @@ -177,6 +178,7 @@ func newMisconfPostHandler(artifactOpt artifact.Option) (handler.PostHandler, er } return misconfPostHandler{ + filePatterns: artifactOpt.MisconfScannerOption.FilePatterns, scanners: map[string]scanners.Scanner{ types.Terraform: tfscanner.New(opts...), types.CloudFormation: cfscanner.New(opts...), @@ -197,6 +199,15 @@ var enabledDefsecTypes = map[detection.FileType]string{ detection.FileTypeRbac: types.Rbac, } +func (h misconfPostHandler) hasCustomPatternForType(t string) bool { + for _, pattern := range h.filePatterns { + if strings.HasPrefix(pattern, t+":") { + return true + } + } + return false +} + // Handle detects misconfigurations. func (h misconfPostHandler) Handle(ctx context.Context, result *analyzer.AnalysisResult, blob *types.BlobInfo) error { files, ok := result.Files[h.Type()] @@ -214,7 +225,7 @@ func (h misconfPostHandler) Handle(ctx context.Context, result *analyzer.Analysi for defsecType, localType := range enabledDefsecTypes { buffer := bytes.NewReader(file.Content) - if !detection.IsType(file.Path, buffer, defsecType) { + if !h.hasCustomPatternForType(localType) && !detection.IsType(file.Path, buffer, defsecType) { continue } // Replace with more detailed config type