Skip to content

Commit

Permalink
Merge pull request #4719 from mrusso19/add-content-scanning
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobbednarz authored Dec 26, 2024
2 parents 49c8582 + 36306ce commit 04ef12b
Show file tree
Hide file tree
Showing 9 changed files with 321 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/4719.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
cloudflare_content_scanning
```
35 changes: 35 additions & 0 deletions docs/resources/content_scanning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
page_title: "cloudflare_content_scanning Resource - Cloudflare"
subcategory: ""
description: |-
Provides a Content Scanning resource to be used for managing the status of the Content Scanning feature within a specific zone.
---

# cloudflare_content_scanning (Resource)

Provides a Content Scanning resource to be used for managing the status of the Content Scanning feature within a specific zone.

## Example Usage

```terraform
# Enable Content Scanning
resource "cloudflare_content_scanning" "example" {
zone_id = "399c6f4950c01a5a141b99ff7fbcbd8b"
enabled = true
}
```
<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `enabled` (Boolean) State of the Content Scanning feature
- `zone_id` (String) The zone identifier to target for the resource.

## Import

Import is supported using the following syntax:

```shell
terraform import cloudflare_content_scanning.example <zone_id>
```
1 change: 1 addition & 0 deletions examples/resources/cloudflare_content_scanning/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import cloudflare_content_scanning.example <zone_id>
5 changes: 5 additions & 0 deletions examples/resources/cloudflare_content_scanning/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Enable Content Scanning
resource "cloudflare_content_scanning" "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 @@ -18,6 +18,7 @@ import (
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/access_mutual_tls_hostname_settings"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/api_token_permissions_groups"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/cloud_connector_rules"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/content_scanning"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/content_scanning_expression"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/d1"
"github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/dcv_delegation"
Expand Down Expand Up @@ -396,6 +397,7 @@ func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Re
zero_trust_infrastructure_access_target.NewResource,
leaked_credential_check.NewResource,
leaked_credential_check_rule.NewResource,
content_scanning.NewResource,
content_scanning_expression.NewResource,
}
}
Expand Down
8 changes: 8 additions & 0 deletions internal/framework/service/content_scanning/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package content_scanning

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

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

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 = &ContentScanningResource{}
)

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

type ContentScanningResource struct {
client *muxclient.Client
}

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

func (r *ContentScanningResource) 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 *ContentScanningResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan ContentScanningModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
zoneID := cloudflare.ZoneIdentifier(plan.ZoneID.ValueString())
if plan.Enabled.ValueBool() {
params := cloudflare.ContentScanningEnableParams{}
_, err := r.client.V1.ContentScanningEnable(ctx, zoneID, params)
if err != nil {
resp.Diagnostics.AddError("Error enabling (Create) Content Scanning", err.Error())
return
}
} else {
params := cloudflare.ContentScanningDisableParams{}
_, err := r.client.V1.ContentScanningDisable(ctx, zoneID, params)
if err != nil {
resp.Diagnostics.AddError("Error disabling (Create) Content Scanning", err.Error())
return
}
}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
}

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

zoneID := state.ZoneID.ValueString()
status, err := r.client.V1.ContentScanningStatus(ctx, cloudflare.ZoneIdentifier(zoneID), cloudflare.ContentScanningStatusParams{})
if err != nil {
resp.Diagnostics.AddError("Error reading Content Scanning status", err.Error())
return
}
switch status.Result.Value {
case "enabled":
state.Enabled = types.BoolValue(true)
case "disabled":
state.Enabled = types.BoolValue(false)
default:
resp.Diagnostics.AddError("Unrecognized state", fmt.Sprintf("Unrecognized state = %s for Content Scanning", status.Result.Value))
return
}

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

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

zoneID := cloudflare.ZoneIdentifier(plan.ZoneID.ValueString())
if plan.Enabled.ValueBool() {
params := cloudflare.ContentScanningEnableParams{}
_, err := r.client.V1.ContentScanningEnable(ctx, zoneID, params)
if err != nil {
resp.Diagnostics.AddError("Error enabling (Update) Content Scanning", err.Error())
return
}
} else {
params := cloudflare.ContentScanningDisableParams{}
_, err := r.client.V1.ContentScanningDisable(ctx, zoneID, params)
if err != nil {
resp.Diagnostics.AddError("Error disabling (Update) Content Scanning", err.Error())
return
}
}
diags = resp.State.Set(ctx, &plan)
resp.Diagnostics.Append(diags...)
}

// Delete disables the Content Scanning feature.
func (r *ContentScanningResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state ContentScanningModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

zoneID := cloudflare.ZoneIdentifier(state.ZoneID.ValueString())
params := cloudflare.ContentScanningDisableParams{}
_, err := r.client.V1.ContentScanningDisable(ctx, zoneID, params)
if err != nil {
resp.Diagnostics.AddError("Error disabling (Update) Content Scanning", err.Error())
return
}
}

func (r *ContentScanningResource) 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 Content Scanning feature
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("zone_id"), req.ID)...)
}
89 changes: 89 additions & 0 deletions internal/framework/service/content_scanning/resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package content_scanning_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_content_scanning", &resource.Sweeper{
Name: "cloudflare_content_scanning",
F: testSweepCloudflareCS,
})
}

func testSweepCloudflareCS(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.ContentScanningStatus(ctx, cfv1.ZoneIdentifier(zoneID), cfv1.ContentScanningStatusParams{})
if err != nil {
tflog.Error(ctx, fmt.Sprintf("Failed to GET Content Scanning status: %s", err))
}

if status.Result.Value == "disabled" {
log.Print("[DEBUG] Content Scanning already disabled")
return nil
}
_, err = client.ContentScanningDisable(ctx, cfv1.ZoneIdentifier(zoneID), cfv1.ContentScanningDisableParams{})
if err != nil {
tflog.Error(ctx, fmt.Sprintf("Failed to disable Content Scanning: %s", err))
return err
}

return nil
}

func TestAccCloudflareContentScanning_Basic(t *testing.T) {
rnd := utils.GenerateRandomResourceName()
name := fmt.Sprintf("cloudflare_content_scanning.%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: testAccContentScanningSimple(rnd, zoneID, "true"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "enabled", "true"),
),
},
{
Config: testAccContentScanningSimple(rnd, zoneID, "false"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "enabled", "false"),
),
},
},
})
}

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

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 *ContentScanningResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Provides a Content Scanning resource to be used for managing the status of the Content Scanning feature 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 Content Scanning feature",
Required: true,
},
},
}
}

0 comments on commit 04ef12b

Please sign in to comment.