github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/terraform/parser/sort.go (about) 1 package parser 2 3 import ( 4 "sort" 5 6 "github.com/khulnasoft-lab/defsec/pkg/terraform" 7 ) 8 9 func sortBlocksByHierarchy(blocks terraform.Blocks) { 10 c := &counter{ 11 cache: make(map[string]int), 12 } 13 sort.Slice(blocks, func(i, j int) bool { 14 a := blocks[i] 15 b := blocks[j] 16 iDepth, jDepth := c.countBlockRecursion(a, blocks, 0), c.countBlockRecursion(b, blocks, 0) 17 switch { 18 case iDepth < jDepth: 19 return true 20 case iDepth > jDepth: 21 return false 22 default: 23 return blocks[i].FullName() < blocks[j].FullName() 24 } 25 }) 26 } 27 28 type counter struct { 29 cache map[string]int 30 } 31 32 func (c *counter) countBlockRecursion(block *terraform.Block, blocks terraform.Blocks, count int) int { 33 metadata := block.GetMetadata() 34 if cached, ok := c.cache[metadata.Reference()]; ok { 35 return cached 36 } 37 var maxCount int 38 var hasRecursion bool 39 for _, attrName := range []string{"for_each", "count"} { 40 if attr := block.GetAttribute(attrName); attr.IsNotNil() { 41 hasRecursion = true 42 for _, other := range blocks { 43 if attr.ReferencesBlock(other) { 44 depth := c.countBlockRecursion(other, blocks, count) 45 if depth > maxCount { 46 maxCount = depth 47 } 48 } 49 } 50 } 51 } 52 if hasRecursion { 53 maxCount++ 54 } 55 result := maxCount + count 56 c.cache[metadata.Reference()] = result 57 return result 58 }