这是indexloc提供的服务,不要输入任何密码
Skip to content

Add support for Attack Challenge Mode #181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions client/attack_challenge_mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package client

import (
"context"
"fmt"
)

type AttackChallengeMode struct {
ProjectID string `json:"projectId"`
TeamID string `json:"-"`
Enabled bool `json:"attackModeEnabled"`
}

func (c *Client) GetAttackChallengeMode(ctx context.Context, projectID, teamID string) (a AttackChallengeMode, err error) {
project, err := c.GetProject(ctx, projectID, teamID)
if err != nil {
return a, err
}
var enabled bool
if project.Security != nil {
enabled = project.Security.AttackModeEnabled
}
return AttackChallengeMode{
ProjectID: projectID,
TeamID: teamID,
Enabled: enabled,
}, err
}

func (c *Client) UpdateAttackChallengeMode(ctx context.Context, request AttackChallengeMode) (a AttackChallengeMode, err error) {
url := fmt.Sprintf("%s/security/attack-mode", c.baseURL)
if c.teamID(request.TeamID) != "" {
url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(request.TeamID))
}

payload := string(mustMarshal(request))
var res struct {
AttackModeEnabled bool `json:"attackModeEnabled"`
}
err = c.doRequest(clientRequest{
ctx: ctx,
method: "POST",
url: url,
body: payload,
}, &res)
if err != nil {
return a, err
}
return AttackChallengeMode{
ProjectID: request.ProjectID,
TeamID: request.TeamID,
Enabled: res.AttackModeEnabled,
}, err
}
5 changes: 5 additions & 0 deletions client/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,18 @@ type ProjectResponse struct {
DirectoryListing bool `json:"directoryListing"`
SkewProtectionMaxAge int `json:"skewProtectionMaxAge"`
GitComments *GitComments `json:"gitComments"`
Security *Security `json:"security"`
}

type GitComments struct {
OnCommit bool `json:"onCommit"`
OnPullRequest bool `json:"onPullRequest"`
}

type Security struct {
AttackModeEnabled bool `json:"attackModeEnabled"`
}

// GetProject retrieves information about an existing project from Vercel.
func (c *Client) GetProject(ctx context.Context, projectID, teamID string) (r ProjectResponse, err error) {
url := fmt.Sprintf("%s/v10/projects/%s", c.baseURL, projectID)
Expand Down
38 changes: 38 additions & 0 deletions docs/data-sources/attack_challenge_mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "vercel_attack_challenge_mode Data Source - terraform-provider-vercel"
subcategory: ""
description: |-
Provides an Attack Challenge Mode resource.
Attack Challenge Mode prevent malicious traffic by showing a verification challenge for every visitor.
---

# vercel_attack_challenge_mode (Data Source)

Provides an Attack Challenge Mode resource.

Attack Challenge Mode prevent malicious traffic by showing a verification challenge for every visitor.

## Example Usage

```terraform
data "vercel_attack_challenge_mode" "example" {
project_id = vercel_project.example.id
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `project_id` (String) The ID of the Project to adjust the CPU for.

### Optional

- `team_id` (String) The ID of the team the Project exists under. Required when configuring a team resource if a default team has not been set in the provider.

### Read-Only

- `enabled` (Boolean) Whether Attack Challenge Mode is enabled or not.
- `id` (String) The resource identifier.
54 changes: 54 additions & 0 deletions docs/resources/attack_challenge_mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "vercel_attack_challenge_mode Resource - terraform-provider-vercel"
subcategory: ""
description: |-
Provides an Attack Challenge Mode resource.
Attack Challenge Mode prevent malicious traffic by showing a verification challenge for every visitor.
---

# vercel_attack_challenge_mode (Resource)

Provides an Attack Challenge Mode resource.

Attack Challenge Mode prevent malicious traffic by showing a verification challenge for every visitor.

## Example Usage

```terraform
resource "vercel_project" "example" {
name = "example-project"
}

resource "vercel_attack_challenge_mode" "example" {
project_id = vercel_project.example.id
enabled = true
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `enabled` (Boolean) Whether Attack Challenge Mode is enabled or not.
- `project_id` (String) The ID of the Project to adjust the CPU for.

### Optional

- `team_id` (String) The ID of the team the Project exists under. Required when configuring a team resource if a default team has not been set in the provider.

### Read-Only

- `id` (String) The resource identifier.

## Import

Import is supported using the following syntax:

```shell
# You can import via the team_id and project_id.
# - team_id can be found in the team `settings` tab in the Vercel UI.
# - project_id can be found in the project `settings` tab in the Vercel UI.
terraform import vercel_attack_challenge_mode.example team_xxxxxxxxxxxxxxxxxxxxxxxx/prj_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "vercel_attack_challenge_mode" "example" {
project_id = vercel_project.example.id
}
4 changes: 4 additions & 0 deletions examples/resources/vercel_attack_challenge_mode/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# You can import via the team_id and project_id.
# - team_id can be found in the team `settings` tab in the Vercel UI.
# - project_id can be found in the project `settings` tab in the Vercel UI.
terraform import vercel_attack_challenge_mode.example team_xxxxxxxxxxxxxxxxxxxxxxxx/prj_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
8 changes: 8 additions & 0 deletions examples/resources/vercel_attack_challenge_mode/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
resource "vercel_project" "example" {
name = "example-project"
}

resource "vercel_attack_challenge_mode" "example" {
project_id = vercel_project.example.id
enabled = true
}
113 changes: 113 additions & 0 deletions vercel/data_source_attack_challenge_mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package vercel

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/vercel/terraform-provider-vercel/client"
)

// Ensure the implementation satisfies the expected interfaces.
var (
_ datasource.DataSource = &attackChallengeModeDataSource{}
_ datasource.DataSourceWithConfigure = &attackChallengeModeDataSource{}
)

func newAttackChallengeModeDataSource() datasource.DataSource {
return &attackChallengeModeDataSource{}
}

type attackChallengeModeDataSource struct {
client *client.Client
}

func (d *attackChallengeModeDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_attack_challenge_mode"
}

func (d *attackChallengeModeDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*client.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}

d.client = client
}

func (r *attackChallengeModeDataSource) Schema(_ context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: `
Provides an Attack Challenge Mode resource.

Attack Challenge Mode prevent malicious traffic by showing a verification challenge for every visitor.`,
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "The resource identifier.",
Computed: true,
},
"project_id": schema.StringAttribute{
Description: "The ID of the Project to adjust the CPU for.",
Required: true,
},
"team_id": schema.StringAttribute{
Optional: true,
Computed: true,
Description: "The ID of the team the Project exists under. Required when configuring a team resource if a default team has not been set in the provider.",
},
"enabled": schema.BoolAttribute{
Computed: true,
Description: "Whether Attack Challenge Mode is enabled or not.",
},
},
}
}

func (d *attackChallengeModeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var config AttackChallengeMode
diags := req.Config.Get(ctx, &config)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

out, err := d.client.GetAttackChallengeMode(ctx, config.ProjectID.ValueString(), config.TeamID.ValueString())
if client.NotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.AddError(
"Error reading Attack Challenge Mode",
fmt.Sprintf("Could not get Attack Challenge Mode %s %s, unexpected error: %s",
config.TeamID.ValueString(),
config.ProjectID.ValueString(),
err,
),
)
return
}

result := responseToAttackChallengeMode(out)
tflog.Info(ctx, "read attack challenge mode", map[string]interface{}{
"team_id": result.TeamID.ValueString(),
"project_id": result.ProjectID.ValueString(),
})

diags = resp.State.Set(ctx, result)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
73 changes: 73 additions & 0 deletions vercel/data_source_attack_challenge_mode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package vercel_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)

func TestAcc_AttackChallengeModeDataSource(t *testing.T) {
name := acctest.RandString(16)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccAttackChallengeModeConfig(name, teamIDConfig()),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.vercel_attack_challenge_mode.never_enabled", "enabled", "false"),
resource.TestCheckResourceAttr("data.vercel_attack_challenge_mode.enabled", "enabled", "true"),
resource.TestCheckResourceAttr("data.vercel_attack_challenge_mode.disabled", "enabled", "false"),
),
},
},
})
}

func testAccAttackChallengeModeConfig(name, teamID string) string {
return fmt.Sprintf(`
resource "vercel_project" "never_enabled" {
name = "test-acc-%[1]s"
%[2]s
}

data "vercel_attack_challenge_mode" "never_enabled" {
project_id = vercel_project.never_enabled.id
%[2]s
}

resource "vercel_project" "enabled" {
name = "test-acc-%[1]s-enabled"
%[2]s
}

resource "vercel_attack_challenge_mode" "enabled" {
project_id = vercel_project.enabled.id
enabled = true
%[2]s
}

data "vercel_attack_challenge_mode" "enabled" {
project_id = vercel_attack_challenge_mode.enabled.project_id
%[2]s
}

resource "vercel_project" "disabled" {
name = "test-acc-%[1]s-disabled"
%[2]s
}

resource "vercel_attack_challenge_mode" "disabled" {
project_id = vercel_project.disabled.id
enabled = false
%[2]s
}

data "vercel_attack_challenge_mode" "disabled" {
project_id = vercel_attack_challenge_mode.disabled.project_id
%[2]s
}
`, name, teamID)
}
2 changes: 2 additions & 0 deletions vercel/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Use the navigation to the left to read about the available resources.
func (p *vercelProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
newAliasResource,
newAttackChallengeModeResource,
newDNSRecordResource,
newDeploymentResource,
newEdgeConfigResource,
Expand All @@ -69,6 +70,7 @@ func (p *vercelProvider) Resources(_ context.Context) []func() resource.Resource
func (p *vercelProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
newAliasDataSource,
newAttackChallengeModeDataSource,
newDeploymentDataSource,
newEdgeConfigDataSource,
newEdgeConfigSchemaDataSource,
Expand Down
Loading