From f99122c839bbba7c8c643be82504f9f7162b8e36 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Fri, 28 Mar 2025 14:42:00 +0100 Subject: [PATCH] Consider and use the protection bypass for automation secret from the plan This fixes #294. Before this change, the vercel_project resource did not pass on changes to the protection_bypass_for_automation_secret attribute on to the API. This commit contains the following changes: * `client/project_protection_bypass_for_automation_update.go`: Change the anonymous struct member to accurately reflect what is marshalled * `projectResource.Create()`: always save the user-provided secret in the state, even if it is empty. This is required so that the update logic below doesn't try to reset the secret when it is generated by the vercel API. * `projectResource.Update()`: correctly handle the different update scenarios ## Limitations This change stops API-generated secrets to be returned into the state. This will break existing setups that rely on this undocumented fact. --- ...protection_bypass_for_automation_update.go | 4 +- vercel/resource_project.go | 59 ++++++++++++++++--- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/client/project_protection_bypass_for_automation_update.go b/client/project_protection_bypass_for_automation_update.go index 11647c11..1a742222 100644 --- a/client/project_protection_bypass_for_automation_update.go +++ b/client/project_protection_bypass_for_automation_update.go @@ -29,9 +29,9 @@ func getUpdateBypassProtectionRequestBody(newValue bool, secret string) string { return "{}" } return string(mustMarshal(struct { - Revoke generateBypassProtectionRequest `json:"generate"` + Generate generateBypassProtectionRequest `json:"generate"` }{ - Revoke: generateBypassProtectionRequest{ + Generate: generateBypassProtectionRequest{ Secret: secret, }, })) diff --git a/vercel/resource_project.go b/vercel/resource_project.go index d31a9bfd..72e2c633 100644 --- a/vercel/resource_project.go +++ b/vercel/resource_project.go @@ -1624,7 +1624,8 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest } if plan.ProtectionBypassForAutomation.ValueBool() { - protectionBypassSecret, err := r.client.UpdateProtectionBypassForAutomation(ctx, client.UpdateProtectionBypassForAutomationRequest{ + plannedSecret := plan.ProtectionBypassForAutomationSecret.ValueString() + _, err := r.client.UpdateProtectionBypassForAutomation(ctx, client.UpdateProtectionBypassForAutomationRequest{ ProjectID: result.ID.ValueString(), TeamID: result.TeamID.ValueString(), NewValue: true, @@ -1637,7 +1638,7 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest ) return } - result.ProtectionBypassForAutomationSecret = types.StringValue(protectionBypassSecret) + result.ProtectionBypassForAutomationSecret = types.StringValue(plannedSecret) result.ProtectionBypassForAutomation = types.BoolValue(true) diags = resp.State.Set(ctx, result) resp.Diagnostics.Append(diags...) @@ -1912,22 +1913,62 @@ func (r *projectResource) Update(ctx context.Context, req resource.UpdateRequest }) } + currentSecret := state.ProtectionBypassForAutomationSecret.ValueString() + plannedSecret := plan.ProtectionBypassForAutomationSecret.ValueString() if state.ProtectionBypassForAutomation != plan.ProtectionBypassForAutomation { - secret := state.ProtectionBypassForAutomationSecret.ValueString() - if plan.ProtectionBypassForAutomationSecret.ValueString() != "" { - secret = plan.ProtectionBypassForAutomationSecret.ValueString() + if plan.ProtectionBypassForAutomation.ValueBool() { + // protection bypass was previously not set, and now is + _, err := r.client.UpdateProtectionBypassForAutomation(ctx, client.UpdateProtectionBypassForAutomationRequest{ + ProjectID: plan.ID.ValueString(), + TeamID: plan.TeamID.ValueString(), + NewValue: true, + Secret: plannedSecret, + }) + if err != nil { + resp.Diagnostics.AddError( + "Error setting protection bypass for automation", + fmt.Sprintf( + "Could not update project %s %s, unexpected error setting Protection Bypass For Automation: %s", + state.TeamID.ValueString(), + state.ID.ValueString(), + err, + ), + ) + return + } + } else { + // protection bypass was previously set, and now is not + _, err := r.client.UpdateProtectionBypassForAutomation(ctx, client.UpdateProtectionBypassForAutomationRequest{ + ProjectID: plan.ID.ValueString(), + TeamID: plan.TeamID.ValueString(), + NewValue: false, + }) + if err != nil { + resp.Diagnostics.AddError( + "Error removing protection bypass for automation", + fmt.Sprintf( + "Could not update project %s %s, unexpected error removing Protection Bypass For Automation: %s", + state.TeamID.ValueString(), + state.ID.ValueString(), + err, + ), + ) + return + } } + } else if plan.ProtectionBypassForAutomation.ValueBool() && currentSecret != plannedSecret { + // protection bypass is already configured and the secret is different _, err := r.client.UpdateProtectionBypassForAutomation(ctx, client.UpdateProtectionBypassForAutomationRequest{ ProjectID: plan.ID.ValueString(), TeamID: plan.TeamID.ValueString(), - NewValue: plan.ProtectionBypassForAutomation.ValueBool(), - Secret: secret, + NewValue: true, + Secret: plannedSecret, }) if err != nil { resp.Diagnostics.AddError( - "Error updating project", + "Error updating protection bypass for automation", fmt.Sprintf( - "Could not update project %s %s, unexpected error setting Protection Bypass For Automation: %s", + "Could not update project %s %s, unexpected error updating Protection Bypass For Automation: %s", state.TeamID.ValueString(), state.ID.ValueString(), err,