Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aa4c103

Browse files
committed
feat: template variables added to input
Input can override template vars, implementing the equivalent of '-var' in terraform.
1 parent ab350ac commit aa4c103

File tree

6 files changed

+204
-3
lines changed

6 files changed

+204
-3
lines changed

preview.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import (
88
"log/slog"
99
"os"
1010
"path/filepath"
11+
"strings"
1112

1213
"github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser"
1314
"github.com/aquasecurity/trivy/pkg/log"
1415
"github.com/hashicorp/hcl/v2"
1516
"github.com/zclconf/go-cty/cty"
1617

18+
"github.com/coder/preview/tfvars"
1719
"github.com/coder/preview/types"
1820
)
1921

@@ -25,6 +27,7 @@ type Input struct {
2527
PlanJSON json.RawMessage
2628
ParameterValues map[string]string
2729
Owner types.WorkspaceOwner
30+
TFVars map[string]cty.Value
2831
}
2932

3033
type Output struct {
@@ -50,6 +53,17 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (*Output, hcl.Diagnost
5053
}
5154
}
5255

56+
variableValues, err := tfvars.LoadTFVars(dir, varFiles)
57+
if err != nil {
58+
return nil, hcl.Diagnostics{
59+
{
60+
Severity: hcl.DiagError,
61+
Summary: "Failed to load tfvars from files",
62+
Detail: err.Error(),
63+
},
64+
}
65+
}
66+
5367
planHook, err := PlanJSONHook(dir, input)
5468
if err != nil {
5569
return nil, hcl.Diagnostics{
@@ -71,17 +85,23 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (*Output, hcl.Diagnost
7185
},
7286
}
7387
}
74-
var _ = ownerHook
88+
89+
// Override with user supplied variables
90+
for k, v := range input.TFVars {
91+
variableValues[k] = v
92+
}
7593

7694
// moduleSource is "" for a local module
7795
p := parser.New(dir, "",
7896
parser.OptionStopOnHCLError(false),
7997
parser.OptionWithDownloads(false),
8098
parser.OptionWithSkipCachedModules(true),
81-
parser.OptionWithTFVarsPaths(varFiles...),
8299
parser.OptionWithEvalHook(planHook),
83100
parser.OptionWithEvalHook(ownerHook),
84101
parser.OptionWithEvalHook(ParameterContextsEvalHook(input)),
102+
// 'OptionsWithTfVars' cannot be set with 'OptionWithTFVarsPaths'. So load the
103+
// tfvars from the files ourselves and merge with the user-supplied tf vars.
104+
parser.OptionsWithTfVars(variableValues),
85105
)
86106

87107
err = p.ParseFS(ctx, ".")
@@ -149,7 +169,7 @@ func tfVarFiles(path string, dir fs.FS) ([]string, error) {
149169
files = append(files, newFiles...)
150170
}
151171

152-
if filepath.Ext(entry.Name()) == ".tfvars" {
172+
if filepath.Ext(entry.Name()) == ".tfvars" || strings.HasSuffix(entry.Name(), ".tfvars.json") {
153173
files = append(files, filepath.Join(path, entry.Name()))
154174
}
155175
}

preview_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/stretchr/testify/assert"
1111
"github.com/stretchr/testify/require"
12+
"github.com/zclconf/go-cty/cty"
1213

1314
"github.com/coder/preview"
1415
"github.com/coder/preview/types"
@@ -392,6 +393,37 @@ func Test_Extract(t *testing.T) {
392393
"beta": ap().unknown(),
393394
},
394395
},
396+
{
397+
name: "tfvars_from_file",
398+
dir: "tfvars",
399+
expTags: map[string]string{},
400+
input: preview.Input{
401+
ParameterValues: map[string]string{},
402+
},
403+
unknownTags: []string{},
404+
params: map[string]assertParam{
405+
"variable_values": ap().
406+
def("alex").optVals("alex", "bob", "claire", "jason"),
407+
},
408+
},
409+
{
410+
name: "tfvars_from_input",
411+
dir: "tfvars",
412+
expTags: map[string]string{},
413+
input: preview.Input{
414+
ParameterValues: map[string]string{},
415+
TFVars: map[string]cty.Value{
416+
"one": cty.StringVal("andrew"),
417+
"two": cty.StringVal("bill"),
418+
"three": cty.StringVal("carter"),
419+
},
420+
},
421+
unknownTags: []string{},
422+
params: map[string]assertParam{
423+
"variable_values": ap().
424+
def("andrew").optVals("andrew", "bill", "carter", "jason"),
425+
},
426+
},
395427
{
396428
skip: "skip until https://github.com/aquasecurity/trivy/pull/8479 is resolved",
397429
name: "submodcount",

testdata/tfvars/.auto.tfvars.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"four":"jason"}

testdata/tfvars/main.tf

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Base case for workspace tags + parameters.
2+
terraform {
3+
required_providers {
4+
coder = {
5+
source = "coder/coder"
6+
}
7+
docker = {
8+
source = "kreuzwerker/docker"
9+
version = "3.0.2"
10+
}
11+
}
12+
}
13+
14+
variable "one" {
15+
default = "alice"
16+
type = string
17+
}
18+
19+
variable "two" {
20+
default = "bob"
21+
type = string
22+
}
23+
24+
variable "three" {
25+
default = "charlie"
26+
type = string
27+
}
28+
29+
variable "four" {
30+
default = "jack"
31+
type = string
32+
}
33+
34+
35+
data "coder_parameter" "variable_values" {
36+
name = "variable_values"
37+
description = "Just to show the variable values"
38+
type = "string"
39+
default = var.one
40+
41+
42+
option {
43+
name = "one"
44+
value = var.one
45+
}
46+
47+
option {
48+
name = "two"
49+
value = var.two
50+
}
51+
52+
option {
53+
name = "three"
54+
value = var.three
55+
}
56+
57+
option {
58+
name = "four"
59+
value = var.four
60+
}
61+
}

testdata/tfvars/values.tfvars

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
one="alex"
2+
three="claire"

tfvars/load.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Code taken from https://github.com/aquasecurity/trivy/blob/main/pkg/iac/scanners/terraform/parser/load_vars.go
2+
package tfvars
3+
4+
import (
5+
"fmt"
6+
"io/fs"
7+
"path/filepath"
8+
"strings"
9+
10+
"github.com/hashicorp/hcl/v2"
11+
"github.com/hashicorp/hcl/v2/hclsyntax"
12+
hcljson "github.com/hashicorp/hcl/v2/json"
13+
"github.com/zclconf/go-cty/cty"
14+
)
15+
16+
func LoadTFVars(srcFS fs.FS, filenames []string) (map[string]cty.Value, error) {
17+
combinedVars := make(map[string]cty.Value)
18+
19+
// Intentionally commented out to avoid loading from host environment
20+
//
21+
//for _, env := range os.Environ() {
22+
// split := strings.Split(env, "=")
23+
// key := split[0]
24+
// if !strings.HasPrefix(key, "TF_VAR_") {
25+
// continue
26+
// }
27+
// key = strings.TrimPrefix(key, "TF_VAR_")
28+
// var val string
29+
// if len(split) > 1 {
30+
// val = split[1]
31+
// }
32+
// combinedVars[key] = cty.StringVal(val)
33+
//}
34+
35+
for _, filename := range filenames {
36+
vars, err := LoadTFVarsFile(srcFS, filename)
37+
if err != nil {
38+
return nil, fmt.Errorf("failed to load tfvars from %s: %w", filename, err)
39+
}
40+
for k, v := range vars {
41+
combinedVars[k] = v
42+
}
43+
}
44+
45+
return combinedVars, nil
46+
}
47+
48+
func LoadTFVarsFile(srcFS fs.FS, filename string) (map[string]cty.Value, error) {
49+
inputVars := make(map[string]cty.Value)
50+
if filename == "" {
51+
return inputVars, nil
52+
}
53+
54+
src, err := fs.ReadFile(srcFS, filepath.ToSlash(filename))
55+
if err != nil {
56+
return nil, err
57+
}
58+
59+
var attrs hcl.Attributes
60+
if strings.HasSuffix(filename, ".json") {
61+
variableFile, err := hcljson.Parse(src, filename)
62+
if err != nil {
63+
return nil, err
64+
}
65+
attrs, err = variableFile.Body.JustAttributes()
66+
if err != nil {
67+
return nil, err
68+
}
69+
} else {
70+
variableFile, err := hclsyntax.ParseConfig(src, filename, hcl.Pos{Line: 1, Column: 1})
71+
if err != nil {
72+
return nil, err
73+
}
74+
attrs, err = variableFile.Body.JustAttributes()
75+
if err != nil {
76+
return nil, err
77+
}
78+
}
79+
80+
for _, attr := range attrs {
81+
inputVars[attr.Name], _ = attr.Expr.Value(&hcl.EvalContext{})
82+
}
83+
84+
return inputVars, nil
85+
}

0 commit comments

Comments
 (0)