From 016c4f782de22c3fa97bd8b0042f7c6bfbe1a9aa Mon Sep 17 00:00:00 2001 From: James Bardin Date: Sat, 27 Jul 2019 12:11:11 -0700 Subject: [PATCH] don't reflect nil in schema validation Nil values were not previously expected during validation, but they can appear in some situations with the new protocol. Add checks to prevent using zero reflect.Values. --- helper/schema/schema.go | 23 +++++++++++++++++++++++ helper/schema/schema_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/helper/schema/schema.go b/helper/schema/schema.go index 931622963..38f3b80d6 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -1440,6 +1440,11 @@ func (m schemaMap) validateList( } } + // schemaMap can't validate nil + if raw == nil { + return nil, nil + } + // We use reflection to verify the slice because you can't // case to []interface{} unless the slice is exactly that type. rawV := reflect.ValueOf(raw) @@ -1518,6 +1523,10 @@ func (m schemaMap) validateMap( } } + // schemaMap can't validate nil + if raw == nil { + return nil, nil + } // We use reflection to verify the slice because you can't // case to []interface{} unless the slice is exactly that type. rawV := reflect.ValueOf(raw) @@ -1644,6 +1653,12 @@ func (m schemaMap) validateObject( schema map[string]*Schema, c *terraform.ResourceConfig) ([]string, []error) { raw, _ := c.Get(k) + + // schemaMap can't validate nil + if raw == nil { + return nil, nil + } + if _, ok := raw.(map[string]interface{}); !ok && !c.IsComputed(k) { return nil, []error{fmt.Errorf( "%s: expected object, got %s", @@ -1688,6 +1703,14 @@ func (m schemaMap) validatePrimitive( raw interface{}, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { + + // a nil value shouldn't happen in the old protocol, and in the new + // protocol the types have already been validated. Either way, we can't + // reflect on nil, so don't panic. + if raw == nil { + return nil, nil + } + // Catch if the user gave a complex type where a primitive was // expected, so we can return a friendly error message that // doesn't contain Go type system terminology. diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 32dc3de44..055e76f26 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -5465,6 +5465,39 @@ func TestSchemaMap_Validate(t *testing.T) { }, Err: false, }, + + "unexpected nils values": { + Schema: map[string]*Schema{ + "strings": &Schema{ + Type: TypeList, + Optional: true, + Elem: &Schema{ + Type: TypeString, + }, + }, + "block": &Schema{ + Type: TypeList, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "int": &Schema{ + Type: TypeInt, + Required: true, + }, + }, + }, + }, + }, + + Config: map[string]interface{}{ + "strings": []interface{}{"1", nil}, + "block": []interface{}{map[string]interface{}{ + "int": nil, + }, + nil, + }, + }, + }, } for tn, tc := range cases {