From acfb3faafbd60bdb64cc90c7b470a1aa4abafc32 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 10 Dec 2024 21:49:13 +0400 Subject: [PATCH 1/4] fix(oidc-auth): comma formatted bound claims required space formatting --- .../pkg/modifiers/comma_space_map_modifier.go | 60 +++++++++++++++++++ .../provider/resource/identity_oidc_auth.go | 19 +++--- 2 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 internal/pkg/modifiers/comma_space_map_modifier.go diff --git a/internal/pkg/modifiers/comma_space_map_modifier.go b/internal/pkg/modifiers/comma_space_map_modifier.go new file mode 100644 index 0000000..883cb21 --- /dev/null +++ b/internal/pkg/modifiers/comma_space_map_modifier.go @@ -0,0 +1,60 @@ +package pkg + +import ( + "context" + "strings" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// CommaSpaceMapModifier ensures consistent formatting of comma-separated strings in map values +type CommaSpaceMapModifier struct{} + +func (m CommaSpaceMapModifier) Description(ctx context.Context) string { + return "Ensures consistent formatting of comma-separated strings in map values with spaces after commas" +} + +func (m CommaSpaceMapModifier) MarkdownDescription(ctx context.Context) string { + return "Ensures consistent formatting of comma-separated strings in map values with spaces after commas" +} + +func (m CommaSpaceMapModifier) PlanModifyMap(ctx context.Context, req planmodifier.MapRequest, resp *planmodifier.MapResponse) { + if req.PlanValue.IsUnknown() || req.PlanValue.IsNull() { + return + } + + planElements := req.PlanValue.Elements() + newElements := make(map[string]types.String) + + for key, value := range planElements { + strValue := value.(types.String) + if !strValue.IsNull() && !strValue.IsUnknown() { + parts := strings.Split(strValue.ValueString(), ",") + + // Trim spaces from each part and rejoin with ", " + for i, part := range parts { + parts[i] = strings.TrimSpace(part) + } + + formattedValue := strings.Join(parts, ", ") + + newElements[key] = types.StringValue(formattedValue) + } else { + // Preserve null/unknown values + newElements[key] = strValue + } + } + + newMapValue, diags := types.MapValueFrom(ctx, types.StringType, newElements) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resp.PlanValue = newMapValue +} + +func CommaSpaceMap() CommaSpaceMapModifier { + return CommaSpaceMapModifier{} +} diff --git a/internal/provider/resource/identity_oidc_auth.go b/internal/provider/resource/identity_oidc_auth.go index df4e220..eda21ab 100644 --- a/internal/provider/resource/identity_oidc_auth.go +++ b/internal/provider/resource/identity_oidc_auth.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" infisical "terraform-provider-infisical/internal/client" - infisicalclient "terraform-provider-infisical/internal/client" + pkg "terraform-provider-infisical/internal/pkg/modifiers" infisicalstrings "terraform-provider-infisical/internal/pkg/strings" "terraform-provider-infisical/internal/pkg/terraform" @@ -88,11 +88,14 @@ func (r *IdentityOidcAuthResource) Schema(_ context.Context, _ resource.SchemaRe PlanModifiers: []planmodifier.List{listplanmodifier.UseStateForUnknown()}, }, "bound_claims": schema.MapAttribute{ - Description: "The attributes that should be present in the JWT for it to be valid. The provided values can be a glob pattern.", - Optional: true, - Computed: true, - ElementType: types.StringType, - PlanModifiers: []planmodifier.Map{mapplanmodifier.UseStateForUnknown()}, + Description: "The attributes that should be present in the JWT for it to be valid. The provided values can be a glob pattern.", + Optional: true, + Computed: true, + ElementType: types.StringType, + PlanModifiers: []planmodifier.Map{ + mapplanmodifier.UseStateForUnknown(), + pkg.CommaSpaceMapModifier{}, + }, }, "bound_subject": schema.StringAttribute{ Description: "The expected principal that is the subject of the JWT.", @@ -163,7 +166,7 @@ func (r *IdentityOidcAuthResource) Configure(_ context.Context, req resource.Con r.client = client } -func updateOidcAuthStateByApi(ctx context.Context, diagnose diag.Diagnostics, plan *IdentityOidcAuthResourceModel, newIdentityOidcAuth *infisicalclient.IdentityOidcAuth) { +func updateOidcAuthStateByApi(ctx context.Context, diagnose diag.Diagnostics, plan *IdentityOidcAuthResourceModel, newIdentityOidcAuth *infisical.IdentityOidcAuth) { plan.AccessTokenMaxTTL = types.Int64Value(newIdentityOidcAuth.AccessTokenMaxTTL) plan.AccessTokenTTL = types.Int64Value(newIdentityOidcAuth.AccessTokenTTL) plan.AccessTokenNumUsesLimit = types.Int64Value(newIdentityOidcAuth.AccessTokenNumUsesLimit) @@ -309,7 +312,7 @@ func (r *IdentityOidcAuthResource) Read(ctx context.Context, req resource.ReadRe }) if err != nil { - if err == infisicalclient.ErrNotFound { + if err == infisical.ErrNotFound { resp.State.RemoveResource(ctx) return } else { From 6452714a41080801381d938bebfa3a78855c9ca6 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Wed, 11 Dec 2024 05:08:53 +0400 Subject: [PATCH 2/4] fix(oidc-auth): comma formatted bound claims required space formatting --- .../pkg/modifiers/comma_space_map_modifier.go | 24 ++++++++++++++--- .../provider/resource/identity_oidc_auth.go | 27 ++++++++++++++++--- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/internal/pkg/modifiers/comma_space_map_modifier.go b/internal/pkg/modifiers/comma_space_map_modifier.go index 883cb21..08d8961 100644 --- a/internal/pkg/modifiers/comma_space_map_modifier.go +++ b/internal/pkg/modifiers/comma_space_map_modifier.go @@ -27,21 +27,36 @@ func (m CommaSpaceMapModifier) PlanModifyMap(ctx context.Context, req planmodifi planElements := req.PlanValue.Elements() newElements := make(map[string]types.String) + // Check config format if available + var configFormat bool // true = spaces, false = no spaces + if !req.ConfigValue.IsNull() { + configElements := req.ConfigValue.Elements() + // Look at first value to determine format + for _, v := range configElements { + if str, ok := v.(types.String); ok && !str.IsNull() { + configFormat = strings.Contains(str.ValueString(), ", ") + break + } + } + } + for key, value := range planElements { strValue := value.(types.String) if !strValue.IsNull() && !strValue.IsUnknown() { parts := strings.Split(strValue.ValueString(), ",") - - // Trim spaces from each part and rejoin with ", " for i, part := range parts { parts[i] = strings.TrimSpace(part) } - formattedValue := strings.Join(parts, ", ") + var formattedValue string + if configFormat { + formattedValue = strings.Join(parts, ", ") + } else { + formattedValue = strings.Join(parts, ",") + } newElements[key] = types.StringValue(formattedValue) } else { - // Preserve null/unknown values newElements[key] = strValue } } @@ -55,6 +70,7 @@ func (m CommaSpaceMapModifier) PlanModifyMap(ctx context.Context, req planmodifi resp.PlanValue = newMapValue } +// CommaSpaceMap returns a new instance of CommaSpaceMapModifier func CommaSpaceMap() CommaSpaceMapModifier { return CommaSpaceMapModifier{} } diff --git a/internal/provider/resource/identity_oidc_auth.go b/internal/provider/resource/identity_oidc_auth.go index eda21ab..aa9686f 100644 --- a/internal/provider/resource/identity_oidc_auth.go +++ b/internal/provider/resource/identity_oidc_auth.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" infisical "terraform-provider-infisical/internal/client" + infisicalclient "terraform-provider-infisical/internal/client" pkg "terraform-provider-infisical/internal/pkg/modifiers" infisicalstrings "terraform-provider-infisical/internal/pkg/strings" "terraform-provider-infisical/internal/pkg/terraform" @@ -166,7 +167,7 @@ func (r *IdentityOidcAuthResource) Configure(_ context.Context, req resource.Con r.client = client } -func updateOidcAuthStateByApi(ctx context.Context, diagnose diag.Diagnostics, plan *IdentityOidcAuthResourceModel, newIdentityOidcAuth *infisical.IdentityOidcAuth) { +func updateOidcAuthStateByApi(ctx context.Context, diagnose diag.Diagnostics, plan *IdentityOidcAuthResourceModel, newIdentityOidcAuth *infisicalclient.IdentityOidcAuth) { plan.AccessTokenMaxTTL = types.Int64Value(newIdentityOidcAuth.AccessTokenMaxTTL) plan.AccessTokenTTL = types.Int64Value(newIdentityOidcAuth.AccessTokenTTL) plan.AccessTokenNumUsesLimit = types.Int64Value(newIdentityOidcAuth.AccessTokenNumUsesLimit) @@ -178,7 +179,27 @@ func updateOidcAuthStateByApi(ctx context.Context, diagnose diag.Diagnostics, pl boundClaimsElements := make(map[string]attr.Value) for key, value := range newIdentityOidcAuth.BoundClaims { - boundClaimsElements[key] = types.StringValue(value) + // Check plan format + useSpaces := false + if !plan.BoundClaims.IsNull() { + if planValue, ok := plan.BoundClaims.Elements()[key]; ok { + planStr := planValue.(types.String).ValueString() + useSpaces = strings.Contains(planStr, ", ") + } + } + + // Split and normalize + parts := strings.Split(value, ",") + for i, part := range parts { + parts[i] = strings.TrimSpace(part) + } + + // Use the same format as the plan + if useSpaces { + boundClaimsElements[key] = types.StringValue(strings.Join(parts, ", ")) + } else { + boundClaimsElements[key] = types.StringValue(strings.Join(parts, ",")) + } } boundClaimsMapValue, diags := types.MapValue(types.StringType, boundClaimsElements) @@ -312,7 +333,7 @@ func (r *IdentityOidcAuthResource) Read(ctx context.Context, req resource.ReadRe }) if err != nil { - if err == infisical.ErrNotFound { + if err == infisicalclient.ErrNotFound { resp.State.RemoveResource(ctx) return } else { From 27beaedc8d3a5ee1f428ee89d161516c93855358 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Wed, 11 Dec 2024 05:16:08 +0400 Subject: [PATCH 3/4] Lint --- internal/pkg/modifiers/comma_space_map_modifier.go | 11 ++++++++--- internal/provider/resource/identity_oidc_auth.go | 5 +++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/internal/pkg/modifiers/comma_space_map_modifier.go b/internal/pkg/modifiers/comma_space_map_modifier.go index 08d8961..8749d04 100644 --- a/internal/pkg/modifiers/comma_space_map_modifier.go +++ b/internal/pkg/modifiers/comma_space_map_modifier.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// CommaSpaceMapModifier ensures consistent formatting of comma-separated strings in map values +// CommaSpaceMapModifier ensures consistent formatting of comma-separated strings in map values. type CommaSpaceMapModifier struct{} func (m CommaSpaceMapModifier) Description(ctx context.Context) string { @@ -41,7 +41,12 @@ func (m CommaSpaceMapModifier) PlanModifyMap(ctx context.Context, req planmodifi } for key, value := range planElements { - strValue := value.(types.String) + strValue, ok := value.(types.String) + + if !ok { + continue + } + if !strValue.IsNull() && !strValue.IsUnknown() { parts := strings.Split(strValue.ValueString(), ",") for i, part := range parts { @@ -70,7 +75,7 @@ func (m CommaSpaceMapModifier) PlanModifyMap(ctx context.Context, req planmodifi resp.PlanValue = newMapValue } -// CommaSpaceMap returns a new instance of CommaSpaceMapModifier +// CommaSpaceMap returns a new instance of CommaSpaceMapModifier. func CommaSpaceMap() CommaSpaceMapModifier { return CommaSpaceMapModifier{} } diff --git a/internal/provider/resource/identity_oidc_auth.go b/internal/provider/resource/identity_oidc_auth.go index aa9686f..5cfc412 100644 --- a/internal/provider/resource/identity_oidc_auth.go +++ b/internal/provider/resource/identity_oidc_auth.go @@ -183,8 +183,9 @@ func updateOidcAuthStateByApi(ctx context.Context, diagnose diag.Diagnostics, pl useSpaces := false if !plan.BoundClaims.IsNull() { if planValue, ok := plan.BoundClaims.Elements()[key]; ok { - planStr := planValue.(types.String).ValueString() - useSpaces = strings.Contains(planStr, ", ") + if planStr, ok := planValue.(types.String); ok { + useSpaces = strings.Contains(planStr.ValueString(), ", ") + } } } From 3c8e9a95e97411a64ca82f4e7dcde77cec7a1c04 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Mon, 16 Dec 2024 15:17:26 +0100 Subject: [PATCH 4/4] Update comma_space_map_modifier.go --- .../pkg/modifiers/comma_space_map_modifier.go | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/internal/pkg/modifiers/comma_space_map_modifier.go b/internal/pkg/modifiers/comma_space_map_modifier.go index 8749d04..70f65ad 100644 --- a/internal/pkg/modifiers/comma_space_map_modifier.go +++ b/internal/pkg/modifiers/comma_space_map_modifier.go @@ -27,22 +27,33 @@ func (m CommaSpaceMapModifier) PlanModifyMap(ctx context.Context, req planmodifi planElements := req.PlanValue.Elements() newElements := make(map[string]types.String) - // Check config format if available - var configFormat bool // true = spaces, false = no spaces + // Track config format for each key + configFormats := make(map[string]bool) + + // Detect config format for each key if !req.ConfigValue.IsNull() { configElements := req.ConfigValue.Elements() - // Look at first value to determine format - for _, v := range configElements { + for key, v := range configElements { if str, ok := v.(types.String); ok && !str.IsNull() { - configFormat = strings.Contains(str.ValueString(), ", ") - break + configFormats[key] = strings.Contains(str.ValueString(), ", ") + } + } + } + + // Fallback to state value if config format not found + if !req.StateValue.IsNull() { + stateElements := req.StateValue.Elements() + for key, v := range stateElements { + if _, exists := configFormats[key]; !exists { + if str, ok := v.(types.String); ok && !str.IsNull() { + configFormats[key] = strings.Contains(str.ValueString(), ", ") + } } } } for key, value := range planElements { strValue, ok := value.(types.String) - if !ok { continue } @@ -53,8 +64,13 @@ func (m CommaSpaceMapModifier) PlanModifyMap(ctx context.Context, req planmodifi parts[i] = strings.TrimSpace(part) } + useSpaces, found := configFormats[key] + if !found { + useSpaces = false + } + var formattedValue string - if configFormat { + if useSpaces { formattedValue = strings.Join(parts, ", ") } else { formattedValue = strings.Join(parts, ",")