Skip to content

Commit 5288e44

Browse files
authored
internal/fwschema: Validate leading numerics in attribute names (#708)
Reference: #705 The error diagnostic details will only contain this additional context if a numeric is detected.
1 parent 19e617b commit 5288e44

File tree

5 files changed

+160
-5
lines changed

5 files changed

+160
-5
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: ENHANCEMENTS
2+
body: 'datasource/schema: Raise validation errors if attempting to use attribute names
3+
with leading numerics (0-9), which are invalid in the Terraform configuration language'
4+
time: 2023-03-30T10:56:17.789569-04:00
5+
custom:
6+
Issue: "705"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: ENHANCEMENTS
2+
body: 'provider/schema: Raise validation errors if attempting to use attribute names
3+
with leading numerics (0-9), which are invalid in the Terraform configuration language'
4+
time: 2023-03-30T10:56:18.789569-04:00
5+
custom:
6+
Issue: "705"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: ENHANCEMENTS
2+
body: 'resource/schema: Raise validation errors if attempting to use attribute names
3+
with leading numerics (0-9), which are invalid in the Terraform configuration language'
4+
time: 2023-03-30T10:56:19.789569-04:00
5+
custom:
6+
Issue: "705"

internal/fwschema/attribute_name_validation.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ package fwschema
33
import (
44
"fmt"
55
"regexp"
6+
"strings"
67

78
"github.com/hashicorp/terraform-plugin-framework/diag"
89
"github.com/hashicorp/terraform-plugin-framework/path"
910
)
1011

12+
// NumericPrefixRegex is a regular expression which matches whether a string
13+
// begins with a numeric (0-9).
14+
var NumericPrefixRegex = regexp.MustCompile(`^[0-9]`)
15+
1116
// ReservedProviderAttributeNames contains the list of root attribute names
1217
// which should not be included in provider-defined provider schemas since
1318
// they require practitioners to implement special syntax in their
@@ -49,11 +54,8 @@ var ReservedResourceAttributeNames = []string{
4954
// including them in attribute names. Introducing them could cause practitioner
5055
// confusion.
5156
//
52-
// TODO: Validate leading numeric characters
53-
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/705
54-
//
5557
// [identifiers]: https://developer.hashicorp.com/terraform/language/syntax/configuration#identifiers
56-
var ValidAttributeNameRegex = regexp.MustCompile("^[a-z0-9_]+$")
58+
var ValidAttributeNameRegex = regexp.MustCompile("^[a-z_][a-z0-9_]*$")
5759

5860
// IsReservedProviderAttributeName returns an error diagnostic if the given
5961
// attribute path represents a root attribute name in
@@ -132,6 +134,16 @@ func IsValidAttributeName(name string, attributePath path.Path) diag.Diagnostics
132134
return diags
133135
}
134136

137+
var message strings.Builder
138+
139+
message.WriteString("Names must ")
140+
141+
if NumericPrefixRegex.MatchString(name) {
142+
message.WriteString("begin with a lowercase alphabet character (a-z) or underscore (_) and must ")
143+
}
144+
145+
message.WriteString("only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).")
146+
135147
// The diagnostic path is intentionally omitted as it is invalid in this
136148
// context. Diagnostic paths are intended to be mapped to actual data,
137149
// while this path information must be synthesized.
@@ -140,7 +152,7 @@ func IsValidAttributeName(name string, attributePath path.Path) diag.Diagnostics
140152
"When validating the schema, an implementation issue was found. "+
141153
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
142154
fmt.Sprintf("%q at schema path %q is an invalid attribute/block name. ", name, attributePath)+
143-
"Names must only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).",
155+
message.String(),
144156
)
145157

146158
return diags

internal/fwschema/attribute_name_validation_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,128 @@ func TestIsReservedResourceAttributeName(t *testing.T) {
215215
})
216216
}
217217
}
218+
219+
func TestIsValidAttributeName(t *testing.T) {
220+
t.Parallel()
221+
222+
testCases := map[string]struct {
223+
name string
224+
expected diag.Diagnostics
225+
}{
226+
"empty": {
227+
name: "",
228+
expected: diag.Diagnostics{
229+
diag.NewErrorDiagnostic(
230+
"Invalid Attribute/Block Name",
231+
"When validating the schema, an implementation issue was found. "+
232+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
233+
"\"\" at schema path \"\" is an invalid attribute/block name. "+
234+
"Names must only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).",
235+
),
236+
},
237+
},
238+
"ascii-lowercase-alphabet": {
239+
name: "test",
240+
expected: nil,
241+
},
242+
"ascii-lowercase-alphabet-leading-underscore": {
243+
name: "_test",
244+
expected: nil,
245+
},
246+
"ascii-lowercase-alphabet-middle-hyphens": {
247+
name: "test-me",
248+
expected: diag.Diagnostics{
249+
diag.NewErrorDiagnostic(
250+
"Invalid Attribute/Block Name",
251+
"When validating the schema, an implementation issue was found. "+
252+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
253+
"\"test-me\" at schema path \"test-me\" is an invalid attribute/block name. "+
254+
"Names must only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).",
255+
),
256+
},
257+
},
258+
"ascii-lowercase-alphabet-middle-underscore": {
259+
name: "test_me",
260+
expected: nil,
261+
},
262+
"ascii-lowercase-alphanumeric": {
263+
name: "test123",
264+
expected: nil,
265+
},
266+
"ascii-lowercase-alphanumeric-leading-numeric": {
267+
name: "123test",
268+
expected: diag.Diagnostics{
269+
diag.NewErrorDiagnostic(
270+
"Invalid Attribute/Block Name",
271+
"When validating the schema, an implementation issue was found. "+
272+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
273+
"\"123test\" at schema path \"123test\" is an invalid attribute/block name. "+
274+
"Names must begin with a lowercase alphabet character (a-z) or underscore (_) and "+
275+
"must only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).",
276+
),
277+
},
278+
},
279+
"ascii-uppercase-alphabet": {
280+
name: "TEST",
281+
expected: diag.Diagnostics{
282+
diag.NewErrorDiagnostic(
283+
"Invalid Attribute/Block Name",
284+
"When validating the schema, an implementation issue was found. "+
285+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
286+
"\"TEST\" at schema path \"TEST\" is an invalid attribute/block name. "+
287+
"Names must only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).",
288+
),
289+
},
290+
},
291+
"ascii-uppercase-alphanumeric": {
292+
name: "TEST123",
293+
expected: diag.Diagnostics{
294+
diag.NewErrorDiagnostic(
295+
"Invalid Attribute/Block Name",
296+
"When validating the schema, an implementation issue was found. "+
297+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
298+
"\"TEST123\" at schema path \"TEST123\" is an invalid attribute/block name. "+
299+
"Names must only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).",
300+
),
301+
},
302+
},
303+
"invalid-bytes": {
304+
name: "\xff\xff",
305+
expected: diag.Diagnostics{
306+
diag.NewErrorDiagnostic(
307+
"Invalid Attribute/Block Name",
308+
"When validating the schema, an implementation issue was found. "+
309+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
310+
"\"\\xff\\xff\" at schema path \"\\xff\\xff\" is an invalid attribute/block name. "+
311+
"Names must only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).",
312+
),
313+
},
314+
},
315+
"unicode": {
316+
name: `tést`, // t, latin small letter e with acute (00e9), s, t
317+
expected: diag.Diagnostics{
318+
diag.NewErrorDiagnostic(
319+
"Invalid Attribute/Block Name",
320+
"When validating the schema, an implementation issue was found. "+
321+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
322+
"\"tést\" at schema path \"tést\" is an invalid attribute/block name. "+
323+
"Names must only contain lowercase alphanumeric characters (a-z, 0-9) and underscores (_).",
324+
),
325+
},
326+
},
327+
}
328+
329+
for name, testCase := range testCases {
330+
name, testCase := name, testCase
331+
332+
t.Run(name, func(t *testing.T) {
333+
t.Parallel()
334+
335+
got := fwschema.IsValidAttributeName(testCase.name, path.Root(testCase.name))
336+
337+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
338+
t.Errorf("unexpected difference: %s", diff)
339+
}
340+
})
341+
}
342+
}

0 commit comments

Comments
 (0)