Skip to content

Commit

Permalink
helper/schema: Additional validation for schema attribute references
Browse files Browse the repository at this point in the history
Reference: hashicorp#71
  • Loading branch information
bflad committed Mar 19, 2020
1 parent 22c75cb commit 5032065
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 15 deletions.
36 changes: 28 additions & 8 deletions helper/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,21 +683,21 @@ func (m schemaMap) internalValidate(topSchemaMap schemaMap, attrsOnly bool) erro
}

if len(v.ConflictsWith) > 0 {
err := checkKeysAgainstSchemaFlags(k, v.ConflictsWith, topSchemaMap)
err := checkKeysAgainstSchemaFlags(k, v.ConflictsWith, topSchemaMap, v)
if err != nil {
return fmt.Errorf("ConflictsWith: %+v", err)
}
}

if len(v.ExactlyOneOf) > 0 {
err := checkKeysAgainstSchemaFlags(k, v.ExactlyOneOf, topSchemaMap)
err := checkKeysAgainstSchemaFlags(k, v.ExactlyOneOf, topSchemaMap, v)
if err != nil {
return fmt.Errorf("ExactlyOneOf: %+v", err)
}
}

if len(v.AtLeastOneOf) > 0 {
err := checkKeysAgainstSchemaFlags(k, v.AtLeastOneOf, topSchemaMap)
err := checkKeysAgainstSchemaFlags(k, v.AtLeastOneOf, topSchemaMap, v)
if err != nil {
return fmt.Errorf("AtLeastOneOf: %+v", err)
}
Expand Down Expand Up @@ -809,14 +809,20 @@ func (m schemaMap) internalValidate(topSchemaMap schemaMap, attrsOnly bool) erro
return nil
}

func checkKeysAgainstSchemaFlags(k string, keys []string, topSchemaMap schemaMap) error {
func checkKeysAgainstSchemaFlags(k string, keys []string, topSchemaMap schemaMap, self *Schema) error {
for _, key := range keys {
parts := strings.Split(key, ".")
sm := topSchemaMap
var target *Schema
for _, part := range parts {
// Skip index fields
if _, err := strconv.Atoi(part); err == nil {
// Skip index fields if 0
partInt, err := strconv.Atoi(part)

if err == nil {
if partInt != 0 {
return fmt.Errorf("%s configuration block reference (%s) can only use the .0. index for TypeList and MaxItems: 1 configuration blocks", k, key)
}

continue
}

Expand All @@ -825,13 +831,27 @@ func checkKeysAgainstSchemaFlags(k string, keys []string, topSchemaMap schemaMap
return fmt.Errorf("%s references unknown attribute (%s) at part (%s)", k, key, part)
}

if subResource, ok := target.Elem.(*Resource); ok {
sm = schemaMap(subResource.Schema)
subResource, ok := target.Elem.(*Resource)

if !ok {
continue
}

if target.Type == TypeSet || target.MaxItems != 1 {
return fmt.Errorf("%s configuration block reference (%s) can only be used with TypeList and MaxItems: 1 configuration blocks", k, key)
}

sm = schemaMap(subResource.Schema)
}

if target == nil {
return fmt.Errorf("%s cannot find target attribute (%s), sm: %#v", k, key, sm)
}

if target == self {
return fmt.Errorf("%s cannot reference self (%s)", k, key)
}

if target.Required {
return fmt.Errorf("%s cannot contain Required attribute (%s)", k, key)
}
Expand Down
38 changes: 31 additions & 7 deletions helper/schema/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3323,14 +3323,15 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
},
},
},
false, // TODO: This should return an error as it will always error during runtime
true,
},

"ConflictsWith list index syntax with list configuration block existing attribute": {
map[string]*Schema{
"config_block_attr": &Schema{
Type: TypeList,
Optional: true,
MaxItems: 1,
Elem: &Resource{
Schema: map[string]*Schema{
"nested_attr": &Schema{
Expand Down Expand Up @@ -3372,6 +3373,29 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
true,
},

"ConflictsWith list index syntax with list configuration block missing MaxItems": {
map[string]*Schema{
"config_block_attr": &Schema{
Type: TypeList,
Optional: true,
Elem: &Resource{
Schema: map[string]*Schema{
"nested_attr": &Schema{
Type: TypeString,
Optional: true,
},
},
},
},
"test": &Schema{
Type: TypeBool,
Optional: true,
ConflictsWith: []string{"config_block_attr.0.missing_attr"},
},
},
true,
},

"ConflictsWith list index syntax with set configuration block existing attribute": {
map[string]*Schema{
"config_block_attr": &Schema{
Expand All @@ -3392,7 +3416,7 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
ConflictsWith: []string{"config_block_attr.0.nested_attr"},
},
},
false, // TODO: This should return an error as sets cannot be indexed
true,
},

"ConflictsWith list index syntax with set configuration block missing attribute": {
Expand Down Expand Up @@ -3438,7 +3462,7 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
ConflictsWith: []string{"config_block_attr.nested_attr"},
},
},
false, // TODO: This should return an error as validateConflictingAttributes will never error
true,
},

"ConflictsWith map key syntax with list configuration block self reference": {
Expand All @@ -3457,7 +3481,7 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
},
},
},
false, // TODO: This should return an error as validateConflictingAttributes will never error
true,
},

"ConflictsWith map key syntax with set configuration block existing attribute": {
Expand All @@ -3480,7 +3504,7 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
ConflictsWith: []string{"config_block_attr.nested_attr"},
},
},
false, // TODO: This should return an error as validateConflictingAttributes will never error and sets cannot be indexed
true,
},

"ConflictsWith map key syntax with set configuration block self reference": {
Expand All @@ -3499,7 +3523,7 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
},
},
},
false, // TODO: This should return an error as validateConflictingAttributes will never error and sets cannot be indexed
true,
},

"ConflictsWith map key syntax with map attribute": {
Expand Down Expand Up @@ -3542,7 +3566,7 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
ConflictsWith: []string{"test"},
},
},
false, // TODO: This should return an error as it will always error during runtime
true,
},

"Sub-resource invalid": {
Expand Down

0 comments on commit 5032065

Please sign in to comment.