Skip to content

Commit

Permalink
Merge pull request #4674 from mrusso19/add-lcc-resource
Browse files Browse the repository at this point in the history
Add Leaked Credential Check resource
  • Loading branch information
jacobbednarz authored Dec 4, 2024
2 parents 12dbc2e + eca1521 commit d61ee7a
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/4674.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
cloudflare_leaked_credential_check
```
35 changes: 35 additions & 0 deletions docs/resources/leaked_credential_check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
page_title: "cloudflare_leaked_credential_check Resource - Cloudflare"
subcategory: ""
description: |-
Provides a Cloudflare Leaked Credential Check resource to be used for managing the status of the Cloudflare Leaked Credential detection within a specific zone.
---

# cloudflare_leaked_credential_check (Resource)

Provides a Cloudflare Leaked Credential Check resource to be used for managing the status of the Cloudflare Leaked Credential detection within a specific zone.

## Example Usage

```terraform
# Enable the Leaked Credentials Check detection
resource "cloudflare_leaked_credential_check" "example" {
zone_id = "399c6f4950c01a5a141b99ff7fbcbd8b"
enabled = true
}
```
<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `enabled` (Boolean) State of the Leaked Credential Check detection
- `zone_id` (String) The zone identifier to target for the resource.

## Import

Import is supported using the following syntax:

```shell
terraform import cloudflare_leaked_credential_check.example <zone_id>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import cloudflare_leaked_credential_check.example <zone_id>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Enable the Leaked Credentials Check detection
resource "cloudflare_leaked_credential_check" "example" {
zone_id = "399c6f4950c01a5a141b99ff7fbcbd8b"
enabled = true
}
2 changes: 2 additions & 0 deletions internal/framework/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/gateway_categories"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/hyperdrive_config"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/infrastructure_access_target_deprecated"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/leaked_credential_check"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/list"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/list_item"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/origin_ca_certificate"
Expand Down Expand Up @@ -387,6 +388,7 @@ func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Re
zero_trust_risk_score_integration.NewResource,
infrastructure_access_target_deprecated.NewResource,
zero_trust_infrastructure_access_target.NewResource,
leaked_credential_check.NewResource,
}
}

Expand Down
8 changes: 8 additions & 0 deletions internal/framework/service/leaked_credential_check/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package leaked_credential_check

import "github.com/hashicorp/terraform-plugin-framework/types"

type LeakedCredentialCheckModel struct {
ZoneID types.String `tfsdk:"zone_id"`
Enabled types.Bool `tfsdk:"enabled"`
}
141 changes: 141 additions & 0 deletions internal/framework/service/leaked_credential_check/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package leaked_credential_check

import (
"context"
"fmt"

"github.com/cloudflare/cloudflare-go"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/muxclient"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
)

var (
_ resource.Resource = &LeakedCredentialCheckResource{}
)

func NewResource() resource.Resource {
return &LeakedCredentialCheckResource{}
}

type LeakedCredentialCheckResource struct {
client *muxclient.Client
}

func (r *LeakedCredentialCheckResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_leaked_credential_check"
}

func (r *LeakedCredentialCheckResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*muxclient.Client)

if !ok {
resp.Diagnostics.AddError(
"unexpected resource configure type",
fmt.Sprintf("Expected *muxclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

r.client = client
}

func (r *LeakedCredentialCheckResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan LeakedCredentialCheckModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

zoneID := plan.ZoneID.ValueString()
createParams := cloudflare.LeakCredentialCheckSetStatusParams{
Enabled: plan.Enabled.ValueBoolPointer(),
}

_, err := r.client.V1.LeakedCredentialCheckSetStatus(ctx, cloudflare.ZoneIdentifier(zoneID), createParams)
if err != nil {
resp.Diagnostics.AddError("Error enabling (Create) Leaked Credential Check", err.Error())
return
}

diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
}

func (r *LeakedCredentialCheckResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state LeakedCredentialCheckModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

zoneID := state.ZoneID.ValueString()
status, err := r.client.V1.LeakedCredentialCheckGetStatus(ctx, cloudflare.ZoneIdentifier(zoneID), cloudflare.LeakedCredentialCheckGetStatusParams{})
if err != nil {
resp.Diagnostics.AddError("Error reading Leaked Credential Check status", err.Error())
return
}
state.Enabled = types.BoolPointerValue(status.Enabled)

diags = resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
}

func (r *LeakedCredentialCheckResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var plan LeakedCredentialCheckModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

zoneID := plan.ZoneID.ValueString()
updateParams := cloudflare.LeakCredentialCheckSetStatusParams{
Enabled: plan.Enabled.ValueBoolPointer(),
}

_, err := r.client.V1.LeakedCredentialCheckSetStatus(ctx, cloudflare.ZoneIdentifier(zoneID), updateParams)
if err != nil {
resp.Diagnostics.AddError("Error updating status of Leaked Credential Check", err.Error())
return
}

diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
}

// Delete disables (enabled: false) the Leaked Credential Check functionality
func (r *LeakedCredentialCheckResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state LeakedCredentialCheckModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

zoneID := state.ZoneID.ValueString()
params := cloudflare.LeakCredentialCheckSetStatusParams{
Enabled: cloudflare.BoolPtr(false),
}

_, err := r.client.V1.LeakedCredentialCheckSetStatus(ctx, cloudflare.ZoneIdentifier(zoneID), params)
if err != nil {
resp.Diagnostics.AddError("Error updating status of Leaked Credential Check", err.Error())
return
}
}

func (r *LeakedCredentialCheckResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
// req.ID is the zoneID for which you want to import the state of the
// Leaked Credential Check feature
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("zone_id"), req.ID)...)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package leaked_credential_check_test

import (
"context"
"errors"
"fmt"
"log"
"os"
"testing"

cfv1 "github.com/cloudflare/cloudflare-go"
"github.com/cloudflare/terraform-provider-cloudflare/internal/acctest"
"github.com/cloudflare/terraform-provider-cloudflare/internal/utils"

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

func init() {
resource.AddTestSweepers("cloudflare_leaked_credential_check", &resource.Sweeper{
Name: "cloudflare_leaked_credential_check",
F: testSweepCloudflareLCC,
})
}

func testSweepCloudflareLCC(r string) error {
ctx := context.Background()
client, clientErr := acctest.SharedV1Client()
if clientErr != nil {
tflog.Error(ctx, fmt.Sprintf("Failed to create Cloudflare client: %s", clientErr))
}

zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
if zoneID == "" {
return errors.New("CLOUDFLARE_ZONE_ID must be set")
}

status, err := client.LeakedCredentialCheckGetStatus(ctx, cfv1.ZoneIdentifier(zoneID), cfv1.LeakedCredentialCheckGetStatusParams{})
if err != nil {
tflog.Error(ctx, fmt.Sprintf("Failed to GET Leaked Credential status: %s", err))
}

if *status.Enabled == false {
log.Print("[DEBUG] LCC already disabled")
return nil
}
_, err = client.LeakedCredentialCheckSetStatus(ctx, cfv1.ZoneIdentifier(zoneID), cfv1.LeakCredentialCheckSetStatusParams{Enabled: cfv1.BoolPtr(false)})
if err != nil {
tflog.Error(ctx, fmt.Sprintf("Failed to disable Leaked Credential Check: %s", err))
return err
}

return nil
}

func TestAccCloudflareLeakedCredentialCheck_Basic(t *testing.T) {
rnd := utils.GenerateRandomResourceName()
name := fmt.Sprintf("cloudflare_leaked_credential_check.%s", rnd)
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")

resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.TestAccPreCheck(t)
},
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccLCCSimple(rnd, zoneID, "true"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "enabled", "true"),
),
},
{
Config: testAccLCCSimple(rnd, zoneID, "false"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "enabled", "false"),
),
},
},
})
}

func testAccLCCSimple(ID, zoneID, enabled string) string {
return fmt.Sprintf(`
resource "cloudflare_leaked_credential_check" "%[1]s" {
zone_id = "%[2]s"
enabled = "%[3]s"
}`, ID, zoneID, enabled)
}
25 changes: 25 additions & 0 deletions internal/framework/service/leaked_credential_check/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package leaked_credential_check

import (
"context"

"github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
)

func (r *LeakedCredentialCheckResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Provides a Cloudflare Leaked Credential Check resource to be used for managing the status of the Cloudflare Leaked Credential detection within a specific zone.",
Attributes: map[string]schema.Attribute{
consts.ZoneIDSchemaKey: schema.StringAttribute{
Description: consts.ZoneIDSchemaDescription,
Required: true,
},
"enabled": schema.BoolAttribute{
Description: "State of the Leaked Credential Check detection",
Required: true,
},
},
}
}

0 comments on commit d61ee7a

Please sign in to comment.