mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
140 lines
3.1 KiB
Go
140 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
hversion "github.com/hashicorp/go-version" //nolint:gomodguard // hc-install uses hashicorp/go-version
|
|
"github.com/hashicorp/hc-install/product"
|
|
"github.com/hashicorp/hc-install/releases"
|
|
"github.com/hashicorp/terraform-exec/tfexec"
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
"github.com/aquasecurity/trivy/internal/testutil"
|
|
)
|
|
|
|
const (
|
|
terraformVersion = "1.7.3"
|
|
terraformParallelLimit = 5
|
|
|
|
tfplanFile = "tfplan"
|
|
)
|
|
|
|
func fixtureTerraformPlanSnapshots(ctx context.Context) error {
|
|
localstackC, addr, err := testutil.SetupLocalStack(ctx, "3.1.0")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer localstackC.Terminate(ctx)
|
|
|
|
envs := []struct {
|
|
key string
|
|
val string
|
|
}{
|
|
{"AWS_DEFAULT_REGION", "us-east-1"},
|
|
{"AWS_ACCESS_KEY_ID", "test"},
|
|
{"AWS_SECRET_ACCESS_KEY", "test"},
|
|
{"AWS_ENDPOINT_URL", addr},
|
|
}
|
|
|
|
for _, env := range envs {
|
|
if err := os.Setenv(env.key, env.val); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
dirs := []string{
|
|
"pkg/fanal/artifact/local/testdata/misconfig/terraformplan/snapshots",
|
|
"pkg/iac/scanners/terraformplan/snapshot/testdata",
|
|
}
|
|
|
|
var workingDirs []string
|
|
|
|
for _, dir := range dirs {
|
|
entries, err := os.ReadDir(filepath.FromSlash(dir))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
workingDirs = append(workingDirs, filepath.Join(dir, entry.Name()))
|
|
}
|
|
}
|
|
|
|
installer := &releases.ExactVersion{
|
|
Product: product.Terraform,
|
|
Version: hversion.Must(hversion.NewVersion(terraformVersion)),
|
|
}
|
|
|
|
execPath, err := installer.Install(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to install Terraform: %w", err)
|
|
}
|
|
|
|
g, ctx := errgroup.WithContext(ctx)
|
|
g.SetLimit(terraformParallelLimit)
|
|
|
|
for _, workingDir := range workingDirs {
|
|
g.Go(func() error {
|
|
if err := os.Remove(tfplanFile); err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
return err
|
|
}
|
|
|
|
if err := generatePlan(ctx, execPath, workingDir); err != nil {
|
|
return fmt.Errorf("failed to generate Terraform Plan: %w", err)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
return g.Wait()
|
|
}
|
|
|
|
func generatePlan(ctx context.Context, execPath, workingDir string) error {
|
|
if err := cleanup(workingDir); err != nil {
|
|
return err
|
|
}
|
|
defer cleanup(workingDir)
|
|
|
|
tf, err := tfexec.NewTerraform(workingDir, execPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run Terraform: %w", err)
|
|
}
|
|
|
|
prefix := fmt.Sprintf("tfplan:%s:", filepath.Base(workingDir))
|
|
tf.SetLogger(log.New(os.Stdout, prefix, log.LstdFlags))
|
|
|
|
if err = tf.Init(ctx, tfexec.Upgrade(true)); err != nil {
|
|
return fmt.Errorf("failed to run Init cmd: %w", err)
|
|
}
|
|
|
|
if _, err := tf.Plan(ctx, tfexec.Out(tfplanFile)); err != nil {
|
|
return fmt.Errorf("failed to run Plan cmd: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func cleanup(workingDir string) error {
|
|
entries, err := os.ReadDir(workingDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
if entry.Name() == "terraform.tfstate" || strings.HasPrefix(entry.Name(), ".terraform") {
|
|
path := filepath.Join(workingDir, entry.Name())
|
|
if err := os.RemoveAll(path); err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|