-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #70 from aquasecurity/add-policy-tests
chore(tests): Add policy based tests
- Loading branch information
Showing
125 changed files
with
1,543 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package test | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/aquasecurity/trivy/pkg/iac/rego" | ||
"github.com/aquasecurity/trivy/pkg/iac/scan" | ||
"github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile" | ||
"github.com/aquasecurity/trivy/pkg/iac/scanners/options" | ||
"github.com/liamg/memoryfs" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func getFileName(fpath string, info os.FileInfo, typePolicy bool) string { | ||
pathParts := strings.Split(fpath, filepath.FromSlash("/")) | ||
fileName := info.Name() | ||
// append test data folder to input file name example Dockerfile.allowed_DS001 | ||
if len(pathParts) > 2 && !typePolicy { | ||
fileName = fmt.Sprintf("%s_%s", fileName, pathParts[len(pathParts)-2]) | ||
} | ||
return fileName | ||
} | ||
|
||
func addFilesToMemFS(memfs *memoryfs.FS, typePolicy bool, folderName string) error { | ||
base := filepath.Base(folderName) | ||
if err := memfs.MkdirAll(base, 0o700); err != nil { | ||
return err | ||
} | ||
err := filepath.Walk(filepath.FromSlash(folderName), | ||
func(fpath string, info os.FileInfo, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
if info.IsDir() { | ||
return nil | ||
} | ||
if typePolicy && !rego.IsRegoFile(info.Name()) { | ||
return nil | ||
} | ||
data, err := os.ReadFile(fpath) | ||
if err != nil { | ||
return err | ||
} | ||
fileName := getFileName(fpath, info, typePolicy) | ||
if err := memfs.WriteFile(path.Join(base, fileName), data, 0o644); err != nil { | ||
return err | ||
} | ||
return nil | ||
}) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func Test_Docker_RegoPoliciesFromDisk(t *testing.T) { | ||
t.Parallel() | ||
|
||
entries, err := os.ReadDir("./testdata/dockerfile") | ||
require.NoError(t, err) | ||
|
||
policiesPath, err := filepath.Abs("../checks/docker") | ||
require.NoError(t, err) | ||
scanner := dockerfile.NewScanner( | ||
options.ScannerWithPolicyDirs(filepath.Base(policiesPath)), | ||
options.ScannerWithEmbeddedLibraries(true), | ||
) | ||
memfs := memoryfs.New() | ||
// add policies | ||
err = addFilesToMemFS(memfs, true, policiesPath) | ||
require.NoError(t, err) | ||
|
||
// add test data | ||
testDataPath, err := filepath.Abs("./testdata/dockerfile") | ||
require.NoError(t, err) | ||
err = addFilesToMemFS(memfs, false, testDataPath) | ||
require.NoError(t, err) | ||
|
||
results, err := scanner.ScanFS(context.TODO(), memfs, filepath.Base(testDataPath)) | ||
require.NoError(t, err) | ||
|
||
for _, entry := range entries { | ||
if !entry.IsDir() { | ||
continue | ||
} | ||
t.Run(entry.Name(), func(t *testing.T) { | ||
require.NoError(t, err) | ||
t.Run(entry.Name(), func(t *testing.T) { | ||
var matched int | ||
for _, result := range results { | ||
if result.Rule().HasID(entry.Name()) && result.Status() == scan.StatusFailed { | ||
if result.Description() != "Specify at least 1 USER command in Dockerfile with non-root user as argument" { | ||
assert.Greater(t, result.Range().GetStartLine(), 0) | ||
assert.Greater(t, result.Range().GetEndLine(), 0) | ||
} | ||
if !strings.HasSuffix(result.Range().GetFilename(), entry.Name()) { | ||
continue | ||
} | ||
matched++ | ||
} | ||
} | ||
assert.Equal(t, 1, matched, "Rule should be matched once") | ||
}) | ||
|
||
}) | ||
} | ||
} | ||
|
||
func Test_Docker_RegoPoliciesEmbedded(t *testing.T) { | ||
t.Parallel() | ||
|
||
entries, err := os.ReadDir("./testdata/dockerfile") | ||
require.NoError(t, err) | ||
|
||
scanner := dockerfile.NewScanner(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)) | ||
srcFS := os.DirFS("../") | ||
|
||
results, err := scanner.ScanFS(context.TODO(), srcFS, "test/testdata/dockerfile") | ||
require.NoError(t, err) | ||
|
||
for _, entry := range entries { | ||
if !entry.IsDir() { | ||
continue | ||
} | ||
t.Run(entry.Name(), func(t *testing.T) { | ||
require.NoError(t, err) | ||
t.Run(entry.Name(), func(t *testing.T) { | ||
var matched bool | ||
for _, result := range results { | ||
if result.Rule().HasID(entry.Name()) && result.Status() == scan.StatusFailed { | ||
if result.Description() != "Specify at least 1 USER command in Dockerfile with non-root user as argument" { | ||
assert.Greater(t, result.Range().GetStartLine(), 0) | ||
assert.Greater(t, result.Range().GetEndLine(), 0) | ||
} | ||
assert.Equal(t, fmt.Sprintf("test/testdata/dockerfile/%s/Dockerfile.denied", entry.Name()), result.Range().GetFilename()) | ||
matched = true | ||
} | ||
} | ||
assert.True(t, matched) | ||
}) | ||
|
||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package test | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/aquasecurity/trivy/pkg/iac/scan" | ||
"github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes" | ||
"github.com/aquasecurity/trivy/pkg/iac/scanners/options" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func Test_Kubernetes_RegoPoliciesFromDisk(t *testing.T) { | ||
t.Parallel() | ||
|
||
entries, err := os.ReadDir("./testdata/kubernetes") | ||
require.NoError(t, err) | ||
|
||
scanner := kubernetes.NewScanner( | ||
options.ScannerWithPerResultTracing(true), | ||
options.ScannerWithEmbeddedPolicies(true), | ||
options.ScannerWithEmbeddedLibraries(true), | ||
) | ||
|
||
srcFS := os.DirFS("../") | ||
|
||
results, err := scanner.ScanFS(context.TODO(), srcFS, "test/testdata/kubernetes") | ||
require.NoError(t, err) | ||
|
||
for _, entry := range entries { | ||
if !entry.IsDir() { | ||
continue | ||
} | ||
if entry.Name() == "optional" { | ||
continue | ||
} | ||
t.Run(entry.Name(), func(t *testing.T) { | ||
var matched bool | ||
for _, result := range results { | ||
if result.Rule().HasID(entry.Name()) { | ||
|
||
failCase := fmt.Sprintf("test/testdata/kubernetes/%s/denied.yaml", entry.Name()) | ||
passCase := fmt.Sprintf("test/testdata/kubernetes/%s/allowed.yaml", entry.Name()) | ||
|
||
switch result.Range().GetFilename() { | ||
case failCase: | ||
assert.Equal(t, scan.StatusFailed, result.Status(), "Rule should have failed, but didn't.") | ||
assert.Greater(t, result.Range().GetStartLine(), 0, "We should have line numbers for a failure") | ||
assert.Greater(t, result.Range().GetEndLine(), 0, "We should have line numbers for a failure") | ||
matched = true | ||
case passCase: | ||
assert.Equal(t, scan.StatusPassed, result.Status(), "Rule should have passed, but didn't.") | ||
matched = true | ||
default: | ||
if strings.Contains(result.Range().GetFilename(), entry.Name()) { | ||
t.Fatal(result.Range().GetFilename()) | ||
} | ||
continue | ||
} | ||
|
||
if t.Failed() { | ||
fmt.Println("Test failed - rego trace follows:") | ||
for _, trace := range result.Traces() { | ||
fmt.Println(trace) | ||
} | ||
} | ||
} | ||
} | ||
assert.True(t, matched, "Neither a pass or fail result was found for %s - did you add example code for it?", entry.Name()) | ||
}) | ||
} | ||
} | ||
|
||
func Test_Kubernetes_RegoPoliciesEmbedded(t *testing.T) { | ||
t.Parallel() | ||
|
||
entries, err := os.ReadDir("./testdata/kubernetes") | ||
require.NoError(t, err) | ||
|
||
scanner := kubernetes.NewScanner(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true), options.ScannerWithEmbeddedLibraries(true)) | ||
|
||
srcFS := os.DirFS("../") | ||
|
||
results, err := scanner.ScanFS(context.TODO(), srcFS, "test/testdata/kubernetes") | ||
require.NoError(t, err) | ||
|
||
for _, entry := range entries { | ||
if !entry.IsDir() { | ||
continue | ||
} | ||
if entry.Name() == "optional" { | ||
continue | ||
} | ||
t.Run(entry.Name(), func(t *testing.T) { | ||
var matched bool | ||
for _, result := range results { | ||
if result.Rule().HasID(entry.Name()) { | ||
|
||
failCase := fmt.Sprintf("test/testdata/kubernetes/%s/denied.yaml", entry.Name()) | ||
passCase := fmt.Sprintf("test/testdata/kubernetes/%s/allowed.yaml", entry.Name()) | ||
|
||
switch result.Range().GetFilename() { | ||
case failCase: | ||
assert.Equal(t, scan.StatusFailed, result.Status(), "Rule should have failed, but didn't.") | ||
assert.Greater(t, result.Range().GetStartLine(), 0, "We should have line numbers for a failure") | ||
assert.Greater(t, result.Range().GetEndLine(), 0, "We should have line numbers for a failure") | ||
matched = true | ||
case passCase: | ||
assert.Equal(t, scan.StatusPassed, result.Status(), "Rule should have passed, but didn't.") | ||
matched = true | ||
default: | ||
continue | ||
} | ||
|
||
if t.Failed() { | ||
fmt.Println("Test failed - rego trace follows:") | ||
for _, trace := range result.Traces() { | ||
fmt.Println(trace) | ||
} | ||
} | ||
} | ||
} | ||
assert.True(t, matched, "Neither a pass or fail result was found for %s - did you add example code for it?", entry.Name()) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/aquasecurity/trivy/pkg/iac/framework" | ||
"github.com/aquasecurity/trivy/pkg/iac/rules" | ||
) | ||
|
||
func TestAVDIDs(t *testing.T) { | ||
existing := make(map[string]struct{}) | ||
for _, rule := range rules.GetRegistered(framework.ALL) { | ||
t.Run(rule.LongID(), func(t *testing.T) { | ||
if rule.GetRule().AVDID == "" { | ||
t.Errorf("Rule has no AVD ID: %#v", rule) | ||
return | ||
} | ||
if _, ok := existing[rule.GetRule().AVDID]; ok { | ||
t.Errorf("Rule detected with duplicate AVD ID: %s", rule.GetRule().AVDID) | ||
} | ||
}) | ||
existing[rule.GetRule().AVDID] = struct{}{} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
FROM debian:9 | ||
RUN apt-get update && apt-get -y install vim && apt-get clean | ||
USER foo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
FROM debian:latest | ||
RUN apt-get update && apt-get -y install vim && apt-get clean | ||
USER foo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
FROM debian:9 | ||
RUN apt-get update && apt-get -y install vim && apt-get clean | ||
USER foo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
FROM debian:9 | ||
RUN apt-get update && apt-get -y install vim && apt-get clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
FROM alpine:3.13 | ||
USER mike | ||
EXPOSE 8080 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
FROM alpine:3.13 | ||
USER mike | ||
EXPOSE 22 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
FROM alpine:3.13 | ||
USER mike | ||
ADD "/target/resources.tar.gz" "resources" |
Oops, something went wrong.