Skip to content

Commit

Permalink
fix: Fix regression of missing parameterised ignore rules (#1504)
Browse files Browse the repository at this point in the history
  • Loading branch information
liamg committed Feb 7, 2022
1 parent 35ff105 commit 7cd3fe5
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 7 deletions.
47 changes: 43 additions & 4 deletions internal/pkg/block/ignore.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/aquasecurity/defsec/types"
"github.com/zclconf/go-cty/cty"
)

type Ignore struct {
Expand All @@ -15,20 +16,21 @@ type Ignore struct {
Expiry *time.Time
Workspace string
Block bool
Params map[string]string
}

type Ignores []Ignore

func (ignores Ignores) Covering(m types.Metadata, workspace string, ids ...string) *Ignore {
func (ignores Ignores) Covering(modules Modules, m types.Metadata, workspace string, ids ...string) *Ignore {
for _, ignore := range ignores {
if ignore.Covering(m, workspace, ids...) {
if ignore.Covering(modules, m, workspace, ids...) {
return &ignore
}
}
return nil
}

func (ignore Ignore) Covering(m types.Metadata, workspace string, ids ...string) bool {
func (ignore Ignore) Covering(modules Modules, m types.Metadata, workspace string, ids ...string) bool {
if ignore.Expiry != nil && time.Now().After(*ignore.Expiry) {
return false
}
Expand Down Expand Up @@ -57,10 +59,47 @@ func (ignore Ignore) Covering(m types.Metadata, workspace string, ids ...string)
continue
}
if metaHierarchy.Range().GetStartLine() == ignore.Range.GetStartLine()+1 || metaHierarchy.Range().GetStartLine() == ignore.Range.GetStartLine() {
return true
return ignore.MatchParams(modules)
}
metaHierarchy = metaHierarchy.Parent()
}
return false

}

func (ignore Ignore) MatchParams(modules Modules) bool {
if len(ignore.Params) == 0 {
return true
}
block := modules.GetBlockByIgnoreRange(ignore.Range)
if block == nil {
return true
}
for key, val := range ignore.Params {
attr := block.GetAttribute(key)
if attr.IsNil() || !attr.Value().IsKnown() {
return false
}
switch attr.Type() {
case cty.String:
if !attr.Equals(val) {
return false
}
case cty.Number:
bf := attr.Value().AsBigFloat()
f64, _ := bf.Float64()
comparableInt := fmt.Sprintf("%d", int(f64))
comparableFloat := fmt.Sprintf("%f", f64)
if val != comparableInt && val != comparableFloat {
return false
}
case cty.Bool:
if fmt.Sprintf("%t", attr.IsTrue()) != val {
return false
}
default:
return false
}
}
return true
}
17 changes: 16 additions & 1 deletion internal/pkg/block/modules.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package block

import "fmt"
import (
"fmt"

"github.com/aquasecurity/defsec/types"
)

type Modules []*Module

Expand Down Expand Up @@ -80,3 +84,14 @@ func (m Modules) GetResourceByIDs(id ...string) Blocks {

return blocks
}

func (m Modules) GetBlockByIgnoreRange(r types.Range) *Block {
for _, module := range m {
for _, block := range module.GetBlocks() {
if br := block.GetMetadata().Range(); br != nil && br.GetFilename() == r.GetFilename() && br.GetStartLine() == r.GetStartLine()+1 {
return block
}
}
}
return nil
}
2 changes: 1 addition & 1 deletion internal/pkg/parser/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (e *Evaluator) evaluateModules() {

moduleIgnores := module.Modules[0].Ignores()
metadata := module.Definition.Metadata()
if ignore := e.ignores.Covering(metadata, e.workspace); ignore != nil {
if ignore := e.ignores.Covering(nil, metadata, e.workspace); ignore != nil {
moduleIgnore := *ignore
moduleIgnores = append(moduleIgnores, moduleIgnore)
}
Expand Down
20 changes: 19 additions & 1 deletion internal/pkg/parser/load_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func parseIgnoreFromComment(input string) (*block.Ignore, error) {
val := segments[i+1]
switch key {
case "ignore":
ignore.RuleID = val
ignore.RuleID, ignore.Params = parseIDWithParams(val)
case "exp":
parsed, err := time.Parse("2006-01-02", val)
if err != nil {
Expand All @@ -120,3 +120,21 @@ func parseIgnoreFromComment(input string) (*block.Ignore, error) {

return &ignore, nil
}

func parseIDWithParams(input string) (string, map[string]string) {
params := make(map[string]string)
if !strings.Contains(input, "[") {
return input, params
}
parts := strings.Split(input, "[")
id := parts[0]
paramStr := strings.TrimSuffix(parts[1], "]")
for _, pair := range strings.Split(paramStr, ",") {
parts := strings.Split(pair, "=")
if len(parts) != 2 {
continue
}
params[parts[0]] = parts[1]
}
return id, params
}
1 change: 1 addition & 0 deletions internal/pkg/scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func (scanner *Scanner) Scan(modules block.Modules) (rules.Results, error) {

for _, result := range results {
if !scanner.includeIgnored && ignores.Covering(
modules,
result.Metadata(),
scanner.workspaceName,
result.Rule().LongID(),
Expand Down
82 changes: 82 additions & 0 deletions test/ignore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,88 @@ resource "bad" "my-rule" {
assert.Len(t, results, 0)
}

func Test_IgnoreLineAboveTheBlockMatchingParamBool(t *testing.T) {
scanner.RegisterCheckRule(exampleRule)
defer scanner.DeregisterCheckRule(exampleRule)

results := testutil.ScanHCL(`
// tfsec:ignore:*[secure=false]
resource "bad" "my-rule" {
secure = false
}
`, t)
assert.Len(t, results, 0)
}

func Test_IgnoreLineAboveTheBlockNotMatchingParamBool(t *testing.T) {
scanner.RegisterCheckRule(exampleRule)
defer scanner.DeregisterCheckRule(exampleRule)

results := testutil.ScanHCL(`
// tfsec:ignore:*[secure=true]
resource "bad" "my-rule" {
secure = false
}
`, t)
assert.Len(t, results, 1)
}

func Test_IgnoreLineAboveTheBlockMatchingParamString(t *testing.T) {
scanner.RegisterCheckRule(exampleRule)
defer scanner.DeregisterCheckRule(exampleRule)

results := testutil.ScanHCL(`
// tfsec:ignore:*[name=myrule]
resource "bad" "my-rule" {
name = "myrule"
secure = false
}
`, t)
assert.Len(t, results, 0)
}

func Test_IgnoreLineAboveTheBlockNotMatchingParamString(t *testing.T) {
scanner.RegisterCheckRule(exampleRule)
defer scanner.DeregisterCheckRule(exampleRule)

results := testutil.ScanHCL(`
// tfsec:ignore:*[name=myrule2]
resource "bad" "my-rule" {
name = "myrule"
secure = false
}
`, t)
assert.Len(t, results, 1)
}

func Test_IgnoreLineAboveTheBlockMatchingParamInt(t *testing.T) {
scanner.RegisterCheckRule(exampleRule)
defer scanner.DeregisterCheckRule(exampleRule)

results := testutil.ScanHCL(`
// tfsec:ignore:*[port=123]
resource "bad" "my-rule" {
secure = false
port = 123
}
`, t)
assert.Len(t, results, 0)
}

func Test_IgnoreLineAboveTheBlockNotMatchingParamInt(t *testing.T) {
scanner.RegisterCheckRule(exampleRule)
defer scanner.DeregisterCheckRule(exampleRule)

results := testutil.ScanHCL(`
// tfsec:ignore:*[port=456]
resource "bad" "my-rule" {
secure = false
port = 123
}
`, t)
assert.Len(t, results, 1)
}

func Test_IgnoreLineStackedAboveTheBlock(t *testing.T) {
scanner.RegisterCheckRule(exampleRule)
defer scanner.DeregisterCheckRule(exampleRule)
Expand Down

0 comments on commit 7cd3fe5

Please sign in to comment.