Skip to content

Commit b3c9e72

Browse files
authored
feat: ValidatePrebuilds to validate presets for prebuild use (#194)
Presets were being created with prebuild counts, even if the preset was unable to be used for a prebuild. This creates a function that can validate prebuilds.
1 parent f33a070 commit b3c9e72

File tree

8 files changed

+371
-62
lines changed

8 files changed

+371
-62
lines changed

extract/preset.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,34 @@
11
package extract
22

33
import (
4+
"fmt"
5+
46
"github.com/aquasecurity/trivy/pkg/iac/terraform"
5-
"github.com/coder/preview/types"
67
"github.com/hashicorp/hcl/v2"
8+
9+
"github.com/coder/preview/types"
710
)
811

9-
func PresetFromBlock(block *terraform.Block) types.Preset {
12+
func PresetFromBlock(block *terraform.Block) (tfPreset types.Preset) {
13+
defer func() {
14+
// Extra safety mechanism to ensure that if a panic occurs, we do not break
15+
// everything else.
16+
if r := recover(); r != nil {
17+
tfPreset = types.Preset{
18+
PresetData: types.PresetData{
19+
Name: block.Label(),
20+
},
21+
Diagnostics: types.Diagnostics{
22+
{
23+
Severity: hcl.DiagError,
24+
Summary: "Panic occurred in extracting preset. This should not happen, please report this to Coder.",
25+
Detail: fmt.Sprintf("panic in preset extract: %+v", r),
26+
},
27+
},
28+
}
29+
}
30+
}()
31+
1032
p := types.Preset{
1133
PresetData: types.PresetData{
1234
Parameters: make(map[string]string),
@@ -41,5 +63,13 @@ func PresetFromBlock(block *terraform.Block) types.Preset {
4163
p.Default = defaultAttr.Value().True()
4264
}
4365

66+
prebuildBlock := block.GetBlock("prebuilds")
67+
if prebuildBlock != nil {
68+
p.Prebuilds = &types.PrebuildData{
69+
// Invalid values will be set to 0
70+
Instances: int(optionalInteger(prebuildBlock, "instances")),
71+
}
72+
}
73+
4474
return p
4575
}

preview.go

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,61 @@ func (o Output) MarshalJSON() ([]byte, error) {
6868
})
6969
}
7070

71+
// ValidatePrebuilds will iterate over each preset, validate the inputs as a set,
72+
// and attach any diagnostics to the preset if there are issues. This must be done
73+
// because prebuilds have to be valid without user input.
74+
//
75+
// This will only validate presets that have prebuilds configured and have no
76+
// existing error diagnostics. This should only be used when doing Template
77+
// Imports as a protection against invalid presets.
78+
//
79+
// A preset doesn't need to specify all required parameters, as users can provide
80+
// the remaining values when creating a workspace. However, since prebuild
81+
// creation has no user input, presets used for prebuilds must provide all
82+
// required parameter values.
83+
func ValidatePrebuilds(ctx context.Context, input Input, preValid []types.Preset, dir fs.FS) {
84+
for i := range preValid {
85+
pre := &preValid[i]
86+
if pre.Prebuilds == nil || pre.Prebuilds.Instances <= 0 {
87+
// No prebuilds, so presets do not need to be valid without user input
88+
continue
89+
}
90+
91+
if hcl.Diagnostics(pre.Diagnostics).HasErrors() {
92+
// Piling on diagnostics is not helpful, if an error exists, leave it at that.
93+
continue
94+
}
95+
96+
// Diagnostics are added to the existing preset.
97+
input.ParameterValues = pre.Parameters
98+
output, diagnostics := Preview(ctx, input, dir)
99+
if diagnostics.HasErrors() {
100+
pre.Diagnostics = append(pre.Diagnostics, diagnostics...)
101+
// Do not pile on more diagnostics for individual params, it already failed
102+
continue
103+
}
104+
105+
if output == nil {
106+
continue
107+
}
108+
109+
// If any parameter is invalid, then the preset is invalid.
110+
// A value must be specified for this failing parameter.
111+
for _, param := range output.Parameters {
112+
if hcl.Diagnostics(param.Diagnostics).HasErrors() {
113+
for _, paramDiag := range param.Diagnostics {
114+
if paramDiag.Severity != hcl.DiagError {
115+
continue // Only care about errors here
116+
}
117+
orig := paramDiag.Summary
118+
paramDiag.Summary = fmt.Sprintf("Parameter %s: %s", param.Name, orig)
119+
pre.Diagnostics = append(pre.Diagnostics, paramDiag)
120+
}
121+
}
122+
}
123+
}
124+
}
125+
71126
func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagnostics hcl.Diagnostics) {
72127
// The trivy package works with `github.com/zclconf/go-cty`. This package is
73128
// similar to `reflect` in its usage. This package can panic if types are
@@ -180,7 +235,9 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagn
180235

181236
diags := make(hcl.Diagnostics, 0)
182237
rp, rpDiags := parameters(modules)
183-
presets := presets(modules, rp)
238+
// preValidPresets are extracted as written in terraform. Each individual
239+
// param value is checked, however, the preset as a whole might not be valid.
240+
preValidPresets := presets(modules, rp)
184241
tags, tagDiags := workspaceTags(modules, p.Files())
185242
vars := variables(modules)
186243

@@ -191,7 +248,7 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (output *Output, diagn
191248
ModuleOutput: outputs,
192249
Parameters: rp,
193250
WorkspaceTags: tags,
194-
Presets: presets,
251+
Presets: preValidPresets,
195252
Files: p.Files(),
196253
Variables: vars,
197254
}, diags.Extend(rpDiags).Extend(tagDiags)

0 commit comments

Comments
 (0)