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

Support newer format versions for terraform JSON plan #1691

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ require (
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.22.1
github.com/open-policy-agent/opa v0.46.1
github.com/owenrumney/go-sarif/v2 v2.1.2
github.com/owenrumney/go-sarif/v2 v2.3.3
github.com/pelletier/go-toml v1.9.5
github.com/pkg/errors v0.9.1
github.com/spf13/afero v1.6.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -957,8 +957,8 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U=
github.com/owenrumney/go-sarif/v2 v2.1.2 h1:PMDK7tXShJ9zsB7bfvlpADH5NEw1dfA9xwU8Xtdj73U=
github.com/owenrumney/go-sarif/v2 v2.1.2/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w=
github.com/owenrumney/go-sarif/v2 v2.3.3 h1:ubWDJcF5i3L/EIOER+ZyQ03IfplbSU1BLOE26uKQIIU=
github.com/owenrumney/go-sarif/v2 v2.3.3/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w=
github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
Expand Down
2 changes: 1 addition & 1 deletion pkg/iac-providers/tfplan/v1/load-file.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var (
)

func getTfPlanFormatVersions() []string {
return []string{"0.1", "0.2"}
return []string{"0.1", "0.2", "1.0", "1.1", "1.2"}
}

// LoadIacFile parses the given tfplan file from the given file path
Expand Down
12 changes: 7 additions & 5 deletions pkg/policy/opa/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ func (e *Engine) reportViolation(regoData *policy.RegoData, resource *output.Res
Category: regoData.Metadata.Category,
RuleFile: regoData.Metadata.File,
RuleData: regoData.RawRego,
ResourceID: resource.ID,
ResourceName: resource.Name,
ResourceType: resource.Type,
ResourceData: resource.Config,
Expand Down Expand Up @@ -340,11 +341,12 @@ func (e *Engine) reportViolation(regoData *policy.RegoData, resource *output.Res
// reportPassed Adds a passed rule which wasn't violated by all the resources
func (e *Engine) reportPassed(regoData *policy.RegoData) {
passedRule := results.PassedRule{
RuleName: regoData.Metadata.Name,
Description: regoData.Metadata.Description,
RuleID: regoData.Metadata.ID,
Severity: regoData.Metadata.Severity,
Category: regoData.Metadata.Category,
RuleName: regoData.Metadata.Name,
Description: regoData.Metadata.Description,
RuleID: regoData.Metadata.ID,
Severity: regoData.Metadata.Severity,
Category: regoData.Metadata.Category,
ResourceType: regoData.Metadata.ResourceType,
}

e.results.ViolationStore.AddPassedRule(&passedRule)
Expand Down
12 changes: 7 additions & 5 deletions pkg/results/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Violation struct {
RuleFile string `json:"-" yaml:"-" xml:"-"`
RuleData interface{} `json:"-" yaml:"-" xml:"-"`
Comment string `json:"skip_comment,omitempty" yaml:"skip_comment,omitempty" xml:"skip_comment,omitempty"`
ResourceID string `json:"resource_id" yaml:"resource_id" xml:"resource_id,attr"`
ResourceName string `json:"resource_name" yaml:"resource_name" xml:"resource_name,attr"`
ResourceType string `json:"resource_type" yaml:"resource_type" xml:"resource_type,attr"`
ResourceData interface{} `json:"-" yaml:"-" xml:"-"`
Expand All @@ -42,11 +43,12 @@ type Violation struct {

// PassedRule contains information of a passed rule
type PassedRule struct {
RuleName string `json:"rule_name" yaml:"rule_name" xml:"rule_name,attr"`
Description string `json:"description" yaml:"description" xml:"description,attr"`
RuleID string `json:"rule_id" yaml:"rule_id" xml:"rule_id,attr"`
Severity string `json:"severity" yaml:"severity" xml:"severity,attr"`
Category string `json:"category" yaml:"category" xml:"category,attr"`
RuleName string `json:"rule_name" yaml:"rule_name" xml:"rule_name,attr"`
Description string `json:"description" yaml:"description" xml:"description,attr"`
RuleID string `json:"rule_id" yaml:"rule_id" xml:"rule_id,attr"`
Severity string `json:"severity" yaml:"severity" xml:"severity,attr"`
Category string `json:"category" yaml:"category" xml:"category,attr"`
ResourceType string `json:"resource_type" yaml:"resource_type" xml:"resource_type,attr"`
}

// ViolationStore Storage area for violation data
Expand Down
57 changes: 41 additions & 16 deletions pkg/runtime/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,26 @@ import (
"reflect"
"testing"

"github.com/hashicorp/go-multierror"
tfv15 "github.com/tenable/terrascan/pkg/iac-providers/terraform/v15"
"github.com/tenable/terrascan/pkg/results"
"github.com/tenable/terrascan/pkg/vulnerability"
"github.com/stretchr/testify/assert"

"github.com/tenable/terrascan/pkg/config"
iacProvider "github.com/tenable/terrascan/pkg/iac-providers"
armv1 "github.com/tenable/terrascan/pkg/iac-providers/arm/v1"
cftv1 "github.com/tenable/terrascan/pkg/iac-providers/cft/v1"
dockerv1 "github.com/tenable/terrascan/pkg/iac-providers/docker/v1"
helmv3 "github.com/tenable/terrascan/pkg/iac-providers/helm/v3"
k8sv1 "github.com/tenable/terrascan/pkg/iac-providers/kubernetes/v1"
kustomizev4 "github.com/tenable/terrascan/pkg/iac-providers/kustomize/v4"
"github.com/tenable/terrascan/pkg/iac-providers/output"
tfv12 "github.com/tenable/terrascan/pkg/iac-providers/terraform/v12"
tfv14 "github.com/tenable/terrascan/pkg/iac-providers/terraform/v14"
"github.com/tenable/terrascan/pkg/notifications/webhook"

"github.com/tenable/terrascan/pkg/config"
"github.com/tenable/terrascan/pkg/iac-providers/output"
tfv15 "github.com/tenable/terrascan/pkg/iac-providers/terraform/v15"
"github.com/tenable/terrascan/pkg/notifications"
"github.com/tenable/terrascan/pkg/notifications/webhook"
"github.com/tenable/terrascan/pkg/policy"
"github.com/tenable/terrascan/pkg/results"
"github.com/tenable/terrascan/pkg/utils"
"github.com/tenable/terrascan/pkg/vulnerability"
)

var (
Expand Down Expand Up @@ -77,6 +76,7 @@ func (m MockIacProvider) Name() string {
// mock policy engine
type MockPolicyEngine struct {
err error
out policy.EngineOutput
}
type MockVulnerabilityEngine struct {
out vulnerability.EngineOutput
Expand All @@ -97,7 +97,7 @@ func (m MockPolicyEngine) Configure() error {
}

func (m MockPolicyEngine) Evaluate(input policy.EngineInput, filter policy.PreScanFilter) (out policy.EngineOutput, err error) {
return out, m.err
return m.out, m.err
}

func (m MockVulnerabilityEngine) ReportVulnerability(input vulnerability.EngineInput, options map[string]interface{}) (out vulnerability.EngineOutput) {
Expand Down Expand Up @@ -125,14 +125,15 @@ func TestExecute(t *testing.T) {
configWithError bool
executor Executor
wantErr error
wantResults *Output
}{
{
name: "test LoadIacDir error",
executor: Executor{
dirPath: testDir,
iacProviders: []iacProvider.IacProvider{MockIacProvider{err: errMockLoadIacDir}},
},
wantErr: multierror.Append(errMockLoadIacDir),
wantErr: errMockLoadIacDir,
},
{
name: "test LoadIacDir no error",
Expand All @@ -155,11 +156,32 @@ func TestExecute(t *testing.T) {
{
name: "test LoadIacFile no error",
executor: Executor{
filePath: filepath.Join(testDataDir, "testfile"),
iacProviders: []iacProvider.IacProvider{MockIacProvider{err: nil}},
policyEngines: []policy.Engine{MockPolicyEngine{err: nil}},
filePath: filepath.Join(testDataDir, "testfile"),
iacProviders: []iacProvider.IacProvider{MockIacProvider{err: nil}},
policyEngines: []policy.Engine{MockPolicyEngine{err: nil, out: policy.EngineOutput{
ViolationStore: &results.ViolationStore{
Violations: []*results.Violation{{
ResourceID: "id",
ResourceName: "name",
}},
},
}}},
},
wantErr: nil,
wantResults: &Output{
ResourceConfig: output.AllResourceConfigs(nil),
Violations: policy.EngineOutput{
ViolationStore: &results.ViolationStore{
Summary: results.ScanSummary{
ResourcePath: "testdata/testfile",
},
Violations: []*results.Violation{{
ResourceID: "id",
ResourceName: "name",
}},
},
},
},
},
{
name: "test SendNotifications no error",
Expand Down Expand Up @@ -227,9 +249,12 @@ func TestExecute(t *testing.T) {

for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
_, gotErr := tt.executor.Execute(tt.configOnly, tt.configWithError)
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
gotResults, gotErr := tt.executor.Execute(tt.configOnly, tt.configWithError)
assert.ErrorIs(t, gotErr, tt.wantErr)
if tt.wantResults != nil {
// Check output (only specific fields as testify no support for ignoring fields)
assert.Equal(t, tt.wantResults.Violations.Summary.ResourcePath, gotResults.Violations.Summary.ResourcePath)
assert.Equal(t, tt.wantResults.Violations.Violations, gotResults.Violations.Violations)
}
})
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/utils/jqhelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func JQFilterWithQuery(jqQuery string, jsonInput []byte) ([]byte, error) {
}

// run jq query on input
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
iter := query.RunWithContext(ctx, input)
for {
Expand All @@ -53,13 +53,13 @@ func JQFilterWithQuery(jqQuery string, jsonInput []byte) ([]byte, error) {
break
}
if err, ok := v.(error); ok {
zap.S().Warn("error in processing jq query; error: '%v'", err)
zap.S().Warnf("error in processing jq query; error: '%v'", err)
continue
}

jqout, err := json.Marshal(v)
if err != nil {
zap.S().Warn("failed to encode jq output into JSON. error: '%v'", err)
zap.S().Warnf("failed to encode jq output into JSON. error: '%v'", err)
continue
}
processed = append(processed, jqout...)
Expand Down
4 changes: 3 additions & 1 deletion pkg/writer/github_sarif_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

const violationTemplateForGH = `{
"version": "2.1.0",
"$schema": "https://json.schemastore.org/sarif-2.1.0-rtm.5.json",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
"runs": [
{
"tool": {
Expand All @@ -29,6 +29,7 @@ const violationTemplateForGH = `{
},
"properties": {
"category": "S3",
"resource_type": "aws_s3_bucket",
"severity": "HIGH"
}
}
Expand Down Expand Up @@ -58,6 +59,7 @@ const violationTemplateForGH = `{
"logicalLocations": [
{
"name": "bucket",
"decoratedName": "aws_s3_bucket.bucket",
"kind": "aws_s3_bucket"
}
]
Expand Down
22 changes: 12 additions & 10 deletions pkg/writer/human_readable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ var (
ViolationStore: &results.ViolationStore{
PassedRules: []*results.PassedRule{
{
RuleName: "s3EnforceUserACL",
Description: "S3 bucket Access is allowed to all AWS Account Users.",
RuleID: "AWS.S3Bucket.DS.High.1043",
Severity: "HIGH",
Category: "S3",
RuleName: "s3EnforceUserACL",
Description: "S3 bucket Access is allowed to all AWS Account Users.",
RuleID: "AWS.S3Bucket.DS.High.1043",
Severity: "HIGH",
Category: "S3",
ResourceType: "aws_s3_bucket",
},
},
Summary: summaryWithNoViolations,
Expand All @@ -53,11 +54,12 @@ var (
},
PassedRules: []*results.PassedRule{
{
RuleName: "s3EnforceUserACL",
Description: "S3 bucket Access is allowed to all AWS Account Users.",
RuleID: "AWS.S3Bucket.DS.High.1043",
Severity: "HIGH",
Category: "S3",
RuleName: "s3EnforceUserACL",
Description: "S3 bucket Access is allowed to all AWS Account Users.",
RuleID: "AWS.S3Bucket.DS.High.1043",
Severity: "HIGH",
Category: "S3",
ResourceType: "aws_s3_bucket",
},
},
Summary: summaryWithNoViolations,
Expand Down
2 changes: 2 additions & 0 deletions pkg/writer/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
"rule_id": "AWS.S3Bucket.DS.High.1043",
"severity": "HIGH",
"category": "S3",
"resource_id": "aws_s3_bucket.bucket",
"resource_name": "bucket",
"resource_type": "aws_s3_bucket",
"file": "modules/m1/main.tf",
Expand All @@ -49,6 +50,7 @@ const (
"rule_id": "AWS.S3Bucket.DS.High.1043",
"severity": "HIGH",
"category": "S3",
"resource_id": "aws_s3_bucket.bucket",
"resource_name": "bucket",
"resource_type": "aws_s3_bucket",
"file": "modules/m1/main.tf",
Expand Down
10 changes: 8 additions & 2 deletions pkg/writer/sarif.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func writeSarif(data interface{}, writers []io.Writer, forGitHub bool) error {
for _, passedRule := range outputData.PassedRules {
m := sarif.NewPropertyBag()
m.Properties["category"] = passedRule.Category
m.Properties["resource_type"] = passedRule.ResourceType
m.Properties["severity"] = passedRule.Severity

run.AddRule(passedRule.RuleID).
Expand All @@ -67,6 +68,7 @@ func writeSarif(data interface{}, writers []io.Writer, forGitHub bool) error {
for _, violation := range outputData.Violations {
m := sarif.NewPropertyBag()
m.Properties["category"] = violation.Category
m.Properties["resource_type"] = violation.ResourceType
m.Properties["severity"] = violation.Severity

rule := run.AddRule(violation.RuleID).
Expand All @@ -93,8 +95,12 @@ func writeSarif(data interface{}, writers []io.Writer, forGitHub bool) error {
WithArtifactLocation(artifactLocation).WithRegion(sarif.NewRegion().WithStartLine(violation.LineNumber)))

if len(violation.ResourceType) > 0 && len(violation.ResourceName) > 0 {
location.LogicalLocations = append(location.LogicalLocations, sarif.NewLogicalLocation().
WithKind(violation.ResourceType).WithName(violation.ResourceName))
ll := sarif.NewLogicalLocation().
WithKind(violation.ResourceType).WithName(violation.ResourceName)
if len(violation.ResourceID) > 0 {
ll.WithDecoratedName(violation.ResourceID)
}
location.LogicalLocations = append(location.LogicalLocations, ll)
}

run.AddResult(sarif.NewRuleResult(rule.ID).
Expand Down
Loading