From 1db84fb10a0cc299d707987c8fced98155897f34 Mon Sep 17 00:00:00 2001 From: Adrian Lai Date: Tue, 4 Nov 2025 12:36:34 +0000 Subject: [PATCH 1/2] Add validators for UUID attributes The API often doesn't return useful error messages. In cases where users might mistakenly use names of resources rather than their corresponding ids, this can lead to confusion. Improve usability by adding some validation. --- .../provider/cloudprovider_gcp_resource.go | 5 ++ internal/provider/firefly_config_resource.go | 3 ++ .../provider/registry_account_resource.go | 5 ++ internal/provider/service_account_resource.go | 5 ++ internal/validators/uuid.go | 48 +++++++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 internal/validators/uuid.go diff --git a/internal/provider/cloudprovider_gcp_resource.go b/internal/provider/cloudprovider_gcp_resource.go index 02e0cf7..36c2619 100644 --- a/internal/provider/cloudprovider_gcp_resource.go +++ b/internal/provider/cloudprovider_gcp_resource.go @@ -8,12 +8,14 @@ import ( "fmt" "terraform-provider-tlspc/internal/tlspc" + "terraform-provider-tlspc/internal/validators" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -60,6 +62,9 @@ func (r *cloudProviderGCPResource) Schema(_ context.Context, _ resource.SchemaRe "team": schema.StringAttribute{ Required: true, MarkdownDescription: "The ID of the owning Team", + Validators: []validator.String{ + validators.Uuid(), + }, }, "service_account_email": schema.StringAttribute{ Required: true, diff --git a/internal/provider/firefly_config_resource.go b/internal/provider/firefly_config_resource.go index 80c7806..132efd5 100644 --- a/internal/provider/firefly_config_resource.go +++ b/internal/provider/firefly_config_resource.go @@ -52,6 +52,9 @@ func (r *fireflyConfigResource) Schema(_ context.Context, _ resource.SchemaReque "subca_provider": schema.StringAttribute{ Required: true, MarkdownDescription: "The ID of the Firefly SubCA Provider", + Validators: []validator.String{ + validators.Uuid(), + }, }, "service_accounts": schema.SetAttribute{ Required: true, diff --git a/internal/provider/registry_account_resource.go b/internal/provider/registry_account_resource.go index 22f08e4..cd96d91 100644 --- a/internal/provider/registry_account_resource.go +++ b/internal/provider/registry_account_resource.go @@ -8,12 +8,14 @@ import ( "fmt" "terraform-provider-tlspc/internal/tlspc" + "terraform-provider-tlspc/internal/validators" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -52,6 +54,9 @@ func (r *registryAccountResource) Schema(_ context.Context, _ resource.SchemaReq "owner": schema.StringAttribute{ Required: true, MarkdownDescription: "ID of the team that owns this service account", + Validators: []validator.String{ + validators.Uuid(), + }, }, "scopes": schema.SetAttribute{ Required: true, diff --git a/internal/provider/service_account_resource.go b/internal/provider/service_account_resource.go index e3aae1e..c78ca71 100644 --- a/internal/provider/service_account_resource.go +++ b/internal/provider/service_account_resource.go @@ -8,12 +8,14 @@ import ( "fmt" "terraform-provider-tlspc/internal/tlspc" + "terraform-provider-tlspc/internal/validators" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -52,6 +54,9 @@ func (r *serviceAccountResource) Schema(_ context.Context, _ resource.SchemaRequ "owner": schema.StringAttribute{ Required: true, MarkdownDescription: "ID of the team that owns this service account", + Validators: []validator.String{ + validators.Uuid(), + }, }, "scopes": schema.SetAttribute{ Required: true, diff --git a/internal/validators/uuid.go b/internal/validators/uuid.go new file mode 100644 index 0000000..3dce140 --- /dev/null +++ b/internal/validators/uuid.go @@ -0,0 +1,48 @@ +// Copyright (c) Venafi, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validators + +import ( + "context" + "fmt" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +func Uuid() uuidValidator { + return uuidValidator{} +} + +type uuidValidator struct { +} + +// Description returns a plain text description of the validator's behavior, suitable for a practitioner to understand its impact. +func (v uuidValidator) Description(ctx context.Context) string { + return "string must be a uuid" +} + +// MarkdownDescription returns a markdown formatted description of the validator's behavior, suitable for a practitioner to understand its impact. +func (v uuidValidator) MarkdownDescription(ctx context.Context) string { + return "string must be a uuid" +} + +// Validate runs the main validation logic of the validator, reading configuration data out of `req` and updating `resp` with diagnostics. +func (v uuidValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { + // If the value is unknown or null, there is nothing to validate. + if req.ConfigValue.IsUnknown() || req.ConfigValue.IsNull() { + return + } + + if err := uuid.Validate(req.ConfigValue.ValueString()); err != nil { + + resp.Diagnostics.AddAttributeError( + req.Path, + "Invalid uuid", + fmt.Sprintf("String must be a uuid: %s", err), + ) + + return + } +} From 4d7520c5edc6f4df231a02426964eae54fd44dc0 Mon Sep 17 00:00:00 2001 From: Adrian Lai Date: Tue, 4 Nov 2025 12:59:57 +0000 Subject: [PATCH 2/2] Add uuid set validators for attributes --- internal/provider/firefly_config_resource.go | 9 +++++++++ internal/provider/service_account_resource.go | 4 ++++ internal/provider/team_resource.go | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/internal/provider/firefly_config_resource.go b/internal/provider/firefly_config_resource.go index 132efd5..cc35a57 100644 --- a/internal/provider/firefly_config_resource.go +++ b/internal/provider/firefly_config_resource.go @@ -8,12 +8,15 @@ import ( "fmt" "terraform-provider-tlspc/internal/tlspc" + "terraform-provider-tlspc/internal/validators" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -60,11 +63,17 @@ func (r *fireflyConfigResource) Schema(_ context.Context, _ resource.SchemaReque Required: true, ElementType: types.StringType, MarkdownDescription: "A list of service account IDs", + Validators: []validator.Set{ + setvalidator.ValueStringsAre(validators.Uuid()), + }, }, "policies": schema.SetAttribute{ Required: true, ElementType: types.StringType, MarkdownDescription: "A list of Firefly Issuance Policy IDs", + Validators: []validator.Set{ + setvalidator.ValueStringsAre(validators.Uuid()), + }, }, }, } diff --git a/internal/provider/service_account_resource.go b/internal/provider/service_account_resource.go index c78ca71..205098f 100644 --- a/internal/provider/service_account_resource.go +++ b/internal/provider/service_account_resource.go @@ -10,6 +10,7 @@ import ( "terraform-provider-tlspc/internal/tlspc" "terraform-provider-tlspc/internal/validators" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -97,6 +98,9 @@ A list of scopes that this service account is authorised for. Available options Optional: true, ElementType: types.StringType, MarkdownDescription: "List of Applications which this service account is authorised for", + Validators: []validator.Set{ + setvalidator.ValueStringsAre(validators.Uuid()), + }, }, }, } diff --git a/internal/provider/team_resource.go b/internal/provider/team_resource.go index 555f928..c122fbd 100644 --- a/internal/provider/team_resource.go +++ b/internal/provider/team_resource.go @@ -9,7 +9,9 @@ import ( "reflect" "terraform-provider-tlspc/internal/tlspc" + "terraform-provider-tlspc/internal/validators" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -64,6 +66,9 @@ func (r *teamResource) Schema(_ context.Context, _ resource.SchemaRequest, resp Required: true, ElementType: types.StringType, MarkdownDescription: "List of user ids", + Validators: []validator.Set{ + setvalidator.ValueStringsAre(validators.Uuid()), + }, }, "user_matching_rules": schema.SetNestedAttribute{ Optional: true,