Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 0 additions & 61 deletions stackit/internal/services/albwaf/custom_rule_group/bool.go

This file was deleted.

117 changes: 0 additions & 117 deletions stackit/internal/services/albwaf/custom_rule_group/bool_test.go

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ func (r *customRuleGroupResource) Schema(_ context.Context, _ resource.SchemaReq
Optional: true,
Computed: true,
Validators: []validator.String{
OnlyAllowedIfBoolEquals(path.MatchRelative().AtParent().AtName("log"), true),
validate.OnlyAllowedIfBoolEquals(path.MatchRelative().AtParent().AtName("log"), sdkUtils.Ptr(true)),
},
},
"severity": schema.StringAttribute{
Expand Down
37 changes: 37 additions & 0 deletions stackit/internal/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/teambition/rrule-go"

Expand Down Expand Up @@ -399,6 +400,42 @@ func IsLowercased() *Validator {
}
}

// OnlyAllowedIfBoolEquals returns a Validator that prevents this string attribute
// from being set if the target bool attribute does not equal the specified value.
// If value is nil, no validation is performed.
func OnlyAllowedIfBoolEquals(target path.Expression, value *bool) *Validator {
description := "the attribute can only be set if the boolean is set to the provided value"

return &Validator{
description: description,
validate: func(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) {
expression := req.PathExpression.Merge(target)

matchedPaths, diags := req.Config.PathMatches(ctx, expression)
resp.Diagnostics.Append(diags...)

for _, targetPath := range matchedPaths {
var targetBool types.Bool
diags := req.Config.GetAttribute(ctx, targetPath, &targetBool)
resp.Diagnostics.Append(diags...)

// nothing to validate against: no expected value given or target not set in the config
if resp.Diagnostics.HasError() || value == nil || targetBool.IsNull() || targetBool.IsUnknown() {
return
}

if targetBool.ValueBool() != *value {
resp.Diagnostics.AddAttributeError(
req.Path,
"Attribute can not be set",
fmt.Sprintf("This attribute can only be configured when %q is set to %t.", targetPath.String(), *value),
)
}
}
},
}
}

// NoLeadingOrTrailingWhitespace returns a Validator that checks if the input string has leading or trailing whitespace.
// Examples:
// - "example": valid
Expand Down
130 changes: 130 additions & 0 deletions stackit/internal/validate/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import (
"context"
"testing"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
)

func TestUUID(t *testing.T) {
Expand Down Expand Up @@ -1085,3 +1087,131 @@ func TestNoLeadingOrtTrailingWhitespace(t *testing.T) {
})
}
}

func TestOnlyAllowedIfBoolEquals(t *testing.T) {
tests := []struct {
description string
target types.Bool
expectedValue *bool
isValid bool
}{
{
description: "target true, expect true",
target: types.BoolValue(true),
expectedValue: utils.Ptr(true),
isValid: true,
},
{
description: "target false, expect true",
target: types.BoolValue(false),
expectedValue: utils.Ptr(true),
isValid: false,
},
{
description: "target false, expect false",
target: types.BoolValue(false),
expectedValue: utils.Ptr(false),
isValid: true,
},
{
description: "target true, expect false",
target: types.BoolValue(true),
expectedValue: utils.Ptr(false),
isValid: false,
},
{
description: "target unknown, expect true",
target: types.BoolUnknown(),
expectedValue: utils.Ptr(true),
isValid: true,
},
{
description: "target unknown, expect false",
target: types.BoolUnknown(),
expectedValue: utils.Ptr(false),
isValid: true,
},
{
description: "target null, expect true",
target: types.BoolNull(),
expectedValue: utils.Ptr(true),
isValid: true,
},
{
description: "target null, expect false",
target: types.BoolNull(),
expectedValue: utils.Ptr(false),
isValid: true,
},
{
description: "target true, expect nil",
target: types.BoolValue(true),
expectedValue: nil,
isValid: true,
},
{
description: "target false, expect nil",
target: types.BoolValue(false),
expectedValue: nil,
isValid: true,
},
}

for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
ctx := context.Background()

boolVal, err := tt.target.ToTerraformValue(ctx)
if err != nil {
t.Fatalf("Failed to convert bool to tftypes.Value: %s", err)
}

objType := tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"target_bool": tftypes.Bool,
},
}
rawConfig := tftypes.NewValue(objType, map[string]tftypes.Value{
"target_bool": boolVal,
})

req := validator.StringRequest{
Path: path.Root("my_string"),
PathExpression: path.MatchRoot("my_string"),
ConfigValue: types.StringValue("example_string"),
Config: tfsdk.Config{
Raw: rawConfig,
Schema: schema.Schema{
Attributes: map[string]schema.Attribute{
"target_bool": schema.BoolAttribute{},
},
},
},
}

resp := &validator.StringResponse{}

OnlyAllowedIfBoolEquals(path.MatchRoot("target_bool"), tt.expectedValue).ValidateString(ctx, req, resp)

if tt.isValid {
if resp.Diagnostics.HasError() {
t.Fatalf("did not expect validation error, got: %v", resp.Diagnostics)
}
} else {
hasExpectedError := false

for _, diag := range resp.Diagnostics {
if diag.Summary() == "Attribute can not be set" {
hasExpectedError = true
} else {
t.Fatalf("expected validation error, got %q", diag.Summary())
}
}

if !hasExpectedError {
t.Fatalf("expected 'Attribute can not be set' error, got: %v", resp.Diagnostics)
}
}
})
}
}
Loading