Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validate deprecated attributes from static traversals #31576

Merged
merged 1 commit into from Aug 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 25 additions & 5 deletions internal/configs/configschema/validate_traversal.go
Expand Up @@ -74,14 +74,34 @@ func (b *Block) StaticValidateTraversal(traversal hcl.Traversal) tfdiags.Diagnos
}

if attrS, exists := b.Attributes[name]; exists {
// Check for Deprecated status of this attribute.
// We currently can't provide the user with any useful guidance because
// the deprecation string is not part of the schema, but we can at
// least warn them.
//
// This purposely does not attempt to recurse into nested attribute
// types. Because nested attribute values are often not accessed via a
// direct traversal to the leaf attributes, we cannot reliably detect
// if a nested, deprecated attribute value is actually used from the
// traversal alone. More precise detection of deprecated attributes
// would require adding metadata like marks to the cty value itself, to
// be caught during evaluation.
if attrS.Deprecated {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: `Deprecated attribute`,
Detail: fmt.Sprintf(`The attribute %q is deprecated. Refer to the provider documentation for details.`, name),
Subject: next.SourceRange().Ptr(),
})
}

// For attribute validation we will just apply the rest of the
// traversal to an unknown value of the attribute type and pass through
// HCL's own errors, since we don't want to replicate all of HCL's type
// checking rules here.
// traversal to an unknown value of the attribute type and pass
// through HCL's own errors, since we don't want to replicate all
// of HCL's type checking rules here.
val := cty.UnknownVal(attrS.ImpliedType())
_, hclDiags := after.TraverseRel(val)
diags = diags.Append(hclDiags)
return diags
return diags.Append(hclDiags)
}

if blockS, exists := b.BlockTypes[name]; exists {
Expand Down
16 changes: 11 additions & 5 deletions internal/configs/configschema/validate_traversal_test.go
Expand Up @@ -10,9 +10,10 @@ import (

func TestStaticValidateTraversal(t *testing.T) {
attrs := map[string]*Attribute{
"str": {Type: cty.String, Optional: true},
"list": {Type: cty.List(cty.String), Optional: true},
"dyn": {Type: cty.DynamicPseudoType, Optional: true},
"str": {Type: cty.String, Optional: true},
"list": {Type: cty.List(cty.String), Optional: true},
"dyn": {Type: cty.DynamicPseudoType, Optional: true},
"deprecated": {Type: cty.String, Computed: true, Deprecated: true},
"nested_single": {
Optional: true,
NestedType: &Object{
Expand Down Expand Up @@ -220,6 +221,10 @@ func TestStaticValidateTraversal(t *testing.T) {
`obj.nested_map["key"].optional`,
``,
},
{
`obj.deprecated`,
`Deprecated attribute: The attribute "deprecated" is deprecated. Refer to the provider documentation for details.`,
},
}

for _, test := range tests {
Expand All @@ -239,8 +244,9 @@ func TestStaticValidateTraversal(t *testing.T) {
t.Errorf("unexpected error: %s", diags.Err().Error())
}
} else {
if diags.HasErrors() {
if got := diags.Err().Error(); got != test.WantError {
err := diags.ErrWithWarnings()
if err != nil {
if got := err.Error(); got != test.WantError {
t.Errorf("wrong error\ngot: %s\nwant: %s", got, test.WantError)
}
} else {
Expand Down