Skip to content

Commit

Permalink
Merge pull request #314 from cloudskiff/issue_232_lotoussa
Browse files Browse the repository at this point in the history
DriftIgnore implement new wildcard match checker
  • Loading branch information
wbeuil authored Mar 18, 2021
2 parents aa7b6e7 + 3da401a commit f34d544
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 9 deletions.
54 changes: 45 additions & 9 deletions pkg/filter/driftignore.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import (
)

type DriftIgnore struct {
resExclusionList map[string]struct{} // map[type.id] exists to ignore
driftExclusionList map[string][]string // map[type.id] contains path for drift to ignore
resExclusionList map[string]struct{} // map[type.id] exists to ignore
resExclusionWildcardList map[string]struct{} // map[type.id] exists with wildcard to ignore
driftExclusionList map[string][]string // map[type.id] contains path for drift to ignore
}

func NewDriftIgnore() *DriftIgnore {
d := DriftIgnore{
resExclusionList: map[string]struct{}{},
driftExclusionList: map[string][]string{},
resExclusionList: map[string]struct{}{},
resExclusionWildcardList: map[string]struct{}{},
driftExclusionList: map[string][]string{},
}
err := d.readIgnoreFile()
if err != nil {
Expand Down Expand Up @@ -53,16 +55,20 @@ func (r *DriftIgnore) readIgnoreFile() error {
}).Warnf("unable to parse line, invalid length, got %d expected >= 2", nbArgs)
continue
}
res := strings.Join(typeVal[0:2], ".")
if nbArgs == 2 { // We want to ignore a resource (type.id)
logrus.WithFields(logrus.Fields{
"type": typeVal[0],
"id": typeVal[1],
}).Debug("Found ignore resource rule in .driftignore")
r.resExclusionList[strings.Join(typeVal, ".")] = struct{}{}
resExclusionTypeList := r.resExclusionList
if strings.Contains(res, "*") {
resExclusionTypeList = r.resExclusionWildcardList
}
resExclusionTypeList[res] = struct{}{}
continue
}
// Here we want to ignore a drift (type.id.path.to.field)
res := strings.Join(typeVal[0:2], ".")
ignoreSublist, exists := r.driftExclusionList[res]
if !exists {
ignoreSublist = make([]string, 0, 1)
Expand All @@ -87,9 +93,17 @@ func (r *DriftIgnore) readIgnoreFile() error {
}

func (r *DriftIgnore) IsResourceIgnored(res resource.Resource) bool {
_, isExclusionRule := r.resExclusionList[fmt.Sprintf("%s.%s", res.TerraformType(), res.TerraformId())]
_, isExclusionWildcardRule := r.resExclusionList[fmt.Sprintf("%s.*", res.TerraformType())]
return isExclusionRule || isExclusionWildcardRule
strRes := fmt.Sprintf("%s.%s", res.TerraformType(), res.TerraformId())

if _, isExclusionRule := r.resExclusionList[strRes]; isExclusionRule {
return true
}
for resExclusion := range r.resExclusionWildcardList {
if wildcardMatchChecker(strRes, resExclusion) {
return true
}
}
return false
}

func (r *DriftIgnore) IsFieldIgnored(res resource.Resource, path []string) bool {
Expand Down Expand Up @@ -129,11 +143,33 @@ RuleCheck:
return false
}

//Check two strings recursively, pattern can contain wildcard
func wildcardMatchChecker(str, pattern string) bool {
if str == "" && pattern == "" {
return true
}
if strings.HasPrefix(pattern, "*") {
if str != "" {
return wildcardMatchChecker(str[1:], pattern) || wildcardMatchChecker(str, pattern[1:])
}
return wildcardMatchChecker(str, pattern[1:])
}
if str != "" && pattern != "" && str[0] == pattern[0] {
return wildcardMatchChecker(str[1:], pattern[1:])
}
return false
}

/**
* Read a line of ignore
* Handle multiple asterisks escaping
* Handle split on dots and escaping
*/
func readDriftIgnoreLine(line string) []string {
for strings.Contains(line, "**") {
line = strings.ReplaceAll(line, "**", "*")
}

var splitted []string
lastWordEnd := 0
for i := range line {
Expand Down
67 changes: 67 additions & 0 deletions pkg/filter/driftignore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,48 @@ func TestDriftIgnore_IsResourceIgnored(t *testing.T) {
true,
},
},
{
name: "drift_ignore_wildcard",
resources: []resource.Resource{
&resource2.FakeResource{
Type: "type1",
Id: "id1",
},
&resource2.FakeResource{
Type: "type2",
Id: "id1",
},
&resource2.FakeResource{
Type: "type2",
Id: "id11",
},
&resource2.FakeResource{
Type: "type2",
Id: "id2",
},
&resource2.FakeResource{
Type: "type3",
Id: "id100",
},
&resource2.FakeResource{
Type: "type3",
Id: "id101",
},
&resource2.FakeResource{
Type: "type4",
Id: "id\\WithBac*slash***\\*\\",
},
},
want: []bool{
false,
true,
true,
false,
true,
false,
true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -280,6 +322,31 @@ func Test_escapableSplit(t *testing.T) {
line: "*.subfoobar",
want: []string{"*", "subfoobar"},
},
{
name: "text wildcard dot",
line: "res*.subfoobar",
want: []string{"res*", "subfoobar"},
},
{
name: "missing text multiple wildcard dot",
line: "r*s*.s**ub***ob********a*r",
want: []string{"r*s*", "s*ub*ob*a*r"},
},
{
name: "prefix wildcard dot",
line: "*res.subfoobar",
want: []string{"*res", "subfoobar"},
},
{
name: "suffix multiple wildcard dot",
line: "res.subfoobar*****",
want: []string{"res", "subfoobar*"},
},
{
name: "dot wildcard",
line: "res.*",
want: []string{"res", "*"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions pkg/filter/testdata/drift_ignore_wildcard/.driftignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*2**.**d1*
type3.id1***0
*.id\\WithBa*slas*\\**\\

# this is *** comment

0 comments on commit f34d544

Please sign in to comment.