From acc4c12ac25455be1b863574be6d81caf8271073 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Mon, 3 Jun 2024 16:15:40 -0400 Subject: [PATCH] variable validation rules must still point to self While variable validation rules can now include other references, they also still need to reference the variable itself. If the variable itself wasn't referenced, then the resulting `Invalid value for variable` error would not make sense. Having no self-references will also cause a panic when trying to reinsert the variable name into the evaluation context, because the context variables map could be nil. A check for a nil map does not need to be added however, because ensuring that a self-reference exists means there will always be at least 1 variable in scope. --- internal/configs/named_values.go | 29 ++++++++++++++++++- .../variable-validation-condition-noself.tf | 10 +++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 internal/configs/testdata/invalid-files/variable-validation-condition-noself.tf diff --git a/internal/configs/named_values.go b/internal/configs/named_values.go index 286c507a11..43a624d9d8 100644 --- a/internal/configs/named_values.go +++ b/internal/configs/named_values.go @@ -180,8 +180,9 @@ func decodeVariableBlock(block *hcl.Block, override bool) (*Variable, hcl.Diagno case "validation": vv, moreDiags := decodeCheckRuleBlock(block, override) diags = append(diags, moreDiags...) - v.Validations = append(v.Validations, vv) + diags = append(diags, checkVariableValidationBlock(v.Name, vv)...) + v.Validations = append(v.Validations, vv) default: // The above cases should be exhaustive for all block types // defined in variableBlockSchema @@ -504,3 +505,29 @@ var outputBlockSchema = &hcl.BodySchema{ {Type: "postcondition"}, }, } + +func checkVariableValidationBlock(varName string, vv *CheckRule) hcl.Diagnostics { + var diags hcl.Diagnostics + + if vv.Condition != nil { + // The validation condition must include a reference to the variable itself + for _, traversal := range vv.Condition.Variables() { + ref, moreDiags := addrs.ParseRef(traversal) + if !moreDiags.HasErrors() { + if addr, ok := ref.Subject.(addrs.InputVariable); ok { + if addr.Name == varName { + return nil + } + } + } + } + + return diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Invalid variable validation condition", + Detail: fmt.Sprintf("The condition for variable %q must refer to var.%s in order to test incoming values.", varName, varName), + Subject: vv.Condition.Range().Ptr(), + }) + } + return nil +} diff --git a/internal/configs/testdata/invalid-files/variable-validation-condition-noself.tf b/internal/configs/testdata/invalid-files/variable-validation-condition-noself.tf new file mode 100644 index 0000000000..3571a58ab1 --- /dev/null +++ b/internal/configs/testdata/invalid-files/variable-validation-condition-noself.tf @@ -0,0 +1,10 @@ +locals { + something = "else" +} + +variable "validation" { + validation { + condition = local.something == "else" + error_message = "Something else." + } +}