Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: replace Go checks with Rego #7867

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
11 changes: 11 additions & 0 deletions internal/testutil/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/liamg/memoryfs"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -36,6 +37,16 @@ func AssertRuleNotFound(t *testing.T, ruleID string, results scan.Results, messa
assert.False(t, found, append([]any{message}, args...)...)
}

func AssertRuleNotFailed(t *testing.T, ruleID string, results scan.Results, message string, args ...any) {
failedExists := ruleIDInResults(ruleID, results.GetFailed())
assert.False(t, failedExists, append([]any{message}, args...)...)
passedResults := lo.Filter(results, func(res scan.Result, _ int) bool {
return res.Status() == scan.StatusPassed || res.Status() == scan.StatusIgnored
})
passedExists := ruleIDInResults(ruleID, passedResults)
assert.True(t, passedExists, append([]any{message}, args...)...)
}

func ruleIDInResults(ruleID string, results scan.Results) bool {
for _, res := range results {
if res.Rule().LongID() == ruleID {
Expand Down
107 changes: 39 additions & 68 deletions pkg/iac/scanners/terraform/count_test.go
Original file line number Diff line number Diff line change
@@ -1,116 +1,113 @@
package terraform

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"

"github.com/aquasecurity/trivy/internal/testutil"
"github.com/aquasecurity/trivy/pkg/iac/providers"
"github.com/aquasecurity/trivy/pkg/iac/rules"
"github.com/aquasecurity/trivy/pkg/iac/scan"
"github.com/aquasecurity/trivy/pkg/iac/severity"
"github.com/aquasecurity/trivy/pkg/iac/terraform"
"github.com/aquasecurity/trivy/pkg/iac/rego"
)

func Test_ResourcesWithCount(t *testing.T) {
var tests = []struct {
name string
source string
expectedResults int
name string
source string
expected int
}{
{
name: "unspecified count defaults to 1",
source: `
resource "bad" "this" {}
resource "aws_s3_bucket" "test" {}
`,
expectedResults: 1,
expected: 1,
},
{
name: "count is literal 1",
source: `
resource "bad" "this" {
resource "aws_s3_bucket" "test" {
count = 1
}
`,
expectedResults: 1,
expected: 1,
},
{
name: "count is literal 99",
source: `
resource "bad" "this" {
resource "aws_s3_bucket" "test" {
count = 99
}
`,
expectedResults: 99,
expected: 99,
},
{
name: "count is literal 0",
source: `
resource "bad" "this" {
resource "aws_s3_bucket" "test" {
count = 0
}
`,
expectedResults: 0,
expected: 0,
},
{
name: "count is 0 from variable",
source: `
variable "count" {
default = 0
}
resource "bad" "this" {
resource "aws_s3_bucket" "test" {
count = var.count
}
`,
expectedResults: 0,
expected: 0,
},
{
name: "count is 1 from variable",
source: `
variable "count" {
default = 1
}
resource "bad" "this" {
resource "aws_s3_bucket" "test" {
count = var.count
}
`,
expectedResults: 1,
expected: 1,
},
{
name: "count is 1 from variable without default",
source: `
variable "count" {
}
resource "bad" "this" {
resource "aws_s3_bucket" "test" {
count = var.count
}
`,
expectedResults: 1,
expected: 1,
},
{
name: "count is 0 from conditional",
source: `
variable "enabled" {
default = false
}
resource "bad" "this" {
resource "aws_s3_bucket" "test" {
count = var.enabled ? 1 : 0
}
`,
expectedResults: 0,
expected: 0,
},
{
name: "count is 1 from conditional",
source: `
variable "enabled" {
default = true
}
resource "bad" "this" {
resource "aws_s3_bucket" "test" {
count = var.enabled ? 1 : 0
}
`,
expectedResults: 1,
expected: 1,
},
{
name: "issue 962",
Expand All @@ -120,18 +117,18 @@ func Test_ResourcesWithCount(t *testing.T) {
ok = true
}

resource "bad" "bad" {
secure = something.else[0].ok
resource "aws_s3_bucket" "test" {
bucket = something.else[0].ok ? "test" : ""
}
`,
expectedResults: 0,
expected: 0,
},
{
name: "Test use of count.index",
source: `
resource "bad" "thing" {
resource "aws_s3_bucket" "test" {
count = 1
secure = var.things[count.index]["ok"]
bucket = var.things[count.index]["ok"] ? "test" : ""
}

variable "things" {
Expand All @@ -145,49 +142,23 @@ variable "things" {
]
}
`,
expectedResults: 0,
expected: 0,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
r1 := scan.Rule{
Provider: providers.AWSProvider,
Service: "service",
ShortCode: "abc123",
Severity: severity.High,
CustomChecks: scan.CustomChecks{
Terraform: &scan.TerraformCustomCheck{
RequiredLabels: []string{"bad"},
Check: func(resourceBlock *terraform.Block, _ *terraform.Module) (results scan.Results) {
if resourceBlock.GetAttribute("secure").IsTrue() {
return
}
results.Add(
"example problem",
resourceBlock,
)
return
},
},
},
}
reg := rules.Register(r1)
defer rules.Deregister(reg)
results := scanHCL(t, test.source)
var include string
var exclude string
if test.expectedResults > 0 {
include = r1.LongID()
results := scanHCL(t, test.source,
rego.WithPolicyReader(strings.NewReader(emptyBucketCheck)),
rego.WithPolicyNamespaces("user"),
)

assert.Len(t, results.GetFailed(), test.expected)

if test.expected > 0 {
testutil.AssertRuleFound(t, "aws-s3-non-empty-bucket", results, "false negative found")
} else {
exclude = r1.LongID()
}
assert.Len(t, results.GetFailed(), test.expectedResults)
if include != "" {
testutil.AssertRuleFound(t, include, results, "false negative found")
}
if exclude != "" {
testutil.AssertRuleNotFound(t, exclude, results, "false positive found")
testutil.AssertRuleNotFound(t, "aws-s3-non-empty-bucket", results, "false positive found")
}
})
}
Expand Down
26 changes: 9 additions & 17 deletions pkg/iac/scanners/terraform/deterministic_test.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
package terraform

import (
"context"
"strings"
"testing"

"github.com/stretchr/testify/require"

"github.com/aquasecurity/trivy/internal/testutil"
"github.com/aquasecurity/trivy/pkg/iac/rules"
"github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/executor"
"github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser"
"github.com/aquasecurity/trivy/pkg/iac/rego"
)

func Test_DeterministicResults(t *testing.T) {

reg := rules.Register(badRule)
defer rules.Deregister(reg)

fs := testutil.CreateFS(t, map[string]string{
fsys := testutil.CreateFS(t, map[string]string{
"first.tf": `
resource "problem" "uhoh" {
bad = true
for_each = other.thing
resource "aws_s3_bucket" "test" {
for_each = other.thing
}
`,
"second.tf": `
Expand All @@ -40,12 +33,11 @@ locals {
})

for i := 0; i < 100; i++ {
p := parser.New(fs, "", parser.OptionStopOnHCLError(true))
err := p.ParseFS(context.TODO(), ".")
require.NoError(t, err)
modules, _, err := p.EvaluateAll(context.TODO())
results, err := scanFS(fsys, ".",
rego.WithPolicyReader(strings.NewReader(emptyBucketCheck)),
rego.WithPolicyNamespaces("user"),
)
require.NoError(t, err)
results, _ := executor.New().Execute(modules)
require.Len(t, results.GetFailed(), 2)
}
}
Loading