Skip to content

Commit

Permalink
fix(cloudformation): evaluate the value for a property when comparing (
Browse files Browse the repository at this point in the history
…#1393)

fix(misconf): evaluate the value for a property when comparing
  • Loading branch information
nikpivkin authored Jul 19, 2023
1 parent 9af96f6 commit 4327cc6
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 35 deletions.
53 changes: 18 additions & 35 deletions pkg/scanners/cloudformation/parser/property_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,28 @@ func (p *Property) IsNotNil() bool {
return !p.IsUnresolved() && !p.IsNil()
}

func (p *Property) IsString() bool {
func (p *Property) Is(t cftypes.CfType) bool {
if p.IsNil() || p.IsUnresolved() {
return false
}
if p.isFunction() {
if prop, success := p.resolveValue(); success && prop != p {
return prop.IsString()
return prop.Is(t)
}
}
return p.Inner.Type == cftypes.String
return p.Inner.Type == t
}

func (p *Property) IsString() bool {
return p.Is(cftypes.String)
}

func (p *Property) IsNotString() bool {
return !p.IsUnresolved() && !p.IsString()
}

func (p *Property) IsInt() bool {
if p.IsNil() || p.IsUnresolved() {
return false
}
if p.isFunction() {
if prop, success := p.resolveValue(); success && prop != p {
return prop.IsInt()
}
}
return p.Inner.Type == cftypes.Int
return p.Is(cftypes.Int)
}

func (p *Property) IsNotInt() bool {
Expand All @@ -61,31 +57,15 @@ func (p *Property) IsNotMap() bool {
}

func (p *Property) IsList() bool {
if p.IsNil() || p.IsUnresolved() {
return false
}
if p.isFunction() {
if prop, success := p.resolveValue(); success && prop != p {
return prop.IsList()
}
}
return p.Inner.Type == cftypes.List
return p.Is(cftypes.List)
}

func (p *Property) IsNotList() bool {
return !p.IsUnresolved() && !p.IsList()
}

func (p *Property) IsBool() bool {
if p.IsNil() || p.IsUnresolved() {
return false
}
if p.isFunction() {
if prop, success := p.resolveValue(); success && prop != p {
return prop.IsBool()
}
}
return p.Inner.Type == cftypes.Bool
return p.Is(cftypes.Bool)
}

func (p *Property) IsUnresolved() bool {
Expand Down Expand Up @@ -200,22 +180,25 @@ func (p *Property) EqualTo(checkValue interface{}, equalityOptions ...EqualityOp
return false
}

switch p.Inner.Type {
case cftypes.String:
if p.Inner.Type == cftypes.String || p.IsString() {
if ignoreCase {
return strings.EqualFold(p.AsString(), checkerVal)
}
return p.AsString() == checkerVal
case cftypes.Int:
} else if p.Inner.Type == cftypes.Int || p.IsInt() {
if val, err := strconv.Atoi(checkerVal); err == nil {
return p.AsInt() == val
}
}
return false
case bool:
return p.Inner.Value == checkerVal
if p.Inner.Type == cftypes.Bool || p.IsBool() {
return p.AsBool() == checkerVal
}
case int:
return p.Inner.Value == checkerVal
if p.Inner.Type == cftypes.Int || p.IsInt() {
return p.AsInt() == checkerVal
}
}

return false
Expand Down
195 changes: 195 additions & 0 deletions pkg/scanners/cloudformation/parser/property_helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package parser

import (
"testing"

"github.com/aquasecurity/defsec/pkg/scanners/cloudformation/cftypes"
"github.com/aquasecurity/defsec/pkg/types"
"github.com/stretchr/testify/assert"
)

func newProp(inner PropertyInner) *Property {
return &Property{
name: "test_prop",
ctx: &FileContext{},
rng: types.NewRange("testfile", 1, 1, "", nil),
Inner: inner,
}
}

func Test_EqualTo(t *testing.T) {
tests := []struct {
name string
property *Property
checkValue interface{}
opts []EqualityOptions
isEqual bool
}{
{
name: "prop is nil",
property: nil,
checkValue: "some value",
isEqual: false,
},
{
name: "compare strings",
property: newProp(PropertyInner{
Type: cftypes.String,
Value: "is str",
}),
checkValue: "is str",
isEqual: true,
},
{
name: "compare strings ignoring case",
property: newProp(PropertyInner{
Type: cftypes.String,
Value: "is str",
}),
opts: []EqualityOptions{IgnoreCase},
checkValue: "Is StR",
isEqual: true,
},
{
name: "strings ate not equal",
property: newProp(PropertyInner{
Type: cftypes.String,
Value: "some value",
}),
checkValue: "some other value",
isEqual: false,
},
{
name: "compare prop with a int represented by a string",
property: newProp(PropertyInner{
Type: cftypes.Int,
Value: 147,
}),
checkValue: "147",
isEqual: true,
},
{
name: "compare ints",
property: newProp(PropertyInner{
Type: cftypes.Int,
Value: 701,
}),
checkValue: 701,
isEqual: true,
},
{
name: "compare bools",
property: newProp(PropertyInner{
Type: cftypes.Bool,
Value: true,
}),
checkValue: true,
isEqual: true,
},
{
name: "prop is string fn",
property: newProp(PropertyInner{
Type: cftypes.Map,
Value: map[string]*Property{
"Fn::If": {
Inner: PropertyInner{
Type: cftypes.List,
Value: []*Property{
{
Inner: PropertyInner{
Type: cftypes.Bool,
Value: false,
},
},
{
Inner: PropertyInner{
Type: cftypes.String,
Value: "bad",
},
},
{
Inner: PropertyInner{
Type: cftypes.String,
Value: "some value",
},
},
},
},
},
},
}),
checkValue: "some value",
isEqual: true,
},
{
name: "prop is int fn",
property: newProp(PropertyInner{
Type: cftypes.Map,
Value: map[string]*Property{
"Fn::If": {
Inner: PropertyInner{
Type: cftypes.List,
Value: []*Property{
{
Inner: PropertyInner{
Type: cftypes.Bool,
Value: true,
},
},
{
Inner: PropertyInner{
Type: cftypes.Int,
Value: 121,
},
},
{
Inner: PropertyInner{
Type: cftypes.Int,
Value: -1,
},
},
},
},
},
},
}),
checkValue: 121,
isEqual: true,
},
{
name: "prop is bool fn",
property: newProp(PropertyInner{
Type: cftypes.Map,
Value: map[string]*Property{
"Fn::Equals": {
Inner: PropertyInner{
Type: cftypes.List,
Value: []*Property{
{
Inner: PropertyInner{
Type: cftypes.String,
Value: "foo",
},
},
{
Inner: PropertyInner{
Type: cftypes.String,
Value: "foo",
},
},
},
},
},
},
}),
checkValue: true,
isEqual: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.isEqual, tt.property.EqualTo(tt.checkValue, tt.opts...))
})
}
}

0 comments on commit 4327cc6

Please sign in to comment.