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  }