diff --git a/.changelog/2852.txt b/.changelog/2852.txt new file mode 100644 index 0000000000..65c9841205 --- /dev/null +++ b/.changelog/2852.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +cloudflare_api_shield_operation_schema_validation_settings +``` diff --git a/docs/resources/api_shield_operation_schema_validation_settings.md b/docs/resources/api_shield_operation_schema_validation_settings.md new file mode 100644 index 0000000000..85ce42b90e --- /dev/null +++ b/docs/resources/api_shield_operation_schema_validation_settings.md @@ -0,0 +1,44 @@ +--- +page_title: "cloudflare_api_shield_operation_schema_validation_settings Resource - Cloudflare" +subcategory: "" +description: |- + Provides a resource to manage operation-level settings in API Shield Schema Validation 2.0. +--- + +# cloudflare_api_shield_operation_schema_validation_settings (Resource) + +Provides a resource to manage operation-level settings in API Shield Schema Validation 2.0. + +## Example Usage + +```terraform +resource "cloudflare_api_shield_operation" "example" { + zone_id = "0da42c8d2132a9ddaf714f9e7c920711" + method = "GET" + host = "api.example.com" + endpoint = "/path" +} + +resource "cloudflare_api_shield_operation_schema_validation_settings" "example" { + zone_id = "0da42c8d2132a9ddaf714f9e7c920711" + operation_id = cloudflare_api_shield_operation.example.id + mitigation_action = "block" +} +``` + +## Schema + +### Required + +- `operation_id` (String) Operation ID these settings should apply to. **Modifying this attribute will force creation of a new resource.** +- `zone_id` (String) The zone identifier to target for the resource. **Modifying this attribute will force creation of a new resource.** + +### Optional + +- `mitigation_action` (String) The mitigation action to apply to this operation. + +### Read-Only + +- `id` (String) The ID of this resource. + + diff --git a/examples/resources/cloudflare_api_shield_operation_schema_validation_settings/resource.tf b/examples/resources/cloudflare_api_shield_operation_schema_validation_settings/resource.tf new file mode 100644 index 0000000000..d619eceddd --- /dev/null +++ b/examples/resources/cloudflare_api_shield_operation_schema_validation_settings/resource.tf @@ -0,0 +1,12 @@ +resource "cloudflare_api_shield_operation" "example" { + zone_id = "0da42c8d2132a9ddaf714f9e7c920711" + method = "GET" + host = "api.example.com" + endpoint = "/path" +} + +resource "cloudflare_api_shield_operation_schema_validation_settings" "example" { + zone_id = "0da42c8d2132a9ddaf714f9e7c920711" + operation_id = cloudflare_api_shield_operation.example.id + mitigation_action = "block" +} diff --git a/internal/sdkv2provider/provider.go b/internal/sdkv2provider/provider.go index 04fa9242b5..2e91cda94f 100644 --- a/internal/sdkv2provider/provider.go +++ b/internal/sdkv2provider/provider.go @@ -181,114 +181,115 @@ func New(version string) func() *schema.Provider { }, ResourcesMap: map[string]*schema.Resource{ - "cloudflare_access_application": resourceCloudflareAccessApplication(), - "cloudflare_access_ca_certificate": resourceCloudflareAccessCACertificate(), - "cloudflare_access_group": resourceCloudflareAccessGroup(), - "cloudflare_access_identity_provider": resourceCloudflareAccessIdentityProvider(), - "cloudflare_access_custom_page": resourceCloudflareAccessCustomPage(), - "cloudflare_access_keys_configuration": resourceCloudflareAccessKeysConfiguration(), - "cloudflare_access_mutual_tls_certificate": resourceCloudflareAccessMutualTLSCertificate(), - "cloudflare_access_organization": resourceCloudflareAccessOrganization(), - "cloudflare_access_policy": resourceCloudflareAccessPolicy(), - "cloudflare_access_rule": resourceCloudflareAccessRule(), - "cloudflare_access_service_token": resourceCloudflareAccessServiceToken(), - "cloudflare_access_tag": resourceCloudflareAccessTag(), - "cloudflare_account_member": resourceCloudflareAccountMember(), - "cloudflare_account": resourceCloudflareAccount(), - "cloudflare_address_map": resourceCloudflareAddressMap(), - "cloudflare_api_shield": resourceCloudflareAPIShield(), - "cloudflare_api_shield_operation": resourceCloudflareAPIShieldOperation(), - "cloudflare_api_shield_schema": resourceCloudflareAPIShieldSchemas(), - "cloudflare_api_shield_schema_validation_settings": resourceCloudflareAPIShieldSchemaValidationSettings(), - "cloudflare_api_token": resourceCloudflareApiToken(), - "cloudflare_argo": resourceCloudflareArgo(), - "cloudflare_authenticated_origin_pulls_certificate": resourceCloudflareAuthenticatedOriginPullsCertificate(), - "cloudflare_authenticated_origin_pulls": resourceCloudflareAuthenticatedOriginPulls(), - "cloudflare_byo_ip_prefix": resourceCloudflareBYOIPPrefix(), - "cloudflare_certificate_pack": resourceCloudflareCertificatePack(), - "cloudflare_custom_hostname_fallback_origin": resourceCloudflareCustomHostnameFallbackOrigin(), - "cloudflare_custom_hostname": resourceCloudflareCustomHostname(), - "cloudflare_custom_pages": resourceCloudflareCustomPages(), - "cloudflare_custom_ssl": resourceCloudflareCustomSsl(), - "cloudflare_device_dex_test": resourceCloudflareDeviceDexTest(), - "cloudflare_device_managed_networks": resourceCloudflareDeviceManagedNetworks(), - "cloudflare_device_policy_certificates": resourceCloudflareDevicePolicyCertificates(), - "cloudflare_device_posture_integration": resourceCloudflareDevicePostureIntegration(), - "cloudflare_device_posture_rule": resourceCloudflareDevicePostureRule(), - "cloudflare_device_settings_policy": resourceCloudflareDeviceSettingsPolicy(), - "cloudflare_dlp_profile": resourceCloudflareDLPProfile(), - "cloudflare_email_routing_address": resourceCloudflareEmailRoutingAddress(), - "cloudflare_email_routing_catch_all": resourceCloudflareEmailRoutingCatchAll(), - "cloudflare_email_routing_rule": resourceCloudflareEmailRoutingRule(), - "cloudflare_email_routing_settings": resourceCloudflareEmailRoutingSettings(), - "cloudflare_fallback_domain": resourceCloudflareFallbackDomain(), - "cloudflare_filter": resourceCloudflareFilter(), - "cloudflare_firewall_rule": resourceCloudflareFirewallRule(), - "cloudflare_gre_tunnel": resourceCloudflareGRETunnel(), - "cloudflare_healthcheck": resourceCloudflareHealthcheck(), - "cloudflare_hostname_tls_setting": resourceCloudflareHostnameTLSSetting(), - "cloudflare_hostname_tls_setting_ciphers": resourceCloudflareHostnameTLSSettingCiphers(), - "cloudflare_ipsec_tunnel": resourceCloudflareIPsecTunnel(), - "cloudflare_list_item": resourceCloudflareListItem(), - "cloudflare_list": resourceCloudflareList(), - "cloudflare_load_balancer_monitor": resourceCloudflareLoadBalancerMonitor(), - "cloudflare_load_balancer_pool": resourceCloudflareLoadBalancerPool(), - "cloudflare_load_balancer": resourceCloudflareLoadBalancer(), - "cloudflare_logpull_retention": resourceCloudflareLogpullRetention(), - "cloudflare_logpush_job": resourceCloudflareLogpushJob(), - "cloudflare_logpush_ownership_challenge": resourceCloudflareLogpushOwnershipChallenge(), - "cloudflare_magic_firewall_ruleset": resourceCloudflareMagicFirewallRuleset(), - "cloudflare_managed_headers": resourceCloudflareManagedHeaders(), - "cloudflare_mtls_certificate": resourceCloudflareMTLSCertificate(), - "cloudflare_notification_policy_webhooks": resourceCloudflareNotificationPolicyWebhook(), - "cloudflare_notification_policy": resourceCloudflareNotificationPolicy(), - "cloudflare_observatory_scheduled_test": resourceCloudflareObservatoryScheduledTest(), - "cloudflare_origin_ca_certificate": resourceCloudflareOriginCACertificate(), - "cloudflare_page_rule": resourceCloudflarePageRule(), - "cloudflare_pages_domain": resourceCloudflarePagesDomain(), - "cloudflare_pages_project": resourceCloudflarePagesProject(), - "cloudflare_queue": resourceCloudflareQueue(), - "cloudflare_rate_limit": resourceCloudflareRateLimit(), - "cloudflare_record": resourceCloudflareRecord(), - "cloudflare_regional_hostname": resourceCloudflareRegionalHostname(), - "cloudflare_regional_tiered_cache": resourceCloudflareRegionalTieredCache(), - "cloudflare_spectrum_application": resourceCloudflareSpectrumApplication(), - "cloudflare_split_tunnel": resourceCloudflareSplitTunnel(), - "cloudflare_static_route": resourceCloudflareStaticRoute(), - "cloudflare_bot_management": resourceCloudflareBotManagement(), - "cloudflare_teams_account": resourceCloudflareTeamsAccount(), - "cloudflare_teams_list": resourceCloudflareTeamsList(), - "cloudflare_teams_location": resourceCloudflareTeamsLocation(), - "cloudflare_teams_proxy_endpoint": resourceCloudflareTeamsProxyEndpoint(), - "cloudflare_teams_rule": resourceCloudflareTeamsRule(), - "cloudflare_tiered_cache": resourceCloudflareTieredCache(), - "cloudflare_total_tls": resourceCloudflareTotalTLS(), - "cloudflare_tunnel_config": resourceCloudflareTunnelConfig(), - "cloudflare_tunnel_route": resourceCloudflareTunnelRoute(), - "cloudflare_tunnel_virtual_network": resourceCloudflareTunnelVirtualNetwork(), - "cloudflare_tunnel": resourceCloudflareTunnel(), - "cloudflare_url_normalization_settings": resourceCloudflareURLNormalizationSettings(), - "cloudflare_user_agent_blocking_rule": resourceCloudflareUserAgentBlockingRules(), - "cloudflare_waiting_room_event": resourceCloudflareWaitingRoomEvent(), - "cloudflare_waiting_room_rules": resourceCloudflareWaitingRoomRules(), - "cloudflare_waiting_room_settings": resourceCloudflareWaitingRoomSettings(), - "cloudflare_waiting_room": resourceCloudflareWaitingRoom(), - "cloudflare_web3_hostname": resourceCloudflareWeb3Hostname(), - "cloudflare_web_analytics_rule": resourceCloudflareWebAnalyticsRule(), - "cloudflare_web_analytics_site": resourceCloudflareWebAnalyticsSite(), - "cloudflare_worker_cron_trigger": resourceCloudflareWorkerCronTrigger(), - "cloudflare_worker_domain": resourceCloudflareWorkerDomain(), - "cloudflare_worker_route": resourceCloudflareWorkerRoute(), - "cloudflare_worker_script": resourceCloudflareWorkerScript(), - "cloudflare_workers_kv_namespace": resourceCloudflareWorkersKVNamespace(), - "cloudflare_workers_kv": resourceCloudflareWorkerKV(), - "cloudflare_zone_cache_reserve": resourceCloudflareZoneCacheReserve(), - "cloudflare_zone_cache_variants": resourceCloudflareZoneCacheVariants(), - "cloudflare_zone_dnssec": resourceCloudflareZoneDNSSEC(), - "cloudflare_zone_lockdown": resourceCloudflareZoneLockdown(), - "cloudflare_zone_settings_override": resourceCloudflareZoneSettingsOverride(), - "cloudflare_zone_hold": resourceCloudflareZoneHold(), - "cloudflare_zone": resourceCloudflareZone(), + "cloudflare_access_application": resourceCloudflareAccessApplication(), + "cloudflare_access_ca_certificate": resourceCloudflareAccessCACertificate(), + "cloudflare_access_group": resourceCloudflareAccessGroup(), + "cloudflare_access_identity_provider": resourceCloudflareAccessIdentityProvider(), + "cloudflare_access_custom_page": resourceCloudflareAccessCustomPage(), + "cloudflare_access_keys_configuration": resourceCloudflareAccessKeysConfiguration(), + "cloudflare_access_mutual_tls_certificate": resourceCloudflareAccessMutualTLSCertificate(), + "cloudflare_access_organization": resourceCloudflareAccessOrganization(), + "cloudflare_access_policy": resourceCloudflareAccessPolicy(), + "cloudflare_access_rule": resourceCloudflareAccessRule(), + "cloudflare_access_service_token": resourceCloudflareAccessServiceToken(), + "cloudflare_access_tag": resourceCloudflareAccessTag(), + "cloudflare_account_member": resourceCloudflareAccountMember(), + "cloudflare_account": resourceCloudflareAccount(), + "cloudflare_address_map": resourceCloudflareAddressMap(), + "cloudflare_api_shield": resourceCloudflareAPIShield(), + "cloudflare_api_shield_operation": resourceCloudflareAPIShieldOperation(), + "cloudflare_api_shield_operation_schema_validation_settings": resourceCloudflareAPIShieldOperationSchemaValidationSettings(), + "cloudflare_api_shield_schema": resourceCloudflareAPIShieldSchemas(), + "cloudflare_api_shield_schema_validation_settings": resourceCloudflareAPIShieldSchemaValidationSettings(), + "cloudflare_api_token": resourceCloudflareApiToken(), + "cloudflare_argo": resourceCloudflareArgo(), + "cloudflare_authenticated_origin_pulls_certificate": resourceCloudflareAuthenticatedOriginPullsCertificate(), + "cloudflare_authenticated_origin_pulls": resourceCloudflareAuthenticatedOriginPulls(), + "cloudflare_byo_ip_prefix": resourceCloudflareBYOIPPrefix(), + "cloudflare_certificate_pack": resourceCloudflareCertificatePack(), + "cloudflare_custom_hostname_fallback_origin": resourceCloudflareCustomHostnameFallbackOrigin(), + "cloudflare_custom_hostname": resourceCloudflareCustomHostname(), + "cloudflare_custom_pages": resourceCloudflareCustomPages(), + "cloudflare_custom_ssl": resourceCloudflareCustomSsl(), + "cloudflare_device_dex_test": resourceCloudflareDeviceDexTest(), + "cloudflare_device_managed_networks": resourceCloudflareDeviceManagedNetworks(), + "cloudflare_device_policy_certificates": resourceCloudflareDevicePolicyCertificates(), + "cloudflare_device_posture_integration": resourceCloudflareDevicePostureIntegration(), + "cloudflare_device_posture_rule": resourceCloudflareDevicePostureRule(), + "cloudflare_device_settings_policy": resourceCloudflareDeviceSettingsPolicy(), + "cloudflare_dlp_profile": resourceCloudflareDLPProfile(), + "cloudflare_email_routing_address": resourceCloudflareEmailRoutingAddress(), + "cloudflare_email_routing_catch_all": resourceCloudflareEmailRoutingCatchAll(), + "cloudflare_email_routing_rule": resourceCloudflareEmailRoutingRule(), + "cloudflare_email_routing_settings": resourceCloudflareEmailRoutingSettings(), + "cloudflare_fallback_domain": resourceCloudflareFallbackDomain(), + "cloudflare_filter": resourceCloudflareFilter(), + "cloudflare_firewall_rule": resourceCloudflareFirewallRule(), + "cloudflare_gre_tunnel": resourceCloudflareGRETunnel(), + "cloudflare_healthcheck": resourceCloudflareHealthcheck(), + "cloudflare_hostname_tls_setting": resourceCloudflareHostnameTLSSetting(), + "cloudflare_hostname_tls_setting_ciphers": resourceCloudflareHostnameTLSSettingCiphers(), + "cloudflare_ipsec_tunnel": resourceCloudflareIPsecTunnel(), + "cloudflare_list_item": resourceCloudflareListItem(), + "cloudflare_list": resourceCloudflareList(), + "cloudflare_load_balancer_monitor": resourceCloudflareLoadBalancerMonitor(), + "cloudflare_load_balancer_pool": resourceCloudflareLoadBalancerPool(), + "cloudflare_load_balancer": resourceCloudflareLoadBalancer(), + "cloudflare_logpull_retention": resourceCloudflareLogpullRetention(), + "cloudflare_logpush_job": resourceCloudflareLogpushJob(), + "cloudflare_logpush_ownership_challenge": resourceCloudflareLogpushOwnershipChallenge(), + "cloudflare_magic_firewall_ruleset": resourceCloudflareMagicFirewallRuleset(), + "cloudflare_managed_headers": resourceCloudflareManagedHeaders(), + "cloudflare_mtls_certificate": resourceCloudflareMTLSCertificate(), + "cloudflare_notification_policy_webhooks": resourceCloudflareNotificationPolicyWebhook(), + "cloudflare_notification_policy": resourceCloudflareNotificationPolicy(), + "cloudflare_observatory_scheduled_test": resourceCloudflareObservatoryScheduledTest(), + "cloudflare_origin_ca_certificate": resourceCloudflareOriginCACertificate(), + "cloudflare_page_rule": resourceCloudflarePageRule(), + "cloudflare_pages_domain": resourceCloudflarePagesDomain(), + "cloudflare_pages_project": resourceCloudflarePagesProject(), + "cloudflare_queue": resourceCloudflareQueue(), + "cloudflare_rate_limit": resourceCloudflareRateLimit(), + "cloudflare_record": resourceCloudflareRecord(), + "cloudflare_regional_hostname": resourceCloudflareRegionalHostname(), + "cloudflare_regional_tiered_cache": resourceCloudflareRegionalTieredCache(), + "cloudflare_spectrum_application": resourceCloudflareSpectrumApplication(), + "cloudflare_split_tunnel": resourceCloudflareSplitTunnel(), + "cloudflare_static_route": resourceCloudflareStaticRoute(), + "cloudflare_bot_management": resourceCloudflareBotManagement(), + "cloudflare_teams_account": resourceCloudflareTeamsAccount(), + "cloudflare_teams_list": resourceCloudflareTeamsList(), + "cloudflare_teams_location": resourceCloudflareTeamsLocation(), + "cloudflare_teams_proxy_endpoint": resourceCloudflareTeamsProxyEndpoint(), + "cloudflare_teams_rule": resourceCloudflareTeamsRule(), + "cloudflare_tiered_cache": resourceCloudflareTieredCache(), + "cloudflare_total_tls": resourceCloudflareTotalTLS(), + "cloudflare_tunnel_config": resourceCloudflareTunnelConfig(), + "cloudflare_tunnel_route": resourceCloudflareTunnelRoute(), + "cloudflare_tunnel_virtual_network": resourceCloudflareTunnelVirtualNetwork(), + "cloudflare_tunnel": resourceCloudflareTunnel(), + "cloudflare_url_normalization_settings": resourceCloudflareURLNormalizationSettings(), + "cloudflare_user_agent_blocking_rule": resourceCloudflareUserAgentBlockingRules(), + "cloudflare_waiting_room_event": resourceCloudflareWaitingRoomEvent(), + "cloudflare_waiting_room_rules": resourceCloudflareWaitingRoomRules(), + "cloudflare_waiting_room_settings": resourceCloudflareWaitingRoomSettings(), + "cloudflare_waiting_room": resourceCloudflareWaitingRoom(), + "cloudflare_web3_hostname": resourceCloudflareWeb3Hostname(), + "cloudflare_web_analytics_rule": resourceCloudflareWebAnalyticsRule(), + "cloudflare_web_analytics_site": resourceCloudflareWebAnalyticsSite(), + "cloudflare_worker_cron_trigger": resourceCloudflareWorkerCronTrigger(), + "cloudflare_worker_domain": resourceCloudflareWorkerDomain(), + "cloudflare_worker_route": resourceCloudflareWorkerRoute(), + "cloudflare_worker_script": resourceCloudflareWorkerScript(), + "cloudflare_workers_kv_namespace": resourceCloudflareWorkersKVNamespace(), + "cloudflare_workers_kv": resourceCloudflareWorkerKV(), + "cloudflare_zone_cache_reserve": resourceCloudflareZoneCacheReserve(), + "cloudflare_zone_cache_variants": resourceCloudflareZoneCacheVariants(), + "cloudflare_zone_dnssec": resourceCloudflareZoneDNSSEC(), + "cloudflare_zone_lockdown": resourceCloudflareZoneLockdown(), + "cloudflare_zone_settings_override": resourceCloudflareZoneSettingsOverride(), + "cloudflare_zone_hold": resourceCloudflareZoneHold(), + "cloudflare_zone": resourceCloudflareZone(), }, } diff --git a/internal/sdkv2provider/resource_cloudflare_api_shield_operation_schema_validation_settings.go b/internal/sdkv2provider/resource_cloudflare_api_shield_operation_schema_validation_settings.go new file mode 100644 index 0000000000..346c64953c --- /dev/null +++ b/internal/sdkv2provider/resource_cloudflare_api_shield_operation_schema_validation_settings.go @@ -0,0 +1,111 @@ +package sdkv2provider + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + + "github.com/MakeNowJust/heredoc/v2" + "github.com/cloudflare/cloudflare-go" + "github.com/cloudflare/terraform-provider-cloudflare/internal/consts" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudflareAPIShieldOperationSchemaValidationSettings() *schema.Resource { + return &schema.Resource{ + Schema: resourceCloudflareAPIShieldOperationSchemaValidationSettingsSchema(), + CreateContext: resourceCloudflareAPIShieldOperationSchemaValidationSettingsCreate, + ReadContext: resourceCloudflareAPIShieldOperationSchemaValidationSettingsRead, + UpdateContext: resourceCloudflareAPIShieldOperationSchemaValidationSettingsUpdate, + DeleteContext: resourceCloudflareAPIShieldOperationSchemaValidationSettingsDelete, + Importer: &schema.ResourceImporter{ + StateContext: nil, + }, + Description: heredoc.Doc(` + Provides a resource to manage operation-level settings in API Shield Schema Validation 2.0. + `), + } +} + +func resourceCloudflareAPIShieldOperationSchemaValidationSettingsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return resourceCloudflareAPIShieldOperationSchemaValidationSettingsUpdate(ctx, d, meta) +} + +func resourceCloudflareAPIShieldOperationSchemaValidationSettingsUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + zoneID := d.Get(consts.ZoneIDSchemaKey).(string) + + operationID := d.Get("operation_id").(string) + + var mitigationAction *string + if ma, ok := d.GetOk("mitigation_action"); ok { + mitigationAction = cloudflare.StringPtr(ma.(string)) + } + + _, err := client.UpdateAPIShieldOperationSchemaValidationSettings( + ctx, + cloudflare.ZoneIdentifier(zoneID), + cloudflare.UpdateAPIShieldOperationSchemaValidationSettings{ + operationID: cloudflare.APIShieldOperationSchemaValidationSettings{ + MitigationAction: mitigationAction, + }, + }, + ) + + if err != nil { + return diag.FromErr(errors.Wrap(err, "failed to create API Shield Operation Schema Validation Settings")) + } + + // Settings are configured at the operation level so using the operationID as the ID + d.SetId(operationID) + return resourceCloudflareAPIShieldOperationSchemaValidationSettingsRead(ctx, d, meta) +} + +func resourceCloudflareAPIShieldOperationSchemaValidationSettingsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + zoneID := d.Get(consts.ZoneIDSchemaKey).(string) + + operationID := d.Get("operation_id").(string) + settings, err := client.GetAPIShieldOperationSchemaValidationSettings( + ctx, + cloudflare.ZoneIdentifier(zoneID), + cloudflare.GetAPIShieldOperationSchemaValidationSettingsParams{ + OperationID: operationID, + }, + ) + + if err != nil { + return diag.FromErr(fmt.Errorf("failed to fetch API Shield Operation Schema Validation Settings: %w", err)) + } + + if err := d.Set("mitigation_action", settings.MitigationAction); err != nil { + return diag.FromErr(err) + } + + // Settings are configured at the operation level so using the zoneID as the ID + d.SetId(operationID) + return nil +} + +func resourceCloudflareAPIShieldOperationSchemaValidationSettingsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + zoneID := d.Get(consts.ZoneIDSchemaKey).(string) + operationID := d.Get("operation_id").(string) + + // There is no DELETE endpoint for schema validation settings, + // so terraform should reset the state to default settings + _, err := client.UpdateAPIShieldOperationSchemaValidationSettings( + ctx, + cloudflare.ZoneIdentifier(zoneID), + cloudflare.UpdateAPIShieldOperationSchemaValidationSettings{ + operationID: cloudflare.APIShieldOperationSchemaValidationSettings{}, + }, + ) + if err != nil { + return diag.FromErr(fmt.Errorf("failed to delete API Shield Operation Schema Validation Settings: %w", err)) + } + + return nil +} diff --git a/internal/sdkv2provider/resource_cloudflare_api_shield_operation_schema_validation_settings_test.go b/internal/sdkv2provider/resource_cloudflare_api_shield_operation_schema_validation_settings_test.go new file mode 100644 index 0000000000..dac6cc35d3 --- /dev/null +++ b/internal/sdkv2provider/resource_cloudflare_api_shield_operation_schema_validation_settings_test.go @@ -0,0 +1,95 @@ +package sdkv2provider + +import ( + "fmt" + "os" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/consts" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudflareAPIShieldOperationSchemaValidationSettings_Create(t *testing.T) { + // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the API token + // endpoint does not yet support the API tokens without an explicit scope. + if os.Getenv("CLOUDFLARE_API_TOKEN") != "" { + t.Setenv("CLOUDFLARE_API_TOKEN", "") + } + + rnd := generateRandomResourceName() + resourceID := "cloudflare_api_shield_operation_schema_validation_settings." + rnd + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + + block := "block" + none := "none" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareAPIShieldOperationSchemaValidationSettingsMitigation(rnd, zoneID, &block), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceID, consts.ZoneIDSchemaKey, zoneID), + resource.TestCheckResourceAttr(resourceID, "mitigation_action", "block"), + ), + }, + { + Config: testAccCloudflareAPIShieldOperationSchemaValidationSettingsMitigation(rnd, zoneID, nil), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceID, consts.ZoneIDSchemaKey, zoneID), + resource.TestCheckResourceAttr(resourceID, "mitigation_action", ""), + ), + }, + { + Config: testAccCloudflareAPIShieldOperationSchemaValidationSettingsMitigation(rnd, zoneID, &none), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceID, consts.ZoneIDSchemaKey, zoneID), + resource.TestCheckResourceAttr(resourceID, "mitigation_action", "none"), + ), + }, + { + Config: testAccCloudflareAPIShieldOperationSchemaValidationSettingsNoMitigation(rnd, zoneID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceID, consts.ZoneIDSchemaKey, zoneID), + resource.TestCheckResourceAttr(resourceID, "mitigation_action", ""), + ), + }, + }, + }) +} + +func testAccCloudflareAPIShieldOperationSchemaValidationSettingsMitigation(resourceName, zone string, mitigation *string) string { + action := "null" + if mitigation != nil { + action = fmt.Sprintf("\"%s\"", *mitigation) + } + + return fmt.Sprintf(` + resource "cloudflare_api_shield_operation" "terraform_test_acc_operation" { + zone_id = "%[2]s" + host = "foo.com" + method = "GET" + endpoint = "/api" + } + resource "cloudflare_api_shield_operation_schema_validation_settings" "%[1]s" { + zone_id = "%[2]s" + operation_id = cloudflare_api_shield_operation.terraform_test_acc_operation.id + mitigation_action = %[3]s + } +`, resourceName, zone, action) +} + +func testAccCloudflareAPIShieldOperationSchemaValidationSettingsNoMitigation(resourceName, zone string) string { + return fmt.Sprintf(` + resource "cloudflare_api_shield_operation" "terraform_test_acc_operation" { + zone_id = "%[2]s" + host = "foo.com" + method = "GET" + endpoint = "/api" + } + resource "cloudflare_api_shield_operation_schema_validation_settings" "%[1]s" { + zone_id = "%[2]s" + operation_id = cloudflare_api_shield_operation.terraform_test_acc_operation.id + } +`, resourceName, zone) +} diff --git a/internal/sdkv2provider/schema_cloudflare_api_shield_operation_schema_validation_settings.go b/internal/sdkv2provider/schema_cloudflare_api_shield_operation_schema_validation_settings.go new file mode 100644 index 0000000000..19d03431a6 --- /dev/null +++ b/internal/sdkv2provider/schema_cloudflare_api_shield_operation_schema_validation_settings.go @@ -0,0 +1,28 @@ +package sdkv2provider + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/consts" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudflareAPIShieldOperationSchemaValidationSettingsSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + consts.ZoneIDSchemaKey: { + Description: consts.ZoneIDSchemaDescription, + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "operation_id": { + Description: "Operation ID these settings should apply to", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "mitigation_action": { + Description: "The mitigation action to apply to this operation", + Type: schema.TypeString, + Optional: true, + }, + } +}