mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 07:10:41 -08:00
83 lines
1.9 KiB
Go
83 lines
1.9 KiB
Go
package parser
|
|
|
|
import (
|
|
"context"
|
|
"path"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/samber/lo"
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/aquasecurity/trivy/pkg/iac/terraform"
|
|
)
|
|
|
|
// FindRootModules takes a list of module paths and identifies the root local modules.
|
|
// It builds a graph based on the module dependencies and determines the modules that have no incoming dependencies,
|
|
// considering them as root modules.
|
|
func (p *Parser) FindRootModules(ctx context.Context, dirs []string) ([]string, error) {
|
|
// skip cached terraform modules as they cannot be root modules
|
|
dirs = lo.Filter(dirs, func(dir string, _ int) bool {
|
|
return !strings.Contains(dir, ".terraform/modules/")
|
|
})
|
|
for _, dir := range dirs {
|
|
if err := p.ParseFS(ctx, dir); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
blocks, _, err := p.readBlocks(p.files)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
g := buildGraph(blocks, dirs)
|
|
rootModules := g.rootModules()
|
|
sort.Strings(rootModules)
|
|
return rootModules, nil
|
|
}
|
|
|
|
type modulesGraph map[string][]string
|
|
|
|
func buildGraph(blocks terraform.Blocks, paths []string) modulesGraph {
|
|
moduleBlocks := blocks.OfType("module")
|
|
|
|
graph := lo.SliceToMap(paths, func(p string) (string, []string) {
|
|
return p, nil
|
|
})
|
|
|
|
for _, block := range moduleBlocks {
|
|
sourceVal := block.GetAttribute("source").Value()
|
|
if sourceVal.Type() != cty.String {
|
|
continue
|
|
}
|
|
|
|
source := sourceVal.AsString()
|
|
if strings.HasPrefix(source, ".") {
|
|
filename := block.GetMetadata().Range().GetFilename()
|
|
dir := path.Dir(filename)
|
|
graph[dir] = append(graph[dir], path.Join(dir, source))
|
|
}
|
|
}
|
|
|
|
return graph
|
|
}
|
|
|
|
func (g modulesGraph) rootModules() []string {
|
|
incomingEdges := make(map[string]int)
|
|
for _, neighbors := range g {
|
|
for _, neighbor := range neighbors {
|
|
incomingEdges[neighbor]++
|
|
}
|
|
}
|
|
|
|
var roots []string
|
|
for module := range g {
|
|
if incomingEdges[module] == 0 {
|
|
roots = append(roots, module)
|
|
}
|
|
}
|
|
|
|
return roots
|
|
}
|