Skip to content

Commit 8e6e188

Browse files
committed
chore: initial preview commit, code will fail
Code will fail until trivy fork changes are merged upstream. Need to push fork changes to github
1 parent ea413c4 commit 8e6e188

File tree

7 files changed

+327
-3
lines changed

7 files changed

+327
-3
lines changed

go.mod

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,16 @@ require (
88
)
99

1010
require (
11+
github.com/agext/levenshtein v1.2.3 // indirect
1112
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
12-
github.com/davecgh/go-spew v1.1.1 // indirect
13-
github.com/pmezard/go-difflib v1.0.0 // indirect
14-
golang.org/x/text v0.11.0 // indirect
13+
github.com/aquasecurity/trivy v0.58.2 // indirect
14+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
15+
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
16+
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
17+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
18+
golang.org/x/mod v0.22.0 // indirect
19+
golang.org/x/sys v0.28.0 // indirect
20+
golang.org/x/text v0.21.0 // indirect
21+
golang.org/x/tools v0.26.0 // indirect
1522
gopkg.in/yaml.v3 v3.0.1 // indirect
1623
)

go.sum

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
1+
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
2+
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
3+
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
14
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
25
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
6+
github.com/aquasecurity/trivy v0.58.2 h1:ZzJ9wOvXVXIJjkfYNE2CZeG3XyWz4yf9UCejgcp8WVU=
7+
github.com/aquasecurity/trivy v0.58.2/go.mod h1:MFlUXVTUBPaiKtQMCyaAYR6KBERWSzl+T3eMdQhH92g=
38
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
49
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
511
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
612
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
13+
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
14+
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
15+
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
16+
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
17+
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
718
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
819
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
20+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
921
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
1022
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
1123
github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70=
1224
github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
25+
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
26+
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
27+
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
28+
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
29+
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
30+
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1331
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
1432
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
33+
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
34+
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
35+
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
36+
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
1537
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
1638
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1739
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

hclext/references.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package hclext
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/hashicorp/hcl/v2"
8+
)
9+
10+
func ReferenceNames(exp hcl.Expression) []string {
11+
allVars := exp.Variables()
12+
vars := make([]string, 0, len(allVars))
13+
14+
for _, v := range allVars {
15+
vars = append(vars, CreateDotReferenceFromTraversal(v))
16+
}
17+
18+
return vars
19+
}
20+
21+
func CreateDotReferenceFromTraversal(traversals ...hcl.Traversal) string {
22+
var refParts []string
23+
24+
for _, x := range traversals {
25+
for _, p := range x {
26+
switch part := p.(type) {
27+
case hcl.TraverseRoot:
28+
refParts = append(refParts, part.Name)
29+
case hcl.TraverseAttr:
30+
refParts = append(refParts, part.Name)
31+
case hcl.TraverseIndex:
32+
refParts = append(refParts, fmt.Sprintf("[%s]", part.Key.AsString()))
33+
}
34+
}
35+
}
36+
return strings.Join(refParts, ".")
37+
}

hclext/vartypes.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package hclext
2+
3+
import (
4+
"github.com/hashicorp/hcl/v2"
5+
"github.com/hashicorp/hcl/v2/ext/typeexpr"
6+
"github.com/hashicorp/hcl/v2/hclsyntax"
7+
"github.com/zclconf/go-cty/cty"
8+
)
9+
10+
func DecodeVarType(exp hcl.Expression) (cty.Type, *typeexpr.Defaults, error) {
11+
// This block converts the string literals "string" -> string
12+
// Coder used to allow literal strings, instead of types as keywords. So
13+
// we have to handle these cases for backwards compatibility.
14+
if tpl, ok := exp.(*hclsyntax.TemplateExpr); ok && len(tpl.Parts) == 1 {
15+
if lit, ok := tpl.Parts[0].(*hclsyntax.LiteralValueExpr); ok && lit.Val.Type() == cty.String {
16+
keyword := lit.Val.AsString()
17+
18+
exp = &hclsyntax.ScopeTraversalExpr{
19+
Traversal: []hcl.Traverser{
20+
hcl.TraverseRoot{
21+
Name: keyword,
22+
SrcRange: exp.Range(),
23+
},
24+
},
25+
SrcRange: exp.Range(),
26+
}
27+
}
28+
}
29+
30+
// Special-case the shortcuts for list(any) and map(any) which aren't hcl.
31+
switch hcl.ExprAsKeyword(exp) {
32+
case "list":
33+
return cty.List(cty.DynamicPseudoType), nil, nil
34+
case "map":
35+
return cty.Map(cty.DynamicPseudoType), nil, nil
36+
}
37+
38+
t, def, diag := typeexpr.TypeConstraintWithDefaults(exp)
39+
if diag.HasErrors() {
40+
return cty.NilType, nil, diag
41+
}
42+
return t, def, nil
43+
}

hook.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package preview
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/aquasecurity/trivy/pkg/iac/terraform"
7+
tfcontext "github.com/aquasecurity/trivy/pkg/iac/terraform/context"
8+
"github.com/hashicorp/hcl/v2"
9+
"github.com/hashicorp/hcl/v2/ext/typeexpr"
10+
"github.com/zclconf/go-cty/cty"
11+
"github.com/zclconf/go-cty/cty/convert"
12+
13+
"github.com/coder/preview/hclext"
14+
)
15+
16+
func ParameterContextsEvalHook(input Input, diags hcl.Diagnostics) func(ctx *tfcontext.Context, blocks terraform.Blocks, inputVars map[string]cty.Value) {
17+
return func(ctx *tfcontext.Context, blocks terraform.Blocks, inputVars map[string]cty.Value) {
18+
data := blocks.OfType("data")
19+
for _, block := range data {
20+
if block.TypeLabel() != "coder_parameter" {
21+
continue
22+
}
23+
24+
if !block.GetAttribute("value").IsNil() {
25+
continue // Wow a value exists?!. This feels like a bug.
26+
}
27+
28+
name := block.NameLabel()
29+
var defDiags hcl.Diagnostics
30+
var value cty.Value
31+
pv, ok := input.RichParameterValue(name)
32+
if ok {
33+
// TODO: Handle non-string types
34+
value = cty.StringVal(pv.Value)
35+
} else {
36+
// get the default value
37+
value, defDiags = evaluateCoderParameterDefault(block)
38+
diags = diags.Extend(defDiags)
39+
}
40+
41+
// Set the default value as the 'value' attribute
42+
path := []string{"data"}
43+
path = append(path, block.Labels()...)
44+
path = append(path, "value")
45+
// The current context is in the `coder_parameter` block.
46+
// Use the parent context to "export" the value
47+
ctx.Set(value, path...)
48+
//block.Context().Parent().Set(value, path...)
49+
}
50+
}
51+
}
52+
53+
func evaluateCoderParameterDefault(b *terraform.Block) (cty.Value, hcl.Diagnostics) {
54+
//if b.Label() == "" {
55+
// return cty.NilVal, errors.New("empty label - cannot resolve")
56+
//}
57+
58+
attributes := b.Attributes()
59+
if attributes == nil {
60+
r := b.HCLBlock().Body.MissingItemRange()
61+
return cty.NilVal, hcl.Diagnostics{
62+
{
63+
Severity: hcl.DiagWarning,
64+
Summary: "'coder_parameter' block has no attributes",
65+
Detail: "No default value will be set for this paramete",
66+
Subject: &r,
67+
},
68+
}
69+
}
70+
71+
var valType cty.Type
72+
var defaults *typeexpr.Defaults
73+
// TODO: `"string"` fails, it should be `string`
74+
typeAttr, exists := attributes["type"]
75+
if exists {
76+
ty, def, err := hclext.DecodeVarType(typeAttr.HCLAttribute().Expr)
77+
if err != nil {
78+
return cty.NilVal, hcl.Diagnostics{
79+
{
80+
Severity: hcl.DiagWarning,
81+
Summary: fmt.Sprintf("Decoding parameter type for %q", b.FullName()),
82+
Detail: err.Error(),
83+
Subject: &typeAttr.HCLAttribute().Range,
84+
Context: &b.HCLBlock().DefRange,
85+
Expression: typeAttr.HCLAttribute().Expr,
86+
EvalContext: b.Context().Inner(),
87+
},
88+
}
89+
}
90+
valType = ty
91+
defaults = def
92+
} else {
93+
// Default to string type
94+
valType = cty.String
95+
}
96+
97+
var val cty.Value
98+
99+
def, exists := attributes["default"]
100+
if exists {
101+
val = def.NullableValue()
102+
} else {
103+
return cty.NilVal, nil
104+
}
105+
106+
if valType != cty.NilType {
107+
if defaults != nil {
108+
val = defaults.Apply(val)
109+
}
110+
111+
typedVal, err := convert.Convert(val, valType)
112+
if err != nil {
113+
return cty.NilVal, hcl.Diagnostics{
114+
{
115+
Severity: hcl.DiagWarning,
116+
Summary: "Converting default parameter value type",
117+
Detail: err.Error(),
118+
Subject: &def.HCLAttribute().Range,
119+
Context: &b.HCLBlock().DefRange,
120+
Expression: def.HCLAttribute().Expr,
121+
EvalContext: b.Context().Inner(),
122+
},
123+
}
124+
}
125+
return typedVal, nil
126+
}
127+
128+
return val, nil
129+
130+
}

preview.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package preview
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io/fs"
7+
"path/filepath"
8+
9+
"github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser"
10+
"github.com/coder/preview/types"
11+
"github.com/hashicorp/hcl/v2"
12+
)
13+
14+
type Input struct {
15+
ParameterValues []types.ParameterValue
16+
}
17+
18+
type Output struct {
19+
Parameters []types.RichParameter
20+
}
21+
22+
func Preview(ctx context.Context, input Input, dir fs.FS) (*Output, hcl.Diagnostics) {
23+
varFiles, err := tfVarFiles("", dir)
24+
if err != nil {
25+
return nil, nil
26+
}
27+
28+
diags := make(hcl.Diagnostics, 0)
29+
hook := ParameterContextsEvalHook(input, diags)
30+
// moduleSource is "" for a local module
31+
p := parser.New(dir, "",
32+
parser.OptionWithDownloads(false),
33+
parser.OptionWithTFVarsPaths(varFiles...),
34+
parser.OptionWithEvalHook(hook),
35+
)
36+
37+
var _ = p
38+
39+
return nil, nil
40+
}
41+
42+
func (i Input) RichParameterValue(key string) (types.ParameterValue, bool) {
43+
for _, p := range i.ParameterValues {
44+
if p.Name == key {
45+
return p, true
46+
}
47+
}
48+
return types.ParameterValue{}, false
49+
}
50+
51+
// tfVarFiles extracts any .tfvars files from the given directory.
52+
// TODO: Test nested directories and how that should behave.
53+
func tfVarFiles(path string, dir fs.FS) ([]string, error) {
54+
dp := "."
55+
entries, err := fs.ReadDir(dir, dp)
56+
if err != nil {
57+
return nil, fmt.Errorf("read dir %q: %w", dp, err)
58+
}
59+
60+
files := make([]string, 0)
61+
for _, entry := range entries {
62+
if entry.IsDir() {
63+
subD, err := fs.Sub(dir, entry.Name())
64+
if err != nil {
65+
return nil, fmt.Errorf("sub dir %q: %w", entry.Name(), err)
66+
}
67+
newFiles, err := tfVarFiles(filepath.Join(path, entry.Name()), subD)
68+
if err != nil {
69+
return nil, err
70+
}
71+
files = append(files, newFiles...)
72+
}
73+
74+
if filepath.Ext(entry.Name()) == ".tfvars" {
75+
files = append(files, filepath.Join(path, entry.Name()))
76+
}
77+
}
78+
return files, nil
79+
}

types/parameter.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import (
88
"github.com/zclconf/go-cty/cty"
99
)
1010

11+
type ParameterValue struct {
12+
Name string `json:"name"`
13+
// TODO: Should this be a cty.Value?
14+
Value string `json:"value"`
15+
}
16+
1117
type RichParameter struct {
1218
Name string `json:"name"`
1319
Description string `json:"description"`

0 commit comments

Comments
 (0)