Skip to content

Commit

Permalink
Merge pull request #30330 from hashicorp/jbardin/non-nullable-default
Browse files Browse the repository at this point in the history
Handle null variable input with nullable=false
  • Loading branch information
jbardin committed Jan 11, 2022
2 parents 85a2d04 + 9314063 commit b3e7ec1
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
33 changes: 33 additions & 0 deletions internal/terraform/context_validate_test.go
Expand Up @@ -2088,3 +2088,36 @@ output "out" {
t.Fatal(diags.ErrWithWarnings())
}
}

func TestContext2Validate_nonNullableVariableDefaultValidation(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
module "first" {
source = "./mod"
input = null
}
`,

"mod/main.tf": `
variable "input" {
type = string
default = "default"
nullable = false
// Validation expressions should receive the default with nullable=false and
// a null input.
validation {
condition = var.input != null
error_message = "Input cannot be null!"
}
}
`,
})

ctx := testContext2(t, &ContextOpts{})

diags := ctx.Validate(m)
if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}
}
23 changes: 23 additions & 0 deletions internal/terraform/node_module_variable.go
Expand Up @@ -233,6 +233,29 @@ func (n *nodeModuleVariable) evalModuleCallArgument(ctx EvalContext, validateOnl
scope := ctx.EvaluationScope(nil, moduleInstanceRepetitionData)
val, diags := scope.EvalExpr(expr, cty.DynamicPseudoType)

// FIXME: This check is only necessary for v1.1, and is will never be
// present in the v1.2 branch.
//
// Default values are currently being handled in two places, the graph
// transformation where a synthetic default expression is created if there
// was no input expression, and in the evaluator when a reference to the
// variable is evaluated. Unfortunately neither of these covers the case
// where a non-nullable variable default needs to be checked within a
// validation statement
//
// Rather than try and fix the overall variable handling here, which runs
// the risk of encountering more unexpected behavior, we are going to fixup
// this one case to ensure a null value doesn't continue to slip into
// validation. A more extensive refactoring of variable handling has been
// completed in v1.2, and this code will only be relevant for the v1.1
// branch.
if !diags.HasErrors() && val.IsNull() &&
!n.Config.Nullable &&
n.Config.Default != cty.NilVal && !n.Config.Default.IsNull() {
// replace the evaluated value with the actual default
val = n.Config.Default
}

// We intentionally passed DynamicPseudoType to EvalExpr above because
// now we can do our own local type conversion and produce an error message
// with better context if it fails.
Expand Down

0 comments on commit b3e7ec1

Please sign in to comment.