From 889ba10f1c0a7cd3bdfd98e5f6d1babac297358b Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Tue, 21 Nov 2023 17:26:52 +0100 Subject: [PATCH 1/9] Add Trusted IPs to provider and update deployment type --- client/project_get.go | 9 +++- client/project_update.go | 39 +++++++++++----- docs/data-sources/project.md | 19 ++------ docs/resources/project.md | 23 +++++++--- vercel/data_source_project_model.go | 46 ++++++++----------- vercel/resource_project.go | 71 ++++++++++++++++++++--------- vercel/resource_project_model.go | 64 +++++++++++++++++--------- 7 files changed, 165 insertions(+), 106 deletions(-) diff --git a/client/project_get.go b/client/project_get.go index 874637cc..fbde3af6 100644 --- a/client/project_get.go +++ b/client/project_get.go @@ -58,6 +58,12 @@ type Protection struct { DeploymentType string `json:"deploymentType"` } +type TrustedIps struct { + DeploymentType string `json:"deploymentType"` + Addresses []TrustedIpAddress `json:"addresses"` + ProtectionMode string `json:"protectionMode"` +} + type ProtectionBypass struct { Scope string `json:"scope"` } @@ -92,8 +98,9 @@ type ProjectResponse struct { PublicSource *bool `json:"publicSource"` RootDirectory *string `json:"rootDirectory"` ServerlessFunctionRegion *string `json:"serverlessFunctionRegion"` - SSOProtection *Protection `json:"ssoProtection"` + VercelAuthentication *Protection `json:"ssoProtection"` PasswordProtection *Protection `json:"passwordProtection"` + TrustedIps *TrustedIps `json:"trustedIps"` ProtectionBypass map[string]ProtectionBypass `json:"protectionBypass"` } diff --git a/client/project_update.go b/client/project_update.go index 95f2e19d..1ea97a53 100644 --- a/client/project_update.go +++ b/client/project_update.go @@ -12,6 +12,20 @@ type PasswordProtectionRequest struct { Password string `json:"password"` } +type VercelAuthenticationRequest struct { + DeploymentType string `json:"deploymentType"` +} + +type TrustedIpAddress struct { + Value string `json:"value"` + Note string `json:"note"` +} +type TrustedIpsRequest struct { + DeploymentType string `json:"deploymentType"` + Addresses []TrustedIpAddress `json:"addresses"` + ProtectionMode string `json:"protectionMode"` +} + // UpdateProjectRequest defines the possible fields that can be updated within a vercel project. // note that the values are all pointers, with many containing `omitempty` for serialisation. // This is because the Vercel API behaves in the following manner: @@ -19,18 +33,19 @@ type PasswordProtectionRequest struct { // - setting the field to an empty value (e.g. "") will remove the setting for that field. // - omitting the value entirely from the request will _not_ update the field. type UpdateProjectRequest struct { - BuildCommand *string `json:"buildCommand"` - CommandForIgnoringBuildStep *string `json:"commandForIgnoringBuildStep"` - DevCommand *string `json:"devCommand"` - Framework *string `json:"framework"` - InstallCommand *string `json:"installCommand"` - Name *string `json:"name,omitempty"` - OutputDirectory *string `json:"outputDirectory"` - PublicSource *bool `json:"publicSource"` - RootDirectory *string `json:"rootDirectory"` - ServerlessFunctionRegion *string `json:"serverlessFunctionRegion"` - SSOProtection *Protection `json:"ssoProtection"` - PasswordProtection *PasswordProtectionRequest `json:"passwordProtection"` + BuildCommand *string `json:"buildCommand"` + CommandForIgnoringBuildStep *string `json:"commandForIgnoringBuildStep"` + DevCommand *string `json:"devCommand"` + Framework *string `json:"framework"` + InstallCommand *string `json:"installCommand"` + Name *string `json:"name,omitempty"` + OutputDirectory *string `json:"outputDirectory"` + PublicSource *bool `json:"publicSource"` + RootDirectory *string `json:"rootDirectory"` + ServerlessFunctionRegion *string `json:"serverlessFunctionRegion"` + VercelAuthentication *VercelAuthenticationRequest `json:"ssoProtection"` + PasswordProtection *PasswordProtectionRequest `json:"passwordProtection"` + TrustedIps *TrustedIpsRequest `json:"trustedIps"` } // UpdateProject updates an existing projects configuration within Vercel. diff --git a/docs/data-sources/project.md b/docs/data-sources/project.md index cc165bdb..9541d67f 100644 --- a/docs/data-sources/project.md +++ b/docs/data-sources/project.md @@ -38,7 +38,6 @@ output "project_id" { ### Optional -- `password_protection` (Attributes) Ensures visitors of your Preview Deployments must enter a password in order to gain access. (see [below for nested schema](#nestedatt--password_protection)) - `team_id` (String) The team ID the project exists beneath. Required when configuring a team resource if a default team has not been set in the provider. ### Read-Only @@ -55,14 +54,9 @@ output "project_id" { - `public_source` (Boolean) Specifies whether the source code and logs of the deployments for this project should be public or not. - `root_directory` (String) The name of a directory or relative path to the source code of your project. When null is used it will default to the project root. - `serverless_function_region` (String) The region on Vercel's network to which your Serverless Functions are deployed. It should be close to any data source your Serverless Function might depend on. A new Deployment is required for your changes to take effect. Please see [Vercel's documentation](https://vercel.com/docs/concepts/edge-network/regions) for a full list of regions. -- `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team. (see [below for nested schema](#nestedatt--vercel_authentication)) - - -### Nested Schema for `password_protection` - -Optional: - -- `protect_production` (Boolean) If true, production deployments will also be protected +- `password_protection` (Attributes) Ensures visitors of your Preview Deployments must enter a password in order to gain access. (see [below for nested schema](#nestedatt--password_protection)) +- `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have access to the deployment. (see [below for nested schema](#nestedatt--vercel_authentication)) +- `trusted_ips` (Attributes) Ensures only visitors from an allowed IP address can access your deployment. (see [below for nested schema](#nestedatt--trusted_ips)) @@ -87,11 +81,4 @@ Read-Only: - `type` (String) The git provider of the repository. Must be either `github`, `gitlab`, or `bitbucket`. - -### Nested Schema for `vercel_authentication` - -Read-Only: - -- `protect_production` (Boolean) If true, production deployments will also be protected - diff --git a/docs/resources/project.md b/docs/resources/project.md index 069a86cd..d5b47031 100644 --- a/docs/resources/project.md +++ b/docs/resources/project.md @@ -64,12 +64,13 @@ resource "vercel_project" "example" { - `install_command` (String) The install command for this project. If omitted, this value will be automatically detected. - `output_directory` (String) The output directory of the project. If omitted, this value will be automatically detected. - `password_protection` (Attributes) Ensures visitors of your Preview Deployments must enter a password in order to gain access. (see [below for nested schema](#nestedatt--password_protection)) +- `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team. (see [below for nested schema](#nestedatt--vercel_authentication)) +- `trusted_ips` (Attributes) Ensures only visitors from an allowed IP address can access your deployment. (see [below for nested schema](#nestedatt--trusted_ips)) - `protection_bypass_for_automation` (Boolean) Allow automation services to bypass Vercel Authentication and Password Protection for both Preview and Production Deployments on this project when using an HTTP header named `x-vercel-protection-bypass` with a value of the `password_protection_for_automation_secret` field. - `public_source` (Boolean) By default, visitors to the `/_logs` and `/_src` paths of your Production and Preview Deployments must log in with Vercel (requires being a member of your team) to see the Source, Logs and Deployment Status of your project. Setting `public_source` to `true` disables this behaviour, meaning the Source, Logs and Deployment Status can be publicly viewed. - `root_directory` (String) The name of a directory or relative path to the source code of your project. If omitted, it will default to the project root. - `serverless_function_region` (String) The region on Vercel's network to which your Serverless Functions are deployed. It should be close to any data source your Serverless Function might depend on. A new Deployment is required for your changes to take effect. Please see [Vercel's documentation](https://vercel.com/docs/concepts/edge-network/regions) for a full list of regions. - `team_id` (String) The team ID to add the project to. Required when configuring a team resource if a default team has not been set in the provider. -- `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team. (see [below for nested schema](#nestedatt--vercel_authentication)) ### Read-Only @@ -97,22 +98,32 @@ Optional: - `repo` (String) The name of the git repository. For example: `vercel/next.js`. - `type` (String) The git provider of the repository. Must be either `github`, `gitlab`, or `bitbucket`. - ### Nested Schema for `password_protection` -Optional: +Required: - `password` (String, Sensitive) The password that visitors must enter to gain access to your Preview Deployments. Drift detection is not possible for this field. -- `protect_production` (Boolean) If true, production deployments will also be protected - +- `deployment_type` (String) Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`. See [Understanding Deployment Protection by environment](https://vercel.com/docs/security/deployment-protection#understanding-deployment-protection-by-environment). ### Nested Schema for `vercel_authentication` +Required: + +- `deployment_type` (String) Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`. See [Understanding Deployment Protection by environment](https://vercel.com/docs/security/deployment-protection#understanding-deployment-protection-by-environment). + + +### Nested Schema for `trusted_ips` + +Required: + +- `addresses` (List) The allowed IP addressses and CIDR ranges with optional descriptions. +- `deployment_type` (String) Must be one one `standard_protection`, `all_deployments`, `only_production_deployments` or `only_preview_deployments`. See [Understanding Deployment Protection by environment](https://vercel.com/docs/security/deployment-protection#understanding-deployment-protection-by-environment). + Optional: -- `protect_production` (Boolean) If true, production deployments will also be protected +- `protection_mode` (String) Whether or not Trusted IPs is optional to access a deployment. Must be either `additional` or `exclusive`. `exclusive` is only availible with Standalone Trusted IPs. ## Import diff --git a/vercel/data_source_project_model.go b/vercel/data_source_project_model.go index 451807cb..66930cdf 100644 --- a/vercel/data_source_project_model.go +++ b/vercel/data_source_project_model.go @@ -7,37 +7,28 @@ import ( // Project reflects the state terraform stores internally for a project. type ProjectDataSource struct { - BuildCommand types.String `tfsdk:"build_command"` - DevCommand types.String `tfsdk:"dev_command"` - Environment types.Set `tfsdk:"environment"` - Framework types.String `tfsdk:"framework"` - GitRepository *GitRepository `tfsdk:"git_repository"` - ID types.String `tfsdk:"id"` - IgnoreCommand types.String `tfsdk:"ignore_command"` - InstallCommand types.String `tfsdk:"install_command"` - Name types.String `tfsdk:"name"` - OutputDirectory types.String `tfsdk:"output_directory"` - PublicSource types.Bool `tfsdk:"public_source"` - RootDirectory types.String `tfsdk:"root_directory"` - ServerlessFunctionRegion types.String `tfsdk:"serverless_function_region"` - TeamID types.String `tfsdk:"team_id"` - VercelAuthentication *VercelAuthentication `tfsdk:"vercel_authentication"` - PasswordProtection *PasswordProtectionDataSource `tfsdk:"password_protection"` -} - -type PasswordProtectionDataSource struct { - ProtectProduction types.Bool `tfsdk:"protect_production"` + BuildCommand types.String `tfsdk:"build_command"` + DevCommand types.String `tfsdk:"dev_command"` + Environment types.Set `tfsdk:"environment"` + Framework types.String `tfsdk:"framework"` + GitRepository *GitRepository `tfsdk:"git_repository"` + ID types.String `tfsdk:"id"` + IgnoreCommand types.String `tfsdk:"ignore_command"` + InstallCommand types.String `tfsdk:"install_command"` + Name types.String `tfsdk:"name"` + OutputDirectory types.String `tfsdk:"output_directory"` + PublicSource types.Bool `tfsdk:"public_source"` + RootDirectory types.String `tfsdk:"root_directory"` + ServerlessFunctionRegion types.String `tfsdk:"serverless_function_region"` + TeamID types.String `tfsdk:"team_id"` + VercelAuthentication *VercelAuthentication `tfsdk:"vercel_authentication"` + PasswordProtection *PasswordProtection `tfsdk:"password_protection"` + TrustedIps *TrustedIps `tfsdk:"trusted_ips"` } func convertResponseToProjectDataSource(response client.ProjectResponse, plan Project) ProjectDataSource { project := convertResponseToProject(response, plan) - var pp *PasswordProtectionDataSource - if project.PasswordProtection != nil { - pp = &PasswordProtectionDataSource{ - ProtectProduction: project.PasswordProtection.ProtectProduction, - } - } return ProjectDataSource{ BuildCommand: project.BuildCommand, DevCommand: project.DevCommand, @@ -54,6 +45,7 @@ func convertResponseToProjectDataSource(response client.ProjectResponse, plan Pr ServerlessFunctionRegion: project.ServerlessFunctionRegion, TeamID: project.TeamID, VercelAuthentication: project.VercelAuthentication, - PasswordProtection: pp, + PasswordProtection: project.PasswordProtection, + TrustedIps: project.TrustedIps, } } diff --git a/vercel/resource_project.go b/vercel/resource_project.go index 2dc4d810..df179fd3 100644 --- a/vercel/resource_project.go +++ b/vercel/resource_project.go @@ -9,10 +9,9 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -176,21 +175,14 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ "vercel_authentication": schema.SingleNestedAttribute{ Description: "Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team.", Optional: true, - Computed: true, - Default: objectdefault.StaticValue(types.ObjectValueMust( - map[string]attr.Type{ - "protect_production": types.BoolType, - }, - map[string]attr.Value{ - "protect_production": types.BoolValue(false), - }, - )), Attributes: map[string]schema.Attribute{ - "protect_production": schema.BoolAttribute{ - Description: "If true, production deployments will also be protected", - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), + "deployment_type": schema.StringAttribute{ + Required: true, + Description: "The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`.", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + Validators: []validator.String{ + stringOneOf("standard_protection", "all_deployments", "only_preview_deployments"), + }, }, }, }, @@ -206,11 +198,46 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ stringLengthBetween(1, 72), }, }, - "protect_production": schema.BoolAttribute{ - Description: "If true, production deployments will also be protected", - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), + "deployment_type": schema.StringAttribute{ + Required: true, + Description: "The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`.", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + Validators: []validator.String{ + stringOneOf("standard_protection", "all_deployments", "only_preview_deployments"), + }, + }, + }, + }, + "trusted_ips": schema.SingleNestedAttribute{ + Description: "Ensures only visitors from an allowed IP address can access your deployment.", + Optional: true, + Attributes: map[string]schema.Attribute{ + "addresses": schema.SetAttribute{ + Description: "The allowed IP addressses and CIDR ranges with optional descriptions.", + Required: true, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "value": types.StringType, + "note": types.StringType, + }, + }, + }, + "deployment_type": schema.StringAttribute{ + Required: true, + Description: "The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, `only_production_deployments`, or `only_preview_deployments`.", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + Validators: []validator.String{ + stringOneOf("standard_protection", "all_deployments", "only_production_deployments", "only_preview_deployments"), + }, + }, + "protection_mode": schema.StringAttribute{ + Optional: true, + Description: "Whether or not Trusted IPs is optional to access a deployment. Must be either `additional` or `exclusive`. `exclusive` is only availible with Standalone Trusted IPs.", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + Validators: []validator.String{ + stringOneOf("additional", "exclusive"), + }, + Default: stringdefault.StaticString("additional"), }, }, }, @@ -285,7 +312,7 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest return } - if plan.PasswordProtection != nil || plan.VercelAuthentication != nil { + if plan.PasswordProtection != nil || plan.VercelAuthentication != nil || plan.TrustedIps != nil { out, err = r.client.UpdateProject(ctx, result.ID.ValueString(), plan.TeamID.ValueString(), plan.toUpdateProjectRequest(plan.Name.ValueString()), !plan.Environment.IsNull()) if err != nil { resp.Diagnostics.AddError( diff --git a/vercel/resource_project_model.go b/vercel/resource_project_model.go index 911cd31c..df5461c2 100644 --- a/vercel/resource_project_model.go +++ b/vercel/resource_project_model.go @@ -27,6 +27,7 @@ type Project struct { TeamID types.String `tfsdk:"team_id"` VercelAuthentication *VercelAuthentication `tfsdk:"vercel_authentication"` PasswordProtection *PasswordProtection `tfsdk:"password_protection"` + TrustedIps *TrustedIps `tfsdk:"trusted_ips"` ProtectionBypassForAutomation types.Bool `tfsdk:"protection_bypass_for_automation"` ProtectionBypassForAutomationSecret types.String `tfsdk:"protection_bypass_for_automation_secret"` } @@ -109,7 +110,8 @@ func (p *Project) toUpdateProjectRequest(oldName string) client.UpdateProjectReq RootDirectory: toStrPointer(p.RootDirectory), ServerlessFunctionRegion: toStrPointer(p.ServerlessFunctionRegion), PasswordProtection: p.PasswordProtection.toUpdateProjectRequest(), - SSOProtection: p.VercelAuthentication.toUpdateProjectRequest(), + VercelAuthentication: p.VercelAuthentication.toUpdateProjectRequest(), + TrustedIps: p.TrustedIps.toUpdateProjectRequest(), } } @@ -154,27 +156,22 @@ func (g *GitRepository) toCreateProjectRequest() *client.GitRepository { } type VercelAuthentication struct { - ProtectProduction types.Bool `tfsdk:"protect_production"` + DeploymentType types.String `tfsdk:"deployment_type"` } -func (v *VercelAuthentication) toUpdateProjectRequest() *client.Protection { +func (v *VercelAuthentication) toUpdateProjectRequest() *client.VercelAuthenticationRequest { if v == nil { return nil } - deploymentType := "preview" - if v.ProtectProduction.ValueBool() { - deploymentType = "all" - } - - return &client.Protection{ - DeploymentType: deploymentType, + return &client.VercelAuthenticationRequest{ + DeploymentType: v.DeploymentType.ValueString(), } } type PasswordProtection struct { - Password types.String `tfsdk:"password"` - ProtectProduction types.Bool `tfsdk:"protect_production"` + Password types.String `tfsdk:"password"` + DeploymentType types.String `tfsdk:"deployment_type"` } func (p *PasswordProtection) toUpdateProjectRequest() *client.PasswordProtectionRequest { @@ -182,17 +179,30 @@ func (p *PasswordProtection) toUpdateProjectRequest() *client.PasswordProtection return nil } - deploymentType := "preview" - if p.ProtectProduction.ValueBool() { - deploymentType = "all" - } - return &client.PasswordProtectionRequest{ - DeploymentType: deploymentType, + DeploymentType: p.DeploymentType.ValueString(), Password: p.Password.ValueString(), } } +type TrustedIps struct { + Addresses []client.TrustedIpAddress `tfsdk:"addresses"` + DeploymentType types.String `tfsdk:"deployment_type"` + ProtectionMode types.String `tfsdk:"protection_mode"` +} + +func (t *TrustedIps) toUpdateProjectRequest() *client.TrustedIpsRequest { + if t == nil { + return nil + } + + return &client.TrustedIpsRequest{ + Addresses: t.Addresses, + DeploymentType: t.DeploymentType.ValueString(), + ProtectionMode: t.ProtectionMode.ValueString(), + } +} + /* * In the Vercel API the following fields are coerced to null during project creation @@ -273,15 +283,24 @@ func convertResponseToProject(response client.ProjectResponse, plan Project) Pro pass = plan.PasswordProtection.Password } pp = &PasswordProtection{ - Password: pass, - ProtectProduction: types.BoolValue(response.PasswordProtection.DeploymentType == "all"), + Password: pass, + DeploymentType: types.StringValue(response.PasswordProtection.DeploymentType), } } var va *VercelAuthentication - if response.SSOProtection != nil { + if response.VercelAuthentication != nil { va = &VercelAuthentication{ - ProtectProduction: types.BoolValue(response.SSOProtection.DeploymentType == "all"), + DeploymentType: types.StringValue(response.VercelAuthentication.DeploymentType), + } + } + + var tip *TrustedIps + if response.TrustedIps != nil { + tip = &TrustedIps{ + DeploymentType: types.StringValue(response.TrustedIps.DeploymentType), + Addresses: response.TrustedIps.Addresses, + ProtectionMode: types.StringValue(response.TrustedIps.ProtectionMode), } } @@ -346,6 +365,7 @@ func convertResponseToProject(response client.ProjectResponse, plan Project) Pro TeamID: toTeamID(response.TeamID), PasswordProtection: pp, VercelAuthentication: va, + TrustedIps: tip, ProtectionBypassForAutomation: protectionBypass, ProtectionBypassForAutomationSecret: protectionBypassSecret, } From 69ab1f02f6c6c94898708d34d24db0e69f6fd8f5 Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Tue, 21 Nov 2023 17:48:51 +0100 Subject: [PATCH 2/9] remove trusted ips default --- vercel/resource_project.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/vercel/resource_project.go b/vercel/resource_project.go index df179fd3..f49f12ef 100644 --- a/vercel/resource_project.go +++ b/vercel/resource_project.go @@ -11,7 +11,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -237,7 +236,6 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ Validators: []validator.String{ stringOneOf("additional", "exclusive"), }, - Default: stringdefault.StaticString("additional"), }, }, }, From 242b772ba203e9689cb55d4f12e659794fbf1ca9 Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Wed, 22 Nov 2023 11:12:02 +0100 Subject: [PATCH 3/9] tfplugindocs --- docs/data-sources/project.md | 37 ++++++++++++++++++++-- docs/resources/project.md | 53 ++++++++++++++++++++++---------- vercel/data_source_project.go | 33 +++++++++++++++++--- vercel/resource_project.go | 6 ++-- vercel/resource_project_model.go | 39 ++++++++++++++++++++--- 5 files changed, 138 insertions(+), 30 deletions(-) diff --git a/docs/data-sources/project.md b/docs/data-sources/project.md index 9541d67f..db87ae70 100644 --- a/docs/data-sources/project.md +++ b/docs/data-sources/project.md @@ -38,7 +38,9 @@ output "project_id" { ### Optional +- `password_protection` (Attributes) Ensures visitors of your Preview Deployments must enter a password in order to gain access. (see [below for nested schema](#nestedatt--password_protection)) - `team_id` (String) The team ID the project exists beneath. Required when configuring a team resource if a default team has not been set in the provider. +- `trusted_ips` (Attributes) Ensures only visitors from an allowed IP address can access your deployment. (see [below for nested schema](#nestedatt--trusted_ips)) ### Read-Only @@ -54,9 +56,33 @@ output "project_id" { - `public_source` (Boolean) Specifies whether the source code and logs of the deployments for this project should be public or not. - `root_directory` (String) The name of a directory or relative path to the source code of your project. When null is used it will default to the project root. - `serverless_function_region` (String) The region on Vercel's network to which your Serverless Functions are deployed. It should be close to any data source your Serverless Function might depend on. A new Deployment is required for your changes to take effect. Please see [Vercel's documentation](https://vercel.com/docs/concepts/edge-network/regions) for a full list of regions. -- `password_protection` (Attributes) Ensures visitors of your Preview Deployments must enter a password in order to gain access. (see [below for nested schema](#nestedatt--password_protection)) -- `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have access to the deployment. (see [below for nested schema](#nestedatt--vercel_authentication)) -- `trusted_ips` (Attributes) Ensures only visitors from an allowed IP address can access your deployment. (see [below for nested schema](#nestedatt--trusted_ips)) +- `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team. (see [below for nested schema](#nestedatt--vercel_authentication)) + + +### Nested Schema for `password_protection` + +Read-Only: + +- `deployment_type` (String) The deployment environment that will be protected. + + + +### Nested Schema for `trusted_ips` + +Read-Only: + +- `addresses` (List of Object) The allowed IP addressses and CIDR ranges with optional descriptions. (see [below for nested schema](#nestedatt--trusted_ips--addresses)) +- `deployment_type` (String) The deployment environment that will be protected. +- `protection_mode` (String) Whether or not Trusted IPs is optional to access a deployment. + + +### Nested Schema for `trusted_ips.addresses` + +Optional: + +- `note` (String) +- `value` (String) + @@ -81,4 +107,9 @@ Read-Only: - `type` (String) The git provider of the repository. Must be either `github`, `gitlab`, or `bitbucket`. + +### Nested Schema for `vercel_authentication` + +Read-Only: +- `deployment_type` (String) The deployment environment that will be protected. diff --git a/docs/resources/project.md b/docs/resources/project.md index d5b47031..35c95728 100644 --- a/docs/resources/project.md +++ b/docs/resources/project.md @@ -64,13 +64,13 @@ resource "vercel_project" "example" { - `install_command` (String) The install command for this project. If omitted, this value will be automatically detected. - `output_directory` (String) The output directory of the project. If omitted, this value will be automatically detected. - `password_protection` (Attributes) Ensures visitors of your Preview Deployments must enter a password in order to gain access. (see [below for nested schema](#nestedatt--password_protection)) -- `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team. (see [below for nested schema](#nestedatt--vercel_authentication)) -- `trusted_ips` (Attributes) Ensures only visitors from an allowed IP address can access your deployment. (see [below for nested schema](#nestedatt--trusted_ips)) - `protection_bypass_for_automation` (Boolean) Allow automation services to bypass Vercel Authentication and Password Protection for both Preview and Production Deployments on this project when using an HTTP header named `x-vercel-protection-bypass` with a value of the `password_protection_for_automation_secret` field. - `public_source` (Boolean) By default, visitors to the `/_logs` and `/_src` paths of your Production and Preview Deployments must log in with Vercel (requires being a member of your team) to see the Source, Logs and Deployment Status of your project. Setting `public_source` to `true` disables this behaviour, meaning the Source, Logs and Deployment Status can be publicly viewed. - `root_directory` (String) The name of a directory or relative path to the source code of your project. If omitted, it will default to the project root. - `serverless_function_region` (String) The region on Vercel's network to which your Serverless Functions are deployed. It should be close to any data source your Serverless Function might depend on. A new Deployment is required for your changes to take effect. Please see [Vercel's documentation](https://vercel.com/docs/concepts/edge-network/regions) for a full list of regions. - `team_id` (String) The team ID to add the project to. Required when configuring a team resource if a default team has not been set in the provider. +- `trusted_ips` (Attributes) Ensures only visitors from an allowed IP address can access your deployment. (see [below for nested schema](#nestedatt--trusted_ips)) +- `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team. (see [below for nested schema](#nestedatt--vercel_authentication)) ### Read-Only @@ -80,51 +80,72 @@ resource "vercel_project" "example" { ### Nested Schema for `environment` -Optional: +Required: -- `git_branch` (String) The git branch of the Environment Variable. -- `id` (String) The ID of the Environment Variable. - `key` (String) The name of the Environment Variable. - `target` (Set of String) The environments that the Environment Variable should be present on. Valid targets are either `production`, `preview`, or `development`. - `value` (String, Sensitive) The value of the Environment Variable. +Optional: + +- `git_branch` (String) The git branch of the Environment Variable. + +Read-Only: + +- `id` (String) The ID of the Environment Variable. + ### Nested Schema for `git_repository` -Optional: +Required: -- `production_branch` (String) By default, every commit pushed to the main branch will trigger a Production Deployment instead of the usual Preview Deployment. You can switch to a different branch here. - `repo` (String) The name of the git repository. For example: `vercel/next.js`. - `type` (String) The git provider of the repository. Must be either `github`, `gitlab`, or `bitbucket`. +Optional: + +- `production_branch` (String) By default, every commit pushed to the main branch will trigger a Production Deployment instead of the usual Preview Deployment. You can switch to a different branch here. + + ### Nested Schema for `password_protection` Required: +- `deployment_type` (String) The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`. - `password` (String, Sensitive) The password that visitors must enter to gain access to your Preview Deployments. Drift detection is not possible for this field. -- `deployment_type` (String) Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`. See [Understanding Deployment Protection by environment](https://vercel.com/docs/security/deployment-protection#understanding-deployment-protection-by-environment). - - -### Nested Schema for `vercel_authentication` - -Required: -- `deployment_type` (String) Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`. See [Understanding Deployment Protection by environment](https://vercel.com/docs/security/deployment-protection#understanding-deployment-protection-by-environment). ### Nested Schema for `trusted_ips` Required: -- `addresses` (List) The allowed IP addressses and CIDR ranges with optional descriptions. -- `deployment_type` (String) Must be one one `standard_protection`, `all_deployments`, `only_production_deployments` or `only_preview_deployments`. See [Understanding Deployment Protection by environment](https://vercel.com/docs/security/deployment-protection#understanding-deployment-protection-by-environment). +- `addresses` (Set of Object) The allowed IP addressses and CIDR ranges with optional descriptions. (see [below for nested schema](#nestedatt--trusted_ips--addresses)) +- `deployment_type` (String) The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, `only_production_deployments`, or `only_preview_deployments`. Optional: - `protection_mode` (String) Whether or not Trusted IPs is optional to access a deployment. Must be either `additional` or `exclusive`. `exclusive` is only availible with Standalone Trusted IPs. + +### Nested Schema for `trusted_ips.addresses` + +Optional: + +- `note` (String) +- `value` (String) + + + + +### Nested Schema for `vercel_authentication` + +Required: + +- `deployment_type` (String) The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`. + ## Import Import is supported using the following syntax: diff --git a/vercel/data_source_project.go b/vercel/data_source_project.go index 2c6bb7b4..a3037dfe 100644 --- a/vercel/data_source_project.go +++ b/vercel/data_source_project.go @@ -5,6 +5,7 @@ import ( "fmt" "regexp" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/schema/validator" @@ -149,8 +150,8 @@ For more detailed information, please see the [Vercel documentation](https://ver Description: "Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team.", Computed: true, Attributes: map[string]schema.Attribute{ - "protect_production": schema.BoolAttribute{ - Description: "If true, production deployments will also be protected", + "deployment_type": schema.StringAttribute{ + Description: "The deployment environment that will be protected.", Computed: true, }, }, @@ -159,8 +160,32 @@ For more detailed information, please see the [Vercel documentation](https://ver Description: "Ensures visitors of your Preview Deployments must enter a password in order to gain access.", Optional: true, Attributes: map[string]schema.Attribute{ - "protect_production": schema.BoolAttribute{ - Description: "If true, production deployments will also be protected", + "deployment_type": schema.StringAttribute{ + Description: "The deployment environment that will be protected.", + Computed: true, + }, + }, + }, + "trusted_ips": schema.SingleNestedAttribute{ + Description: "Ensures only visitors from an allowed IP address can access your deployment.", + Optional: true, + Attributes: map[string]schema.Attribute{ + "deployment_type": schema.StringAttribute{ + Description: "The deployment environment that will be protected.", + Computed: true, + }, + "addresses": schema.ListAttribute{ + Description: "The allowed IP addressses and CIDR ranges with optional descriptions.", + Computed: true, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "value": types.StringType, + "note": types.StringType, + }, + }, + }, + "protection_mode": schema.StringAttribute{ + Description: "Whether or not Trusted IPs is optional to access a deployment.", Computed: true, }, }, diff --git a/vercel/resource_project.go b/vercel/resource_project.go index f49f12ef..40df97d0 100644 --- a/vercel/resource_project.go +++ b/vercel/resource_project.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -212,8 +213,9 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ Optional: true, Attributes: map[string]schema.Attribute{ "addresses": schema.SetAttribute{ - Description: "The allowed IP addressses and CIDR ranges with optional descriptions.", - Required: true, + Description: "The allowed IP addressses and CIDR ranges with optional descriptions.", + Required: true, + PlanModifiers: []planmodifier.Set{setplanmodifier.UseStateForUnknown()}, ElementType: types.ObjectType{ AttrTypes: map[string]attr.Type{ "value": types.StringType, diff --git a/vercel/resource_project_model.go b/vercel/resource_project_model.go index df5461c2..0a611b62 100644 --- a/vercel/resource_project_model.go +++ b/vercel/resource_project_model.go @@ -185,10 +185,15 @@ func (p *PasswordProtection) toUpdateProjectRequest() *client.PasswordProtection } } +type TrustedIpsAddress struct { + Value types.String `tfsdk:"value"` + Note types.String `tfsdk:"note"` +} + type TrustedIps struct { - Addresses []client.TrustedIpAddress `tfsdk:"addresses"` - DeploymentType types.String `tfsdk:"deployment_type"` - ProtectionMode types.String `tfsdk:"protection_mode"` + Addresses []TrustedIpsAddress `tfsdk:"addresses"` + DeploymentType types.String `tfsdk:"deployment_type"` + ProtectionMode types.String `tfsdk:"protection_mode"` } func (t *TrustedIps) toUpdateProjectRequest() *client.TrustedIpsRequest { @@ -196,8 +201,16 @@ func (t *TrustedIps) toUpdateProjectRequest() *client.TrustedIpsRequest { return nil } + var addresses = []client.TrustedIpAddress{} + for _, address := range t.Addresses { + addresses = append(addresses, client.TrustedIpAddress{ + Value: address.Value.ValueString(), + Note: address.Note.ValueString(), + }) + } + return &client.TrustedIpsRequest{ - Addresses: t.Addresses, + Addresses: addresses, DeploymentType: t.DeploymentType.ValueString(), ProtectionMode: t.ProtectionMode.ValueString(), } @@ -261,6 +274,15 @@ var envVariableElemType = types.ObjectType{ }, } +var trustedIpsAddressesVariableElemType = types.SetType{ + ElemType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "value": types.StringType, + "note": types.StringType, + }, + }, +} + func convertResponseToProject(response client.ProjectResponse, plan Project) Project { fields := plan.coercedFields() @@ -297,9 +319,16 @@ func convertResponseToProject(response client.ProjectResponse, plan Project) Pro var tip *TrustedIps if response.TrustedIps != nil { + var addresses []TrustedIpsAddress + for _, address := range response.TrustedIps.Addresses { + addresses = append(addresses, TrustedIpsAddress{ + Value: types.StringValue(address.Value), + Note: types.StringValue(address.Note), + }) + } tip = &TrustedIps{ DeploymentType: types.StringValue(response.TrustedIps.DeploymentType), - Addresses: response.TrustedIps.Addresses, + Addresses: addresses, ProtectionMode: types.StringValue(response.TrustedIps.ProtectionMode), } } From 09868bce03adb790833a0ccf452f89ebc6c030ad Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Wed, 22 Nov 2023 11:14:01 +0100 Subject: [PATCH 4/9] lint --- vercel/resource_project_model.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/vercel/resource_project_model.go b/vercel/resource_project_model.go index 0a611b62..eddfde7f 100644 --- a/vercel/resource_project_model.go +++ b/vercel/resource_project_model.go @@ -274,15 +274,6 @@ var envVariableElemType = types.ObjectType{ }, } -var trustedIpsAddressesVariableElemType = types.SetType{ - ElemType: types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "value": types.StringType, - "note": types.StringType, - }, - }, -} - func convertResponseToProject(response client.ProjectResponse, plan Project) Project { fields := plan.coercedFields() From a9112ea8d4824a08a2b6f714d8de4ab9a061ff0b Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Wed, 22 Nov 2023 11:21:50 +0100 Subject: [PATCH 5/9] docs --- docs/data-sources/project.md | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/data-sources/project.md b/docs/data-sources/project.md index db87ae70..aa985312 100644 --- a/docs/data-sources/project.md +++ b/docs/data-sources/project.md @@ -38,9 +38,7 @@ output "project_id" { ### Optional -- `password_protection` (Attributes) Ensures visitors of your Preview Deployments must enter a password in order to gain access. (see [below for nested schema](#nestedatt--password_protection)) - `team_id` (String) The team ID the project exists beneath. Required when configuring a team resource if a default team has not been set in the provider. -- `trusted_ips` (Attributes) Ensures only visitors from an allowed IP address can access your deployment. (see [below for nested schema](#nestedatt--trusted_ips)) ### Read-Only @@ -53,11 +51,35 @@ output "project_id" { - `ignore_command` (String) When a commit is pushed to the Git repository that is connected with your Project, its SHA will determine if a new Build has to be issued. If the SHA was deployed before, no new Build will be issued. You can customize this behavior with a command that exits with code 1 (new Build needed) or code 0. - `install_command` (String) The install command for this project. If omitted, this value will be automatically detected. - `output_directory` (String) The output directory of the project. When null is used this value will be automatically detected. +- `password_protection` (Attributes) Ensures visitors of your Preview Deployments must enter a password in order to gain access. (see [below for nested schema](#nestedatt--password_protection)) - `public_source` (Boolean) Specifies whether the source code and logs of the deployments for this project should be public or not. - `root_directory` (String) The name of a directory or relative path to the source code of your project. When null is used it will default to the project root. - `serverless_function_region` (String) The region on Vercel's network to which your Serverless Functions are deployed. It should be close to any data source your Serverless Function might depend on. A new Deployment is required for your changes to take effect. Please see [Vercel's documentation](https://vercel.com/docs/concepts/edge-network/regions) for a full list of regions. +- `trusted_ips` (Attributes) Ensures only visitors from an allowed IP address can access your deployment. (see [below for nested schema](#nestedatt--trusted_ips)) - `vercel_authentication` (Attributes) Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team. (see [below for nested schema](#nestedatt--vercel_authentication)) + +### Nested Schema for `environment` + +Read-Only: + +- `git_branch` (String) The git branch of the environment variable. +- `id` (String) The ID of the environment variable +- `key` (String) The name of the environment variable. +- `target` (Set of String) The environments that the environment variable should be present on. Valid targets are either `production`, `preview`, or `development`. +- `value` (String) The value of the environment variable. + + + +### Nested Schema for `git_repository` + +Read-Only: + +- `production_branch` (String) By default, every commit pushed to the main branch will trigger a Production Deployment instead of the usual Preview Deployment. You can switch to a different branch here. +- `repo` (String) The name of the git repository. For example: `vercel/next.js`. +- `type` (String) The git provider of the repository. Must be either `github`, `gitlab`, or `bitbucket`. + + ### Nested Schema for `password_protection` @@ -78,35 +100,13 @@ Read-Only: ### Nested Schema for `trusted_ips.addresses` -Optional: +Read-Only: - `note` (String) - `value` (String) - -### Nested Schema for `environment` - -Read-Only: - -- `git_branch` (String) The git branch of the environment variable. -- `id` (String) The ID of the environment variable -- `key` (String) The name of the environment variable. -- `target` (Set of String) The environments that the environment variable should be present on. Valid targets are either `production`, `preview`, or `development`. -- `value` (String) The value of the environment variable. - - - -### Nested Schema for `git_repository` - -Read-Only: - -- `production_branch` (String) By default, every commit pushed to the main branch will trigger a Production Deployment instead of the usual Preview Deployment. You can switch to a different branch here. -- `repo` (String) The name of the git repository. For example: `vercel/next.js`. -- `type` (String) The git provider of the repository. Must be either `github`, `gitlab`, or `bitbucket`. - - ### Nested Schema for `vercel_authentication` From f850faa24c9782e8ee5af4c15645ddd9ac50a395 Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Wed, 22 Nov 2023 11:23:19 +0100 Subject: [PATCH 6/9] make vercel auth optional --- .github/workflows/test.yml | 21 +++- README.md | 18 ++++ Taskfile.yml | 2 +- client/deployment_protection.go | 28 +++++ client/must_marshal.go | 16 ++- client/project_get.go | 18 +--- client/project_update.go | 45 +++----- docs/data-sources/alias.md | 2 - docs/data-sources/file.md | 2 - docs/data-sources/prebuilt_project.md | 2 - docs/data-sources/project_directory.md | 2 - docs/resources/alias.md | 2 - docs/resources/deployment.md | 2 - docs/resources/dns_record.md | 2 +- docs/resources/project.md | 17 +-- vercel/data_source_project.go | 4 +- vercel/data_source_project_model.go | 8 +- vercel/data_source_project_test.go | 26 ++++- vercel/deployment_protection.go | 30 ++++++ vercel/resource_project.go | 47 ++++++--- vercel/resource_project_model.go | 138 +++++++++++++++---------- vercel/resource_project_test.go | 118 ++++++++++++++++----- 22 files changed, 383 insertions(+), 167 deletions(-) create mode 100644 client/deployment_protection.go create mode 100644 vercel/deployment_protection.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ceb80fb5..7b66e9fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,6 +39,23 @@ jobs: run: task build - name: Format run: task lint + + docs: + name: Docs Test + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: "1.20" + id: go + - name: Install Task + uses: arduino/setup-task@v1 + with: + version: "3.x" + - name: Check out code into the Go module directory + uses: actions/checkout@v2 - name: Check if docs are up-to-date run: | task docs @@ -48,7 +65,7 @@ jobs: test: name: Matrix Test - needs: [ build ] + needs: [build] timeout-minutes: 15 strategy: max-parallel: 1 @@ -80,7 +97,7 @@ jobs: env: TF_ACC: "true" VERCEL_API_TOKEN: ${{ secrets.VERCEL_API_TOKEN }} - VERCEL_TERRAFORM_TESTING_TEAM: "team_Q8MH2GVRnqKLtxicP2HWPgLi" + VERCEL_TERRAFORM_TESTING_TEAM: "team_RvxIb1z0pi9RSsQ13p3ES4cK" VERCEL_TERRAFORM_TESTING_GITHUB_REPO: "dglsparsons/test" VERCEL_TERRAFORM_TESTING_GITLAB_REPO: "dglsparsons/test" VERCEL_TERRAFORM_TESTING_BITBUCKET_REPO: "dglsparsons-test/test" diff --git a/README.md b/README.md index 545c2633..d7fe7bfe 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ The acceptance tests require a few environment variables to be set: * `VERCEL_TERRAFORM_TESTING_TEAM` - a Vercel team_id where resources can be created and destroyed * `VERCEL_TERRAFORM_TESTING_GITHUB_REPO` - a GitHub repository in the form 'org/repo' that can be used to trigger deployments * `VERCEL_TERRAFORM_TESTING_BITBUCKET_REPO` - a Bitbucket repository in the form 'project/repo' that can be used to trigger deployments +* `VERCEL_TERRAFORM_TESTING_GITLAB_REPO` - a GitLab repository in the form 'project/repo' that can be used to trigger deployments +* `VERCEL_TERRAFORM_TESTING_DOMAIN` - a Vercel testing domain that can be used for testing ```sh $ task test @@ -59,6 +61,22 @@ To run a specific set of tests, use the `-run` flag and specify a regex pattern $ task test -- -run 'TestAcc_Project*' ``` +## Running the provider locally + +Set up a local override on your machine + +```sh +$ task install +``` + +Build the provider + +```sh +$ task build +``` + +Create a `main.tf` file on your machine and use the [terraform cli](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli#install-terraform) to test + ## Building The Documentation The documentation is autogenerated from Description fields within the provider, and the `examples` directory. diff --git a/Taskfile.yml b/Taskfile.yml index 076a96b9..a46cb24c 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -23,7 +23,7 @@ tasks: install-tfplugindocs: desc: "Install the tfplugindocs tool" cmds: - - go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@v0.7.0 + - go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@v0.16.0 status: - which tfplugindocs diff --git a/client/deployment_protection.go b/client/deployment_protection.go new file mode 100644 index 00000000..eba07053 --- /dev/null +++ b/client/deployment_protection.go @@ -0,0 +1,28 @@ +package client + +type VercelAuthentication struct { + DeploymentType string `json:"deploymentType"` +} + +type PasswordProtection struct { + DeploymentType string `json:"deploymentType"` +} +type PasswordProtectionWithPassword struct { + DeploymentType string `json:"deploymentType"` + Password string `json:"password"` +} + +type TrustedIpAddress struct { + Value string `json:"value"` + Note string `json:"note"` +} + +type TrustedIps struct { + DeploymentType string `json:"deploymentType"` + Addresses []TrustedIpAddress `json:"addresses"` + ProtectionMode string `json:"protectionMode"` +} + +type ProtectionBypass struct { + Scope string `json:"scope"` +} diff --git a/client/must_marshal.go b/client/must_marshal.go index 27f85dec..d4989fd5 100644 --- a/client/must_marshal.go +++ b/client/must_marshal.go @@ -1,6 +1,20 @@ package client -import "encoding/json" +import ( + "encoding/json" +) + +func (v *VercelAuthentication) MarshalJSON() ([]byte, error) { + if v.DeploymentType == "none" { + return []byte(`null`), nil + } + + return json.Marshal(&struct { + DeploymentType string `json:"deploymentType"` + }{ + DeploymentType: v.DeploymentType, + }) +} // mustMarshal is a helper to remove unnecessary error checking when marshaling a Go // struct to json. There are only a few instances where marshaling can fail, and they diff --git a/client/project_get.go b/client/project_get.go index fbde3af6..b82c69c5 100644 --- a/client/project_get.go +++ b/client/project_get.go @@ -54,20 +54,6 @@ func (r *ProjectResponse) Repository() *Repository { return nil } -type Protection struct { - DeploymentType string `json:"deploymentType"` -} - -type TrustedIps struct { - DeploymentType string `json:"deploymentType"` - Addresses []TrustedIpAddress `json:"addresses"` - ProtectionMode string `json:"protectionMode"` -} - -type ProtectionBypass struct { - Scope string `json:"scope"` -} - // ProjectResponse defines the information Vercel returns about a project. type ProjectResponse struct { BuildCommand *string `json:"buildCommand"` @@ -98,8 +84,8 @@ type ProjectResponse struct { PublicSource *bool `json:"publicSource"` RootDirectory *string `json:"rootDirectory"` ServerlessFunctionRegion *string `json:"serverlessFunctionRegion"` - VercelAuthentication *Protection `json:"ssoProtection"` - PasswordProtection *Protection `json:"passwordProtection"` + VercelAuthentication *VercelAuthentication `json:"ssoProtection"` + PasswordProtection *PasswordProtection `json:"passwordProtection"` TrustedIps *TrustedIps `json:"trustedIps"` ProtectionBypass map[string]ProtectionBypass `json:"protectionBypass"` } diff --git a/client/project_update.go b/client/project_update.go index 1ea97a53..b77a43dd 100644 --- a/client/project_update.go +++ b/client/project_update.go @@ -7,25 +7,6 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" ) -type PasswordProtectionRequest struct { - DeploymentType string `json:"deploymentType"` - Password string `json:"password"` -} - -type VercelAuthenticationRequest struct { - DeploymentType string `json:"deploymentType"` -} - -type TrustedIpAddress struct { - Value string `json:"value"` - Note string `json:"note"` -} -type TrustedIpsRequest struct { - DeploymentType string `json:"deploymentType"` - Addresses []TrustedIpAddress `json:"addresses"` - ProtectionMode string `json:"protectionMode"` -} - // UpdateProjectRequest defines the possible fields that can be updated within a vercel project. // note that the values are all pointers, with many containing `omitempty` for serialisation. // This is because the Vercel API behaves in the following manner: @@ -33,19 +14,19 @@ type TrustedIpsRequest struct { // - setting the field to an empty value (e.g. "") will remove the setting for that field. // - omitting the value entirely from the request will _not_ update the field. type UpdateProjectRequest struct { - BuildCommand *string `json:"buildCommand"` - CommandForIgnoringBuildStep *string `json:"commandForIgnoringBuildStep"` - DevCommand *string `json:"devCommand"` - Framework *string `json:"framework"` - InstallCommand *string `json:"installCommand"` - Name *string `json:"name,omitempty"` - OutputDirectory *string `json:"outputDirectory"` - PublicSource *bool `json:"publicSource"` - RootDirectory *string `json:"rootDirectory"` - ServerlessFunctionRegion *string `json:"serverlessFunctionRegion"` - VercelAuthentication *VercelAuthenticationRequest `json:"ssoProtection"` - PasswordProtection *PasswordProtectionRequest `json:"passwordProtection"` - TrustedIps *TrustedIpsRequest `json:"trustedIps"` + BuildCommand *string `json:"buildCommand"` + CommandForIgnoringBuildStep *string `json:"commandForIgnoringBuildStep"` + DevCommand *string `json:"devCommand"` + Framework *string `json:"framework"` + InstallCommand *string `json:"installCommand"` + Name *string `json:"name,omitempty"` + OutputDirectory *string `json:"outputDirectory"` + PublicSource *bool `json:"publicSource"` + RootDirectory *string `json:"rootDirectory"` + ServerlessFunctionRegion *string `json:"serverlessFunctionRegion"` + VercelAuthentication *VercelAuthentication `json:"ssoProtection"` + PasswordProtection *PasswordProtectionWithPassword `json:"passwordProtection"` + TrustedIps *TrustedIps `json:"trustedIps"` } // UpdateProject updates an existing projects configuration within Vercel. diff --git a/docs/data-sources/alias.md b/docs/data-sources/alias.md index 3b7c7fa6..ec7e0b3e 100644 --- a/docs/data-sources/alias.md +++ b/docs/data-sources/alias.md @@ -30,5 +30,3 @@ An Alias allows a `vercel_deployment` to be accessed through a different URL. - `deployment_id` (String) The ID of the Deployment the Alias is associated with. - `id` (String) The ID of this resource. - - diff --git a/docs/data-sources/file.md b/docs/data-sources/file.md index 9ba4a959..06843acc 100644 --- a/docs/data-sources/file.md +++ b/docs/data-sources/file.md @@ -44,5 +44,3 @@ resource "vercel_deployment" "example" { - `file` (Map of String) A map of filename to metadata about the file. The metadata contains the file size and hash, and allows a deployment to be created if the file changes. - `id` (String) The ID of this resource. - - diff --git a/docs/data-sources/prebuilt_project.md b/docs/data-sources/prebuilt_project.md index 32e316eb..e335951d 100644 --- a/docs/data-sources/prebuilt_project.md +++ b/docs/data-sources/prebuilt_project.md @@ -65,5 +65,3 @@ resource "vercel_deployment" "example" { - `id` (String) The ID of this resource. - `output` (Map of String) A map of output file to metadata about the file. The metadata contains the file size and hash, and allows a deployment to be created if the file changes. - - diff --git a/docs/data-sources/project_directory.md b/docs/data-sources/project_directory.md index eed9655f..751a708c 100644 --- a/docs/data-sources/project_directory.md +++ b/docs/data-sources/project_directory.md @@ -58,5 +58,3 @@ resource "vercel_deployment" "example" { - `files` (Map of String) A map of filename to metadata about the file. The metadata contains the file size and hash, and allows a deployment to be created if the file changes. - `id` (String) The ID of this resource. - - diff --git a/docs/resources/alias.md b/docs/resources/alias.md index 62b03922..1a8d9cbf 100644 --- a/docs/resources/alias.md +++ b/docs/resources/alias.md @@ -30,5 +30,3 @@ An Alias allows a `vercel_deployment` to be accessed through a different URL. ### Read-Only - `id` (String) The ID of this resource. - - diff --git a/docs/resources/deployment.md b/docs/resources/deployment.md index 92399b46..629a5940 100644 --- a/docs/resources/deployment.md +++ b/docs/resources/deployment.md @@ -129,5 +129,3 @@ Optional: - `install_command` (String) The install command for this deployment. If omitted, this value will be taken from the project or automatically detected. - `output_directory` (String) The output directory of the deployment. If omitted, this value will be taken from the project or automatically detected. - `root_directory` (String) The name of a directory or relative path to the source code of your project. When null is used it will default to the project root. - - diff --git a/docs/resources/dns_record.md b/docs/resources/dns_record.md index 88a8e821..171e937f 100644 --- a/docs/resources/dns_record.md +++ b/docs/resources/dns_record.md @@ -124,7 +124,7 @@ For 'TXT' records, this can contain arbitrary text. ### Nested Schema for `srv` -Optional: +Required: - `port` (Number) The TCP or UDP port on which the service is to be found. - `priority` (Number) The priority of the target host, lower value means more preferred. diff --git a/docs/resources/project.md b/docs/resources/project.md index 35c95728..dabfb28e 100644 --- a/docs/resources/project.md +++ b/docs/resources/project.md @@ -113,7 +113,7 @@ Optional: Required: -- `deployment_type` (String) The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`. +- `deployment_type` (String) The deployment environment to protect. Must be one of `standard_protection`, `all_deployments`, or `only_preview_deployments`. - `password` (String, Sensitive) The password that visitors must enter to gain access to your Preview Deployments. Drift detection is not possible for this field. @@ -122,20 +122,23 @@ Required: Required: -- `addresses` (Set of Object) The allowed IP addressses and CIDR ranges with optional descriptions. (see [below for nested schema](#nestedatt--trusted_ips--addresses)) -- `deployment_type` (String) The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, `only_production_deployments`, or `only_preview_deployments`. +- `addresses` (Attributes Set) The allowed IP addressses and CIDR ranges with optional descriptions. (see [below for nested schema](#nestedatt--trusted_ips--addresses)) +- `deployment_type` (String) The deployment environment to protect. Must be one of `standard_protection`, `all_deployments`, `only_production_deployments`, or `only_preview_deployments`. Optional: -- `protection_mode` (String) Whether or not Trusted IPs is optional to access a deployment. Must be either `additional` or `exclusive`. `exclusive` is only availible with Standalone Trusted IPs. +- `protection_mode` (String) Whether or not Trusted IPs is optional to access a deployment. Must be either `trusted_ip_required` or `trusted_ip_optional`. `trusted_ip_optional` is only available with Standalone Trusted IPs. ### Nested Schema for `trusted_ips.addresses` +Required: + +- `value` (String, Sensitive) The address or CIDR range that can access deployments. + Optional: -- `note` (String) -- `value` (String) +- `note` (String) A description for the value @@ -144,7 +147,7 @@ Optional: Required: -- `deployment_type` (String) The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`. +- `deployment_type` (String) The deployment environment to protect. Must be one of `standard_protection`, `all_deployments`, `only_preview_deployments`, or `none`. ## Import diff --git a/vercel/data_source_project.go b/vercel/data_source_project.go index a3037dfe..100f2d18 100644 --- a/vercel/data_source_project.go +++ b/vercel/data_source_project.go @@ -158,7 +158,7 @@ For more detailed information, please see the [Vercel documentation](https://ver }, "password_protection": schema.SingleNestedAttribute{ Description: "Ensures visitors of your Preview Deployments must enter a password in order to gain access.", - Optional: true, + Computed: true, Attributes: map[string]schema.Attribute{ "deployment_type": schema.StringAttribute{ Description: "The deployment environment that will be protected.", @@ -168,7 +168,7 @@ For more detailed information, please see the [Vercel documentation](https://ver }, "trusted_ips": schema.SingleNestedAttribute{ Description: "Ensures only visitors from an allowed IP address can access your deployment.", - Optional: true, + Computed: true, Attributes: map[string]schema.Attribute{ "deployment_type": schema.StringAttribute{ Description: "The deployment environment that will be protected.", diff --git a/vercel/data_source_project_model.go b/vercel/data_source_project_model.go index 66930cdf..6e2d780f 100644 --- a/vercel/data_source_project_model.go +++ b/vercel/data_source_project_model.go @@ -29,6 +29,12 @@ type ProjectDataSource struct { func convertResponseToProjectDataSource(response client.ProjectResponse, plan Project) ProjectDataSource { project := convertResponseToProject(response, plan) + var pp *PasswordProtection + if project.PasswordProtection != nil { + pp = &PasswordProtection{ + DeploymentType: project.PasswordProtection.DeploymentType, + } + } return ProjectDataSource{ BuildCommand: project.BuildCommand, DevCommand: project.DevCommand, @@ -45,7 +51,7 @@ func convertResponseToProjectDataSource(response client.ProjectResponse, plan Pr ServerlessFunctionRegion: project.ServerlessFunctionRegion, TeamID: project.TeamID, VercelAuthentication: project.VercelAuthentication, - PasswordProtection: project.PasswordProtection, + PasswordProtection: pp, TrustedIps: project.TrustedIps, } } diff --git a/vercel/data_source_project_test.go b/vercel/data_source_project_test.go index b199f751..8612b0cb 100644 --- a/vercel/data_source_project_test.go +++ b/vercel/data_source_project_test.go @@ -25,8 +25,16 @@ func TestAcc_ProjectDataSource(t *testing.T) { resource.TestCheckResourceAttr("data.vercel_project.test", "output_directory", ".output"), resource.TestCheckResourceAttr("data.vercel_project.test", "public_source", "true"), resource.TestCheckResourceAttr("data.vercel_project.test", "root_directory", "ui/src"), - resource.TestCheckResourceAttr("data.vercel_project.test", "vercel_authentication.protect_production", "true"), - resource.TestCheckResourceAttr("data.vercel_project.test", "password_protection.protect_production", "true"), + resource.TestCheckResourceAttr("data.vercel_project.test", "vercel_authentication.deployment_type", "standard_protection"), + resource.TestCheckResourceAttr("data.vercel_project.test", "password_protection.deployment_type", "standard_protection"), + resource.TestCheckResourceAttr("data.vercel_project.test", "trusted_ips.addresses.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs("data.vercel_project.test", "trusted_ips.addresses.*", map[string]string{ + "value": "1.1.1.1", + "note": "notey note", + }), + resource.TestCheckResourceAttr("data.vercel_project.test", "trusted_ips.deployment_type", "only_production_deployments"), + resource.TestCheckResourceAttr("data.vercel_project.test", "trusted_ips.protection_mode", "additional"), + resource.TestCheckTypeSetElemNestedAttrs("data.vercel_project.test", "environment.*", map[string]string{ "key": "foo", "value": "bar", @@ -50,11 +58,21 @@ resource "vercel_project" "test" { public_source = true root_directory = "ui/src" vercel_authentication = { - protect_production = true + deployment_type = "standard_protection" } password_protection = { password = "foo" - protect_production = true + deployment_type = "standard_protection" + } + trusted_ips = { + addresses = [ + { + value = "1.1.1.1" + note = "notey note" + } + ] + deployment_type = "only_production_deployments" + protection_mode = "additional" } %s environment = [ diff --git a/vercel/deployment_protection.go b/vercel/deployment_protection.go new file mode 100644 index 00000000..6bb8f354 --- /dev/null +++ b/vercel/deployment_protection.go @@ -0,0 +1,30 @@ +package vercel + +import "github.com/hashicorp/terraform-plugin-framework/types" + +type VercelAuthentication struct { + DeploymentType types.String `tfsdk:"deployment_type"` +} + +type PasswordProtection struct { + DeploymentType types.String `tfsdk:"deployment_type"` +} +type PasswordProtectionWithPassword struct { + DeploymentType types.String `tfsdk:"deployment_type"` + Password types.String `tfsdk:"password"` +} + +type TrustedIpAddress struct { + Value types.String `tfsdk:"value"` + Note types.String `tfsdk:"note"` +} + +type TrustedIps struct { + DeploymentType types.String `tfsdk:"deployment_type"` + Addresses []TrustedIpAddress `tfsdk:"addresses"` + ProtectionMode types.String `tfsdk:"protection_mode"` +} + +type ProtectionBypass struct { + Scope types.String `tfsdk:"scope"` +} diff --git a/vercel/resource_project.go b/vercel/resource_project.go index 40df97d0..54e80447 100644 --- a/vercel/resource_project.go +++ b/vercel/resource_project.go @@ -9,9 +9,11 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -173,15 +175,25 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ }, }, "vercel_authentication": schema.SingleNestedAttribute{ - Description: "Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team.", - Optional: true, + Description: "Ensures visitors to your Preview Deployments are logged into Vercel and have a minimum of Viewer access on your team.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Object{objectplanmodifier.UseStateForUnknown()}, + Default: objectdefault.StaticValue(types.ObjectValueMust( + map[string]attr.Type{ + "deployment_type": types.StringType, + }, + map[string]attr.Value{ + "deployment_type": types.StringValue("standard_protection"), + }, + )), Attributes: map[string]schema.Attribute{ "deployment_type": schema.StringAttribute{ Required: true, - Description: "The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`.", + Description: "The deployment environment to protect. Must be one of `standard_protection`, `all_deployments`, `only_preview_deployments`, or `none`.", PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, Validators: []validator.String{ - stringOneOf("standard_protection", "all_deployments", "only_preview_deployments"), + stringOneOf("standard_protection", "all_deployments", "only_preview_deployments", "none"), }, }, }, @@ -200,7 +212,7 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ }, "deployment_type": schema.StringAttribute{ Required: true, - Description: "The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, or `only_preview_deployments`.", + Description: "The deployment environment to protect. Must be one of `standard_protection`, `all_deployments`, or `only_preview_deployments`.", PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, Validators: []validator.String{ stringOneOf("standard_protection", "all_deployments", "only_preview_deployments"), @@ -212,20 +224,27 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ Description: "Ensures only visitors from an allowed IP address can access your deployment.", Optional: true, Attributes: map[string]schema.Attribute{ - "addresses": schema.SetAttribute{ + "addresses": schema.SetNestedAttribute{ Description: "The allowed IP addressses and CIDR ranges with optional descriptions.", Required: true, PlanModifiers: []planmodifier.Set{setplanmodifier.UseStateForUnknown()}, - ElementType: types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "value": types.StringType, - "note": types.StringType, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "value": schema.StringAttribute{ + Description: "The address or CIDR range that can access deployments.", + Required: true, + Sensitive: true, + }, + "note": schema.StringAttribute{ + Description: "A description for the value", + Optional: true, + }, }, }, }, "deployment_type": schema.StringAttribute{ Required: true, - Description: "The deployment environment to protect. Must be one one `standard_protection`, `all_deployments`, `only_production_deployments`, or `only_preview_deployments`.", + Description: "The deployment environment to protect. Must be one of `standard_protection`, `all_deployments`, `only_production_deployments`, or `only_preview_deployments`.", PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, Validators: []validator.String{ stringOneOf("standard_protection", "all_deployments", "only_production_deployments", "only_preview_deployments"), @@ -233,10 +252,12 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ }, "protection_mode": schema.StringAttribute{ Optional: true, - Description: "Whether or not Trusted IPs is optional to access a deployment. Must be either `additional` or `exclusive`. `exclusive` is only availible with Standalone Trusted IPs.", + Computed: true, + Default: stringdefault.StaticString("trusted_ip_required"), + Description: "Whether or not Trusted IPs is optional to access a deployment. Must be either `trusted_ip_required` or `trusted_ip_optional`. `trusted_ip_optional` is only available with Standalone Trusted IPs.", PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, Validators: []validator.String{ - stringOneOf("additional", "exclusive"), + stringOneOf("trusted_ip_required", "trusted_ip_optional"), }, }, }, diff --git a/vercel/resource_project_model.go b/vercel/resource_project_model.go index eddfde7f..ae4d8669 100644 --- a/vercel/resource_project_model.go +++ b/vercel/resource_project_model.go @@ -11,25 +11,25 @@ import ( // Project reflects the state terraform stores internally for a project. type Project struct { - BuildCommand types.String `tfsdk:"build_command"` - DevCommand types.String `tfsdk:"dev_command"` - Environment types.Set `tfsdk:"environment"` - Framework types.String `tfsdk:"framework"` - GitRepository *GitRepository `tfsdk:"git_repository"` - ID types.String `tfsdk:"id"` - IgnoreCommand types.String `tfsdk:"ignore_command"` - InstallCommand types.String `tfsdk:"install_command"` - Name types.String `tfsdk:"name"` - OutputDirectory types.String `tfsdk:"output_directory"` - PublicSource types.Bool `tfsdk:"public_source"` - RootDirectory types.String `tfsdk:"root_directory"` - ServerlessFunctionRegion types.String `tfsdk:"serverless_function_region"` - TeamID types.String `tfsdk:"team_id"` - VercelAuthentication *VercelAuthentication `tfsdk:"vercel_authentication"` - PasswordProtection *PasswordProtection `tfsdk:"password_protection"` - TrustedIps *TrustedIps `tfsdk:"trusted_ips"` - ProtectionBypassForAutomation types.Bool `tfsdk:"protection_bypass_for_automation"` - ProtectionBypassForAutomationSecret types.String `tfsdk:"protection_bypass_for_automation_secret"` + BuildCommand types.String `tfsdk:"build_command"` + DevCommand types.String `tfsdk:"dev_command"` + Environment types.Set `tfsdk:"environment"` + Framework types.String `tfsdk:"framework"` + GitRepository *GitRepository `tfsdk:"git_repository"` + ID types.String `tfsdk:"id"` + IgnoreCommand types.String `tfsdk:"ignore_command"` + InstallCommand types.String `tfsdk:"install_command"` + Name types.String `tfsdk:"name"` + OutputDirectory types.String `tfsdk:"output_directory"` + PublicSource types.Bool `tfsdk:"public_source"` + RootDirectory types.String `tfsdk:"root_directory"` + ServerlessFunctionRegion types.String `tfsdk:"serverless_function_region"` + TeamID types.String `tfsdk:"team_id"` + VercelAuthentication *VercelAuthentication `tfsdk:"vercel_authentication"` + PasswordProtection *PasswordProtectionWithPassword `tfsdk:"password_protection"` + TrustedIps *TrustedIps `tfsdk:"trusted_ips"` + ProtectionBypassForAutomation types.Bool `tfsdk:"protection_bypass_for_automation"` + ProtectionBypassForAutomationSecret types.String `tfsdk:"protection_bypass_for_automation_secret"` } var nullProject = Project{ @@ -155,48 +155,80 @@ func (g *GitRepository) toCreateProjectRequest() *client.GitRepository { } } -type VercelAuthentication struct { - DeploymentType types.String `tfsdk:"deployment_type"` +func toApiDeploymentProtectionType(dt types.String) string { + switch dt { + case types.StringValue("standard_protection"): + return "prod_deployment_urls_and_all_previews" + case types.StringValue("all_deployments"): + return "all" + case types.StringValue("only_preview_deployments"): + return "preview" + case types.StringValue("only_production_deployments"): + return "production" + default: + return dt.ValueString() + } } -func (v *VercelAuthentication) toUpdateProjectRequest() *client.VercelAuthenticationRequest { +func fromApiDeploymentProtectionType(dt string) types.String { + switch dt { + case "prod_deployment_urls_and_all_previews": + return types.StringValue("standard_protection") + case "all": + return types.StringValue("all_deployments") + case "preview": + return types.StringValue("only_preview_deployments") + case "production": + return types.StringValue("only_production_deployments") + default: + return types.StringValue(dt) + } +} + +func (v *VercelAuthentication) toUpdateProjectRequest() *client.VercelAuthentication { if v == nil { return nil } - return &client.VercelAuthenticationRequest{ - DeploymentType: v.DeploymentType.ValueString(), + return &client.VercelAuthentication{ + DeploymentType: toApiDeploymentProtectionType(v.DeploymentType), } } -type PasswordProtection struct { - Password types.String `tfsdk:"password"` - DeploymentType types.String `tfsdk:"deployment_type"` -} - -func (p *PasswordProtection) toUpdateProjectRequest() *client.PasswordProtectionRequest { +func (p *PasswordProtectionWithPassword) toUpdateProjectRequest() *client.PasswordProtectionWithPassword { if p == nil { return nil } - return &client.PasswordProtectionRequest{ - DeploymentType: p.DeploymentType.ValueString(), + return &client.PasswordProtectionWithPassword{ + DeploymentType: toApiDeploymentProtectionType(p.DeploymentType), Password: p.Password.ValueString(), } } -type TrustedIpsAddress struct { - Value types.String `tfsdk:"value"` - Note types.String `tfsdk:"note"` +func toApiTrustedIpProtectionMode(dt types.String) string { + switch dt { + case types.StringValue("trusted_ip_required"): + return "additional" + case types.StringValue("trusted_ip_optional"): + return "exclusive" + default: + return dt.ValueString() + } } -type TrustedIps struct { - Addresses []TrustedIpsAddress `tfsdk:"addresses"` - DeploymentType types.String `tfsdk:"deployment_type"` - ProtectionMode types.String `tfsdk:"protection_mode"` +func fromApiTrustedIpProtectionMode(dt string) types.String { + switch dt { + case "additional": + return types.StringValue("trusted_ip_required") + case "exclusive": + return types.StringValue("trusted_ip_optional") + default: + return types.StringValue(dt) + } } -func (t *TrustedIps) toUpdateProjectRequest() *client.TrustedIpsRequest { +func (t *TrustedIps) toUpdateProjectRequest() *client.TrustedIps { if t == nil { return nil } @@ -209,10 +241,10 @@ func (t *TrustedIps) toUpdateProjectRequest() *client.TrustedIpsRequest { }) } - return &client.TrustedIpsRequest{ + return &client.TrustedIps{ Addresses: addresses, - DeploymentType: t.DeploymentType.ValueString(), - ProtectionMode: t.ProtectionMode.ValueString(), + DeploymentType: toApiDeploymentProtectionType(t.DeploymentType), + ProtectionMode: toApiTrustedIpProtectionMode(t.ProtectionMode), } } @@ -289,38 +321,40 @@ func convertResponseToProject(response client.ProjectResponse, plan Project) Pro } } - var pp *PasswordProtection + var pp *PasswordProtectionWithPassword if response.PasswordProtection != nil { pass := types.StringValue("") if plan.PasswordProtection != nil { pass = plan.PasswordProtection.Password } - pp = &PasswordProtection{ + pp = &PasswordProtectionWithPassword{ Password: pass, - DeploymentType: types.StringValue(response.PasswordProtection.DeploymentType), + DeploymentType: fromApiDeploymentProtectionType(response.PasswordProtection.DeploymentType), } } - var va *VercelAuthentication + var va *VercelAuthentication = &VercelAuthentication{ + DeploymentType: types.StringValue("none"), + } if response.VercelAuthentication != nil { va = &VercelAuthentication{ - DeploymentType: types.StringValue(response.VercelAuthentication.DeploymentType), + DeploymentType: fromApiDeploymentProtectionType(response.VercelAuthentication.DeploymentType), } } var tip *TrustedIps if response.TrustedIps != nil { - var addresses []TrustedIpsAddress + var addresses []TrustedIpAddress for _, address := range response.TrustedIps.Addresses { - addresses = append(addresses, TrustedIpsAddress{ + addresses = append(addresses, TrustedIpAddress{ Value: types.StringValue(address.Value), Note: types.StringValue(address.Note), }) } tip = &TrustedIps{ - DeploymentType: types.StringValue(response.TrustedIps.DeploymentType), + DeploymentType: fromApiDeploymentProtectionType(response.TrustedIps.DeploymentType), Addresses: addresses, - ProtectionMode: types.StringValue(response.TrustedIps.ProtectionMode), + ProtectionMode: fromApiTrustedIpProtectionMode(response.TrustedIps.ProtectionMode), } } diff --git a/vercel/resource_project_test.go b/vercel/resource_project_test.go index 41964115..de05fbf7 100644 --- a/vercel/resource_project_test.go +++ b/vercel/resource_project_test.go @@ -146,7 +146,7 @@ func TestAcc_ProjectWithGitRepository(t *testing.T) { }) } -func TestAcc_ProjectWithSSOAndPasswordProtection(t *testing.T) { +func TestAcc_ProjectWithVercelAuthAndPasswordProtectionAndTrustedIps(t *testing.T) { projectSuffix := acctest.RandString(16) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -154,44 +154,74 @@ func TestAcc_ProjectWithSSOAndPasswordProtection(t *testing.T) { CheckDestroy: testAccProjectDestroy("vercel_project.enabled_to_start", testTeam()), Steps: []resource.TestStep{ { - Config: testAccProjectConfigWithSSOAndPassword(projectSuffix, teamIDConfig()), + Config: testAccProjectConfigWithVercelAuthAndPasswordAndTrustedIps(projectSuffix, teamIDConfig()), Check: resource.ComposeAggregateTestCheckFunc( testAccProjectExists("vercel_project.enabled_to_start", testTeam()), - resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "vercel_authentication.protect_production", "true"), - resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "password_protection.protect_production", "true"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "vercel_authentication.deployment_type", "all_deployments"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "password_protection.deployment_type", "all_deployments"), resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "password_protection.password", "password"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "trusted_ips.addresses.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs("vercel_project.enabled_to_start", "trusted_ips.addresses.*", map[string]string{ + "value": "1.1.1.1", + "note": "notey note", + }), + resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "trusted_ips.deployment_type", "all_deployments"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "trusted_ips.protection_mode", "exclusive"), resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "protection_bypass_for_automation", "true"), resource.TestCheckResourceAttrSet("vercel_project.enabled_to_start", "protection_bypass_for_automation_secret"), testAccProjectExists("vercel_project.disabled_to_start", testTeam()), - resource.TestCheckNoResourceAttr("vercel_project.disabled_to_start", "vercel_authentication"), + resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "vercel_authentication.deployment_type", "standard_protection"), resource.TestCheckNoResourceAttr("vercel_project.disabled_to_start", "password_protection"), + resource.TestCheckNoResourceAttr("vercel_project.disabled_to_start", "trusted_ips"), resource.TestCheckNoResourceAttr("vercel_project.disabled_to_start", "protection_bypass_for_automation"), resource.TestCheckNoResourceAttr("vercel_project.disabled_to_start", "protection_bypass_for_automation_secret"), testAccProjectExists("vercel_project.enabled_to_update", testTeam()), - resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "vercel_authentication.protect_production", "false"), - resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "password_protection.protect_production", "false"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "vercel_authentication.deployment_type", "only_preview_deployments"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "password_protection.deployment_type", "only_preview_deployments"), resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "password_protection.password", "password"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.addresses.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs("vercel_project.enabled_to_update", "trusted_ips.addresses.*", map[string]string{ + "value": "1.1.1.3", + "note": "notey notey note", + }), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.deployment_type", "only_production_deployments"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.protection_mode", "additional"), resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "protection_bypass_for_automation", "true"), resource.TestCheckResourceAttrSet("vercel_project.enabled_to_update", "protection_bypass_for_automation_secret"), ), }, { - Config: testAccProjectConfigWithSSOAndPasswordUpdated(projectSuffix, teamIDConfig()), + Config: testAccProjectConfigWithVercelAuthAndPasswordAndTrustedIpsUpdated(projectSuffix, teamIDConfig()), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckNoResourceAttr("vercel_project.enabled_to_start", "vercel_authentication"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "vercel_authentication.deployment_type", "standard_protection"), resource.TestCheckNoResourceAttr("vercel_project.enabled_to_start", "password_protection"), resource.TestCheckNoResourceAttr("vercel_project.enabled_to_start", "protection_bypass_for_automation"), + resource.TestCheckNoResourceAttr("vercel_project.enabled_to_start", "trusted_ips"), resource.TestCheckNoResourceAttr("vercel_project.enabled_to_start", "protection_bypass_for_automation_secret"), - resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "vercel_authentication.protect_production", "true"), - resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "password_protection.protect_production", "true"), + resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "vercel_authentication.deployment_type", "standard_protection"), + resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "password_protection.deployment_type", "standard_protection"), resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "password_protection.password", "password"), + resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "trusted_ips.addresses.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs("vercel_project.disabled_to_start", "trusted_ips.addresses.*", map[string]string{ + "value": "1.1.1.1", + "note": "notey note", + }), + resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "trusted_ips.deployment_type", "standard_protection"), + resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "trusted_ips.protection_mode", "additional"), resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "protection_bypass_for_automation", "true"), resource.TestCheckResourceAttrSet("vercel_project.disabled_to_start", "protection_bypass_for_automation_secret"), - resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "vercel_authentication.protect_production", "true"), - resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "password_protection.protect_production", "true"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "vercel_authentication.deployment_type", "standard_protection"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "password_protection.deployment_type", "standard_protection"), resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "password_protection.password", "password2"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.addresses.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs("vercel_project.enabled_to_update", "trusted_ips.addresses.*", map[string]string{ + "value": "1.1.1.3", + "note": "notey notey", + }), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.deployment_type", "all_deployments"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.protection_mode", "exclusive"), resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "protection_bypass_for_automation", "false"), resource.TestCheckNoResourceAttr("vercel_project.enabled_to_update", "protection_bypass_for_automation_secret"), ), @@ -330,18 +360,28 @@ resource "vercel_project" "test" { `, projectSuffix, teamID) } -func testAccProjectConfigWithSSOAndPassword(projectSuffix, teamID string) string { +func testAccProjectConfigWithVercelAuthAndPasswordAndTrustedIps(projectSuffix, teamID string) string { return fmt.Sprintf(` resource "vercel_project" "enabled_to_start" { name = "test-acc-protection-one-%[1]s" %[2]s vercel_authentication = { - protect_production = true + deployment_type = "all_deployments" } password_protection = { - protect_production = true + deployment_type = "all_deployments" password = "password" } + trusted_ips = { + addresses = [ + { + value = "1.1.1.1" + note = "notey note" + } + ] + deployment_type = "all_deployments" + protection_mode = "exclusive" + } protection_bypass_for_automation = true } @@ -354,18 +394,31 @@ resource "vercel_project" "enabled_to_update" { name = "test-acc-protection-three-%[1]s" %[2]s vercel_authentication = { - protect_production = false + deployment_type = "only_preview_deployments" } password_protection = { - protect_production = false + deployment_type = "only_preview_deployments" password = "password" } + trusted_ips = { + addresses = [ + { + value = "1.1.1.1" + note = "notey notey" + }, + { + value = "1.1.1.3" + note = "notey notey note" + } + ] + deployment_type = "only_production_deployments" + } protection_bypass_for_automation = true } `, projectSuffix, teamID) } -func testAccProjectConfigWithSSOAndPasswordUpdated(projectSuffix, teamID string) string { +func testAccProjectConfigWithVercelAuthAndPasswordAndTrustedIpsUpdated(projectSuffix, teamID string) string { return fmt.Sprintf(` resource "vercel_project" "enabled_to_start" { name = "test-acc-protection-one-%[1]s" @@ -376,12 +429,21 @@ resource "vercel_project" "disabled_to_start" { name = "test-acc-protection-two-%[1]s" %[2]s vercel_authentication = { - protect_production = true + deployment_type = "standard_protection" } password_protection = { - protect_production = true + deployment_type = "standard_protection" password = "password" } + trusted_ips = { + addresses = [ + { + value = "1.1.1.1" + note = "notey note" + } + ] + deployment_type = "standard_protection" + } protection_bypass_for_automation = true } @@ -389,12 +451,22 @@ resource "vercel_project" "enabled_to_update" { name = "test-acc-protection-three-%[1]s" %[2]s vercel_authentication = { - protect_production = true + deployment_type = "standard_protection" } password_protection = { - protect_production = true + deployment_type = "standard_protection" password = "password2" } + trusted_ips = { + addresses = [ + { + value = "1.1.1.3" + note = "notey notey" + } + ] + deployment_type = "all_deployments" + protection_mode = "exclusive" + } protection_bypass_for_automation = false } `, projectSuffix, teamID) From 94d9edca750096bb481f5f0efc4a8ff945b7bc94 Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Fri, 24 Nov 2023 10:17:10 +0100 Subject: [PATCH 7/9] validate addresses is non empty --- README.md | 37 ++++++++++++++++++++----------------- vercel/resource_project.go | 3 +++ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index d7fe7bfe..82e05b0d 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,30 @@ If you wish to work on the provider, you'll first need [Go](http://www.golang.or To compile the provider, run `task build`. This will build the provider and put the provider binary in the repository root. -In addition, you can run `task install` to set up a developer overrides in your ~/.terraformrc. This will then allow you -to use your locally built provider binary. +```sh +$ task build +``` + +In addition, you can run `task install` to set up a developer overrides in your ~/.terraformrc. This will then allow you to use your locally built provider binary. + +```sh +$ task install +``` + +Create a `main.tf` file on your machine and use the [terraform cli](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli#install-terraform) to test + +```sh +$ terraform plan +$ terraform apply +``` When you are finished using a local version of the provider, running `task uninstall` will remove _all_ developer overrides. +```sh +$ task uninstall +``` + - HashiCorp - [Development Overrides for Provider developers](https://www.terraform.io/docs/cli/config/config-file.html#development-overrides-for-provider-developers). ## Testing @@ -61,21 +79,6 @@ To run a specific set of tests, use the `-run` flag and specify a regex pattern $ task test -- -run 'TestAcc_Project*' ``` -## Running the provider locally - -Set up a local override on your machine - -```sh -$ task install -``` - -Build the provider - -```sh -$ task build -``` - -Create a `main.tf` file on your machine and use the [terraform cli](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli#install-terraform) to test ## Building The Documentation diff --git a/vercel/resource_project.go b/vercel/resource_project.go index 54e80447..bb1d79f1 100644 --- a/vercel/resource_project.go +++ b/vercel/resource_project.go @@ -241,6 +241,9 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ }, }, }, + Validators: []validator.Set{ + stringSetMinCount(1), + }, }, "deployment_type": schema.StringAttribute{ Required: true, From 9241655b5c16025a7af366f41725d8216e8e0233 Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Fri, 24 Nov 2023 10:23:01 +0100 Subject: [PATCH 8/9] update trusted ips tests --- docs/index.md | 2 +- examples/provider/provider.tf | 2 +- vercel/data_source_project.go | 2 +- vercel/data_source_project_test.go | 4 ++-- vercel/resource_project_test.go | 12 ++++++------ 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/index.md b/docs/index.md index 7a517e1a..f872eb00 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,7 +25,7 @@ terraform { required_providers { vercel = { source = "vercel/vercel" - version = "~> 0.4" + version = "~> 1.0" } } } diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index ce63b5fc..a82ab0fb 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -5,7 +5,7 @@ terraform { required_providers { vercel = { source = "vercel/vercel" - version = "~> 0.4" + version = "~> 1.0" } } } diff --git a/vercel/data_source_project.go b/vercel/data_source_project.go index 100f2d18..ff92a180 100644 --- a/vercel/data_source_project.go +++ b/vercel/data_source_project.go @@ -185,7 +185,7 @@ For more detailed information, please see the [Vercel documentation](https://ver }, }, "protection_mode": schema.StringAttribute{ - Description: "Whether or not Trusted IPs is optional to access a deployment.", + Description: "Whether or not Trusted IPs is required or optional to access a deployment.", Computed: true, }, }, diff --git a/vercel/data_source_project_test.go b/vercel/data_source_project_test.go index 8612b0cb..e107a21a 100644 --- a/vercel/data_source_project_test.go +++ b/vercel/data_source_project_test.go @@ -33,7 +33,7 @@ func TestAcc_ProjectDataSource(t *testing.T) { "note": "notey note", }), resource.TestCheckResourceAttr("data.vercel_project.test", "trusted_ips.deployment_type", "only_production_deployments"), - resource.TestCheckResourceAttr("data.vercel_project.test", "trusted_ips.protection_mode", "additional"), + resource.TestCheckResourceAttr("data.vercel_project.test", "trusted_ips.protection_mode", "trusted_ip_required"), resource.TestCheckTypeSetElemNestedAttrs("data.vercel_project.test", "environment.*", map[string]string{ "key": "foo", @@ -72,7 +72,7 @@ resource "vercel_project" "test" { } ] deployment_type = "only_production_deployments" - protection_mode = "additional" + protection_mode = "trusted_ip_required" } %s environment = [ diff --git a/vercel/resource_project_test.go b/vercel/resource_project_test.go index de05fbf7..11a7a3da 100644 --- a/vercel/resource_project_test.go +++ b/vercel/resource_project_test.go @@ -166,7 +166,7 @@ func TestAcc_ProjectWithVercelAuthAndPasswordProtectionAndTrustedIps(t *testing. "note": "notey note", }), resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "trusted_ips.deployment_type", "all_deployments"), - resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "trusted_ips.protection_mode", "exclusive"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "trusted_ips.protection_mode", "trusted_ip_optional"), resource.TestCheckResourceAttr("vercel_project.enabled_to_start", "protection_bypass_for_automation", "true"), resource.TestCheckResourceAttrSet("vercel_project.enabled_to_start", "protection_bypass_for_automation_secret"), testAccProjectExists("vercel_project.disabled_to_start", testTeam()), @@ -185,7 +185,7 @@ func TestAcc_ProjectWithVercelAuthAndPasswordProtectionAndTrustedIps(t *testing. "note": "notey notey note", }), resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.deployment_type", "only_production_deployments"), - resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.protection_mode", "additional"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.protection_mode", "trusted_ip_required"), resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "protection_bypass_for_automation", "true"), resource.TestCheckResourceAttrSet("vercel_project.enabled_to_update", "protection_bypass_for_automation_secret"), ), @@ -208,7 +208,7 @@ func TestAcc_ProjectWithVercelAuthAndPasswordProtectionAndTrustedIps(t *testing. "note": "notey note", }), resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "trusted_ips.deployment_type", "standard_protection"), - resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "trusted_ips.protection_mode", "additional"), + resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "trusted_ips.protection_mode", "trusted_ip_required"), resource.TestCheckResourceAttr("vercel_project.disabled_to_start", "protection_bypass_for_automation", "true"), resource.TestCheckResourceAttrSet("vercel_project.disabled_to_start", "protection_bypass_for_automation_secret"), @@ -221,7 +221,7 @@ func TestAcc_ProjectWithVercelAuthAndPasswordProtectionAndTrustedIps(t *testing. "note": "notey notey", }), resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.deployment_type", "all_deployments"), - resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.protection_mode", "exclusive"), + resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "trusted_ips.protection_mode", "trusted_ip_optional"), resource.TestCheckResourceAttr("vercel_project.enabled_to_update", "protection_bypass_for_automation", "false"), resource.TestCheckNoResourceAttr("vercel_project.enabled_to_update", "protection_bypass_for_automation_secret"), ), @@ -380,7 +380,7 @@ resource "vercel_project" "enabled_to_start" { } ] deployment_type = "all_deployments" - protection_mode = "exclusive" + protection_mode = "trusted_ip_optional" } protection_bypass_for_automation = true } @@ -465,7 +465,7 @@ resource "vercel_project" "enabled_to_update" { } ] deployment_type = "all_deployments" - protection_mode = "exclusive" + protection_mode = "trusted_ip_optional" } protection_bypass_for_automation = false } From 63242b5988c761ad0e4103590d236c29698bba7c Mon Sep 17 00:00:00 2001 From: Kit Foster Date: Fri, 24 Nov 2023 10:28:35 +0100 Subject: [PATCH 9/9] docs --- docs/data-sources/project.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-sources/project.md b/docs/data-sources/project.md index aa985312..c7dbec3c 100644 --- a/docs/data-sources/project.md +++ b/docs/data-sources/project.md @@ -95,7 +95,7 @@ Read-Only: - `addresses` (List of Object) The allowed IP addressses and CIDR ranges with optional descriptions. (see [below for nested schema](#nestedatt--trusted_ips--addresses)) - `deployment_type` (String) The deployment environment that will be protected. -- `protection_mode` (String) Whether or not Trusted IPs is optional to access a deployment. +- `protection_mode` (String) Whether or not Trusted IPs is required or optional to access a deployment. ### Nested Schema for `trusted_ips.addresses`