Skip to content

Commit b500ce7

Browse files
authored
internal/schemavalidator: Fix bug where unknown values were returning error diagnostics too early (#252)
* internal/schemavalidator: Fix bug where unknown values were returning error diagnostics too early * changelog
1 parent 16687f3 commit b500ce7

8 files changed

+120
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: BUG FIXES
2+
body: Fixed bug with `ConflictsWith` and `AlsoRequires` validators where unknown values
3+
would raise invalid diagnostics during `terraform validate`.
4+
time: 2024-12-12T15:21:25.964001-05:00
5+
custom:
6+
Issue: "251"

internal/schemavalidator/also_requires.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ func (av AlsoRequiresValidator) MarkdownDescription(_ context.Context) string {
5858

5959
func (av AlsoRequiresValidator) Validate(ctx context.Context, req AlsoRequiresValidatorRequest, res *AlsoRequiresValidatorResponse) {
6060
// If attribute configuration is null, there is nothing else to validate
61-
if req.ConfigValue.IsNull() {
61+
// If attribute configuration is unknown, delay the validation until it is known.
62+
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
6263
return
6364
}
6465

internal/schemavalidator/also_requires_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,33 @@ func TestAlsoRequiresValidatorValidate(t *testing.T) {
8080
path.MatchRoot("foo"),
8181
},
8282
},
83+
"self-is-unknown": {
84+
req: schemavalidator.AlsoRequiresValidatorRequest{
85+
ConfigValue: types.StringUnknown(),
86+
Path: path.Root("bar"),
87+
PathExpression: path.MatchRoot("bar"),
88+
Config: tfsdk.Config{
89+
Schema: schema.Schema{
90+
Attributes: map[string]schema.Attribute{
91+
"foo": schema.Int64Attribute{},
92+
"bar": schema.StringAttribute{},
93+
},
94+
},
95+
Raw: tftypes.NewValue(tftypes.Object{
96+
AttributeTypes: map[string]tftypes.Type{
97+
"foo": tftypes.Number,
98+
"bar": tftypes.String,
99+
},
100+
}, map[string]tftypes.Value{
101+
"foo": tftypes.NewValue(tftypes.Number, nil),
102+
"bar": tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
103+
}),
104+
},
105+
},
106+
in: path.Expressions{
107+
path.MatchRoot("foo"),
108+
},
109+
},
83110
"error_missing-one": {
84111
req: schemavalidator.AlsoRequiresValidatorRequest{
85112
ConfigValue: types.StringValue("bar value"),

internal/schemavalidator/at_least_one_of.go

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ func (av AtLeastOneOfValidator) MarkdownDescription(_ context.Context) string {
5858

5959
func (av AtLeastOneOfValidator) Validate(ctx context.Context, req AtLeastOneOfValidatorRequest, res *AtLeastOneOfValidatorResponse) {
6060
// If attribute configuration is not null, validator already succeeded.
61+
// If attribute configuration is unknown, delay the validation until it is known.
6162
if !req.ConfigValue.IsNull() {
6263
return
6364
}

internal/schemavalidator/at_least_one_of_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,34 @@ func TestAtLeastOneOfValidatorValidate(t *testing.T) {
8484
},
8585
expected: &schemavalidator.AtLeastOneOfValidatorResponse{},
8686
},
87+
"self-is-unknown": {
88+
req: schemavalidator.AtLeastOneOfValidatorRequest{
89+
ConfigValue: types.StringUnknown(),
90+
Path: path.Root("bar"),
91+
PathExpression: path.MatchRoot("bar"),
92+
Config: tfsdk.Config{
93+
Schema: schema.Schema{
94+
Attributes: map[string]schema.Attribute{
95+
"foo": schema.Int64Attribute{},
96+
"bar": schema.StringAttribute{},
97+
},
98+
},
99+
Raw: tftypes.NewValue(tftypes.Object{
100+
AttributeTypes: map[string]tftypes.Type{
101+
"foo": tftypes.Number,
102+
"bar": tftypes.String,
103+
},
104+
}, map[string]tftypes.Value{
105+
"foo": tftypes.NewValue(tftypes.Number, 42),
106+
"bar": tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
107+
}),
108+
},
109+
},
110+
in: path.Expressions{
111+
path.MatchRoot("foo"),
112+
},
113+
expected: &schemavalidator.AtLeastOneOfValidatorResponse{},
114+
},
87115
"error_none-set": {
88116
req: schemavalidator.AtLeastOneOfValidatorRequest{
89117
ConfigValue: types.StringNull(),

internal/schemavalidator/conflicts_with.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ func (av ConflictsWithValidator) MarkdownDescription(_ context.Context) string {
5858

5959
func (av ConflictsWithValidator) Validate(ctx context.Context, req ConflictsWithValidatorRequest, res *ConflictsWithValidatorResponse) {
6060
// If attribute configuration is null, it cannot conflict with others
61-
if req.ConfigValue.IsNull() {
61+
// If attribute configuration is unknown, delay the validation until it is known.
62+
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
6263
return
6364
}
6465

internal/schemavalidator/conflicts_with_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,33 @@ func TestConflictsWithValidatorValidate(t *testing.T) {
139139
path.MatchRoot("foo"),
140140
},
141141
},
142+
"self-is-unknown": {
143+
req: schemavalidator.ConflictsWithValidatorRequest{
144+
ConfigValue: types.StringUnknown(),
145+
Path: path.Root("bar"),
146+
PathExpression: path.MatchRoot("bar"),
147+
Config: tfsdk.Config{
148+
Schema: schema.Schema{
149+
Attributes: map[string]schema.Attribute{
150+
"foo": schema.Int64Attribute{},
151+
"bar": schema.StringAttribute{},
152+
},
153+
},
154+
Raw: tftypes.NewValue(tftypes.Object{
155+
AttributeTypes: map[string]tftypes.Type{
156+
"foo": tftypes.Number,
157+
"bar": tftypes.String,
158+
},
159+
}, map[string]tftypes.Value{
160+
"foo": tftypes.NewValue(tftypes.Number, 42),
161+
"bar": tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
162+
}),
163+
},
164+
},
165+
in: path.Expressions{
166+
path.MatchRoot("foo"),
167+
},
168+
},
142169
"error_allow-duplicate-input": {
143170
req: schemavalidator.ConflictsWithValidatorRequest{
144171
ConfigValue: types.StringValue("bar value"),

internal/schemavalidator/exactly_one_of_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,33 @@ func TestExactlyOneOfValidator(t *testing.T) {
8181
path.MatchRoot("foo"),
8282
},
8383
},
84+
"self-is-unknown": {
85+
req: schemavalidator.ExactlyOneOfValidatorRequest{
86+
ConfigValue: types.StringUnknown(),
87+
Path: path.Root("bar"),
88+
PathExpression: path.MatchRoot("bar"),
89+
Config: tfsdk.Config{
90+
Schema: schema.Schema{
91+
Attributes: map[string]schema.Attribute{
92+
"foo": schema.Int64Attribute{},
93+
"bar": schema.StringAttribute{},
94+
},
95+
},
96+
Raw: tftypes.NewValue(tftypes.Object{
97+
AttributeTypes: map[string]tftypes.Type{
98+
"foo": tftypes.Number,
99+
"bar": tftypes.String,
100+
},
101+
}, map[string]tftypes.Value{
102+
"foo": tftypes.NewValue(tftypes.Number, 42),
103+
"bar": tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
104+
}),
105+
},
106+
},
107+
in: path.Expressions{
108+
path.MatchRoot("foo"),
109+
},
110+
},
84111
"error_too-many": {
85112
req: schemavalidator.ExactlyOneOfValidatorRequest{
86113
ConfigValue: types.StringValue("bar value"),

0 commit comments

Comments
 (0)