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 9316229631..38f3b80d6a 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 32dc3de44b..055e76f26c 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 {