From b275baf0e3b4b4c315c2f9ec945c34aa33823416 Mon Sep 17 00:00:00 2001 From: Diogo Sousa Date: Mon, 17 Apr 2023 16:27:21 +0100 Subject: [PATCH 1/3] Added support for the `http_response_compression` phase and `compress_response` action. --- .changelog/2372.txt | 7 ++ docs/data-sources/rulesets.md | 2 +- docs/resources/access_organization.md | 2 +- docs/resources/ruleset.md | 42 ++++++-- .../resources/cloudflare_ruleset/resource.tf | 19 ++++ internal/framework/service/rulesets/model.go | 99 ++++++++++--------- .../framework/service/rulesets/resource.go | 22 +++++ .../service/rulesets/resource_test.go | 58 +++++++++++ internal/framework/service/rulesets/schema.go | 17 ++++ .../resource_cloudflare_workers_script.go | 24 ++--- 10 files changed, 224 insertions(+), 68 deletions(-) create mode 100644 .changelog/2372.txt diff --git a/.changelog/2372.txt b/.changelog/2372.txt new file mode 100644 index 0000000000..3db90d09b4 --- /dev/null +++ b/.changelog/2372.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/cloudflare_ruleset: add support for the `http_response_compression` phase +``` + +```release-note:enhancement +resource/cloudflare_ruleset: add support for the `compress_response` action +``` diff --git a/docs/data-sources/rulesets.md b/docs/data-sources/rulesets.md index f4fa19ec32..1e2869e197 100644 --- a/docs/data-sources/rulesets.md +++ b/docs/data-sources/rulesets.md @@ -44,7 +44,7 @@ Optional: - `id` (String) The ID of the Ruleset to target. - `kind` (String) Type of Ruleset to create. Available values: `custom`, `managed`, `root`, `schema`, `zone`. - `name` (String) Name of the ruleset. -- `phase` (String) Point in the request/response lifecycle where the ruleset will be created. Available values: `ddos_l4`, `ddos_l7`, `http_custom_errors`, `http_log_custom_fields`, `http_request_cache_settings`, `http_request_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_late_transform_managed`, `http_request_main`, `http_request_origin`, `http_request_dynamic_redirect`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `http_response_headers_transform_managed`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`, `http_config_settings`. +- `phase` (String) Point in the request/response lifecycle where the ruleset will be created. Available values: `ddos_l4`, `ddos_l7`, `http_custom_errors`, `http_log_custom_fields`, `http_request_cache_settings`, `http_request_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_late_transform_managed`, `http_request_main`, `http_request_origin`, `http_request_dynamic_redirect`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `http_response_headers_transform_managed`, `http_response_compression`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`, `http_config_settings`. - `version` (String) Version of the ruleset to filter on. diff --git a/docs/resources/access_organization.md b/docs/resources/access_organization.md index 5115064cde..a63845e44e 100644 --- a/docs/resources/access_organization.md +++ b/docs/resources/access_organization.md @@ -39,12 +39,12 @@ resource "cloudflare_access_organization" "example" { ### Optional - `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`. +- `auto_redirect_to_identity` (Boolean) When set to true, users skip the identity provider selection step during login. - `is_ui_read_only` (Boolean) When set to true, this will disable all editing of Access resources via the Zero Trust Dashboard. - `login_design` (Block List) (see [below for nested schema](#nestedblock--login_design)) - `name` (String) The name of your Zero Trust organization. - `ui_read_only_toggle_reason` (String) A description of the reason why the UI read only field is being toggled. - `user_seat_expiration_inactive_time` (String) The amount of time a user seat is inactive before it expires. When the user seat exceeds the set time of inactivity, the user is removed as an active seat and no longer counts against your Teams seat count. Must be in the format `300ms` or `2h45m`. -- `auto_redirect_to_identity` (Boolean) When set to true, users skip the identity provider selection step during login. - `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`. ### Read-Only diff --git a/docs/resources/ruleset.md b/docs/resources/ruleset.md index 18eddb1662..545e5188a8 100644 --- a/docs/resources/ruleset.md +++ b/docs/resources/ruleset.md @@ -415,6 +415,25 @@ resource "cloudflare_ruleset" "http_config_rules_example" { enabled = true } } + +# Set compress algorithm for response. +resource "cloudflare_ruleset" "response_compress_brotli_html" { + zone_id = "0da42c8d2132a9ddaf714f9e7c920711" + name = "Brotli response compression for HTML" + description = "Response compression ruleset" + kind = "zone" + phase = "http_response_compression" + + rules { + action = "compress_response" + action_parameters { + algorithms = [ { name: "brotli" }, { name: "default" } ] + } + expression = "http.response.content_type.media_type == \"text/html\"" + description = "Prefer brotli compression for HTML" + enabled = true + } +} ``` @@ -424,7 +443,7 @@ resource "cloudflare_ruleset" "http_config_rules_example" { - `kind` (String) Type of Ruleset to create. Available values: `custom`, `managed`, `root`, `schema`, `zone`. - `name` (String) Name of the ruleset. -- `phase` (String) Point in the request/response lifecycle where the ruleset will be created. Available values: `ddos_l4`, `ddos_l7`, `http_custom_errors`, `http_log_custom_fields`, `http_request_cache_settings`, `http_request_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_late_transform_managed`, `http_request_main`, `http_request_origin`, `http_request_dynamic_redirect`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `http_response_headers_transform_managed`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`, `http_config_settings`. +- `phase` (String) Point in the request/response lifecycle where the ruleset will be created. Available values: `ddos_l4`, `ddos_l7`, `http_custom_errors`, `http_log_custom_fields`, `http_request_cache_settings`, `http_request_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_late_transform_managed`, `http_request_main`, `http_request_origin`, `http_request_dynamic_redirect`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `http_response_headers_transform_managed`, `http_response_compression`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`, `http_config_settings`. ### Optional @@ -447,7 +466,7 @@ Required: Optional: -- `action` (String) Action to perform in the ruleset rule. Available values: `allow`, `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `set_config`, `serve_error`, `skip`. +- `action` (String) Action to perform in the ruleset rule. Available values: `allow`, `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `set_config`, `serve_error`, `skip`, `compress_response`. - `action_parameters` (Block List) List of parameters that configure the behavior of the ruleset rule action. (see [below for nested schema](#nestedblock--rules--action_parameters)) - `description` (String) Brief summary of the ruleset rule and its intended use. - `enabled` (Boolean) Whether the rule is active. @@ -464,6 +483,7 @@ Optional: Optional: +- `algorithms` (Block List) Compression algorithms to use in order of preference. (see [below for nested schema](#nestedblock--rules--action_parameters--algorithms)) - `automatic_https_rewrites` (Boolean) Turn on or off Cloudflare Automatic HTTPS rewrites. - `autominify` (Block List) Indicate which file extensions to minify automatically. (see [below for nested schema](#nestedblock--rules--action_parameters--autominify)) - `bic` (Boolean) Inspect the visitor's browser for headers commonly associated with spammers and certain bots. @@ -491,7 +511,7 @@ Optional: - `origin` (Block List) List of properties to change request origin. (see [below for nested schema](#nestedblock--rules--action_parameters--origin)) - `origin_error_page_passthru` (Boolean) Pass-through error page for origin. - `overrides` (Block List) List of override configurations to apply to the ruleset. (see [below for nested schema](#nestedblock--rules--action_parameters--overrides)) -- `phases` (Set of String) Point in the request/response lifecycle where the ruleset will be created. Available values: `ddos_l4`, `ddos_l7`, `http_custom_errors`, `http_log_custom_fields`, `http_request_cache_settings`, `http_request_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_late_transform_managed`, `http_request_main`, `http_request_origin`, `http_request_dynamic_redirect`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `http_response_headers_transform_managed`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`, `http_config_settings`. +- `phases` (Set of String) Point in the request/response lifecycle where the ruleset will be created. Available values: `ddos_l4`, `ddos_l7`, `http_custom_errors`, `http_log_custom_fields`, `http_request_cache_settings`, `http_request_firewall_custom`, `http_request_firewall_managed`, `http_request_late_transform`, `http_request_late_transform_managed`, `http_request_main`, `http_request_origin`, `http_request_dynamic_redirect`, `http_request_redirect`, `http_request_sanitize`, `http_request_transform`, `http_response_firewall_managed`, `http_response_headers_transform`, `http_response_headers_transform_managed`, `http_response_compression`, `magic_transit`, `http_ratelimit`, `http_request_sbfm`, `http_config_settings`. - `polish` (String) Apply options from the Polish feature of the Cloudflare Speed app. - `products` (Set of String) Products to target with the actions. Available values: `bic`, `hot`, `ratelimit`, `securityLevel`, `uablock`, `waf`, `zonelockdown`. - `request_fields` (Set of String) List of request headers to include as part of custom fields logging, in lowercase. @@ -512,6 +532,14 @@ Optional: - `uri` (Block List) List of URI properties to configure for the ruleset rule when performing URL rewrite transformations. (see [below for nested schema](#nestedblock--rules--action_parameters--uri)) - `version` (String) Version of the ruleset to deploy. + +### Nested Schema for `rules.action_parameters.algorithms` + +Required: + +- `name` (String) Name of the compression algorithm to use. + + ### Nested Schema for `rules.action_parameters.autominify` @@ -664,7 +692,7 @@ Optional: - `expression` (String) Use a value dynamically determined by the Firewall Rules expression language based on Wireshark display filters. Refer to the [Firewall Rules language](https://developers.cloudflare.com/firewall/cf-firewall-language) documentation for all available fields, operators, and functions. - `name` (String) Name of the HTTP request header to target. -- `operation` (String) Action to perform on the HTTP request header. Available values: `remove`, `set`. +- `operation` (String) Action to perform on the HTTP request header. Available values: `remove`, `set`, `add`. - `value` (String) Static value to provide as the HTTP request header value. @@ -690,7 +718,7 @@ Optional: Optional: -- `action` (String) Action to perform in the rule-level override. Available values: `allow`, `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `set_config`, `serve_error`, `skip`. +- `action` (String) Action to perform in the rule-level override. Available values: `allow`, `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `set_config`, `serve_error`, `skip`, `compress_response`. - `categories` (Block List) List of tag-based overrides. (see [below for nested schema](#nestedblock--rules--action_parameters--overrides--categories)) - `enabled` (Boolean) Defines if the current ruleset-level override enables or disables the ruleset. - `rules` (Block List) List of rule-based overrides. (see [below for nested schema](#nestedblock--rules--action_parameters--overrides--rules)) @@ -701,7 +729,7 @@ Optional: Optional: -- `action` (String) Action to perform in the tag-level override. Available values: `allow`, `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `set_config`, `serve_error`, `skip`. +- `action` (String) Action to perform in the tag-level override. Available values: `allow`, `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `set_config`, `serve_error`, `skip`, `compress_response`. - `category` (String) Tag name to apply the ruleset rule override to. - `enabled` (Boolean) Defines if the current tag-level override enables or disables the ruleset rules with the specified tag. @@ -711,7 +739,7 @@ Optional: Optional: -- `action` (String) Action to perform in the rule-level override. Available values: `allow`, `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `set_config`, `serve_error`, `skip`. +- `action` (String) Action to perform in the rule-level override. Available values: `allow`, `block`, `challenge`, `ddos_dynamic`, `execute`, `force_connection_close`, `js_challenge`, `log`, `log_custom_field`, `managed_challenge`, `redirect`, `rewrite`, `route`, `score`, `set_cache_settings`, `set_config`, `serve_error`, `skip`, `compress_response`. - `enabled` (Boolean) Defines if the current rule-level override enables or disables the rule. - `id` (String) Rule ID to apply the override to. - `score_threshold` (Number) Anomaly score threshold to apply in the ruleset rule override. Only applicable to modsecurity-based rulesets. diff --git a/examples/resources/cloudflare_ruleset/resource.tf b/examples/resources/cloudflare_ruleset/resource.tf index 10bbf10a7b..00c9ae0fd9 100644 --- a/examples/resources/cloudflare_ruleset/resource.tf +++ b/examples/resources/cloudflare_ruleset/resource.tf @@ -383,3 +383,22 @@ resource "cloudflare_ruleset" "http_config_rules_example" { enabled = true } } + +# Set compress algorithm for response. +resource "cloudflare_ruleset" "response_compress_brotli_html" { + zone_id = "0da42c8d2132a9ddaf714f9e7c920711" + name = "Brotli response compression for HTML" + description = "Response compression ruleset" + kind = "zone" + phase = "http_response_compression" + + rules { + action = "compress_response" + action_parameters { + algorithms = [ { name: "brotli" }, { name: "default" } ] + } + expression = "http.response.content_type.media_type == \"text/html\"" + description = "Prefer brotli compression for HTML" + enabled = true + } +} diff --git a/internal/framework/service/rulesets/model.go b/internal/framework/service/rulesets/model.go index 028a0049e2..a37f410bb7 100644 --- a/internal/framework/service/rulesets/model.go +++ b/internal/framework/service/rulesets/model.go @@ -30,53 +30,54 @@ type RulesModel struct { } type ActionParametersModel struct { - Version types.String `tfsdk:"version"` - AutomaticHTTPSRewrites types.Bool `tfsdk:"automatic_https_rewrites"` - AutoMinify []*ActionParameterAutoMinifyModel `tfsdk:"autominify"` - BIC types.Bool `tfsdk:"bic"` - BrowserTTL []*ActionParameterBrowserTTLModel `tfsdk:"browser_ttl"` - Cache types.Bool `tfsdk:"cache"` - CacheKey []*ActionParameterCacheKeyModel `tfsdk:"cache_key"` - Content types.String `tfsdk:"content"` - ContentType types.String `tfsdk:"content_type"` - CookieFields types.Set `tfsdk:"cookie_fields"` - DisableApps types.Bool `tfsdk:"disable_apps"` - DisableRailgun types.Bool `tfsdk:"disable_railgun"` - DisableZaraz types.Bool `tfsdk:"disable_zaraz"` - EdgeTTL []*ActionParameterEdgeTTLModel `tfsdk:"edge_ttl"` - EmailObfuscation types.Bool `tfsdk:"email_obfuscation"` - FromList []*ActionParameterFromListModel `tfsdk:"from_list"` - FromValue []*ActionParameterFromValueModel `tfsdk:"from_value"` - Headers []*ActionParametersHeadersModel `tfsdk:"headers"` - HostHeader types.String `tfsdk:"host_header"` - HotlinkProtection types.Bool `tfsdk:"hotlink_protection"` - ID types.String `tfsdk:"id"` - Increment types.Int64 `tfsdk:"increment"` - MatchedData []*ActionParametersMatchedDataModel `tfsdk:"matched_data"` - Mirage types.Bool `tfsdk:"mirage"` - OpportunisticEncryption types.Bool `tfsdk:"opportunistic_encryption"` - Origin []*ActionParameterOriginModel `tfsdk:"origin"` - OriginErrorPagePassthru types.Bool `tfsdk:"origin_error_page_passthru"` - Overrides []*ActionParameterOverridesModel `tfsdk:"overrides"` - Phases types.Set `tfsdk:"phases"` - Polish types.String `tfsdk:"polish"` - Products types.Set `tfsdk:"products"` - RequestFields types.Set `tfsdk:"request_fields"` - RespectStrongEtags types.Bool `tfsdk:"respect_strong_etags"` - Response []*ActionParameterResponseModel `tfsdk:"response"` - ResponseFields types.Set `tfsdk:"response_fields"` - RocketLoader types.Bool `tfsdk:"rocket_loader"` - Rules map[string]types.String `tfsdk:"rules"` - Ruleset types.String `tfsdk:"ruleset"` - Rulesets types.Set `tfsdk:"rulesets"` - SecurityLevel types.String `tfsdk:"security_level"` - ServerSideExcludes types.Bool `tfsdk:"server_side_excludes"` - ServeStale []*ActionParameterServeStaleModel `tfsdk:"serve_stale"` - SNI []*ActionParameterSNIModel `tfsdk:"sni"` - SSL types.String `tfsdk:"ssl"` - StatusCode types.Int64 `tfsdk:"status_code"` - SXG types.Bool `tfsdk:"sxg"` - URI []*ActionParametersURIModel `tfsdk:"uri"` + Version types.String `tfsdk:"version"` + AutomaticHTTPSRewrites types.Bool `tfsdk:"automatic_https_rewrites"` + AutoMinify []*ActionParameterAutoMinifyModel `tfsdk:"autominify"` + BIC types.Bool `tfsdk:"bic"` + BrowserTTL []*ActionParameterBrowserTTLModel `tfsdk:"browser_ttl"` + Cache types.Bool `tfsdk:"cache"` + CacheKey []*ActionParameterCacheKeyModel `tfsdk:"cache_key"` + Content types.String `tfsdk:"content"` + ContentType types.String `tfsdk:"content_type"` + CookieFields types.Set `tfsdk:"cookie_fields"` + DisableApps types.Bool `tfsdk:"disable_apps"` + DisableRailgun types.Bool `tfsdk:"disable_railgun"` + DisableZaraz types.Bool `tfsdk:"disable_zaraz"` + EdgeTTL []*ActionParameterEdgeTTLModel `tfsdk:"edge_ttl"` + EmailObfuscation types.Bool `tfsdk:"email_obfuscation"` + FromList []*ActionParameterFromListModel `tfsdk:"from_list"` + FromValue []*ActionParameterFromValueModel `tfsdk:"from_value"` + Headers []*ActionParametersHeadersModel `tfsdk:"headers"` + HostHeader types.String `tfsdk:"host_header"` + HotlinkProtection types.Bool `tfsdk:"hotlink_protection"` + ID types.String `tfsdk:"id"` + Increment types.Int64 `tfsdk:"increment"` + MatchedData []*ActionParametersMatchedDataModel `tfsdk:"matched_data"` + Mirage types.Bool `tfsdk:"mirage"` + OpportunisticEncryption types.Bool `tfsdk:"opportunistic_encryption"` + Origin []*ActionParameterOriginModel `tfsdk:"origin"` + OriginErrorPagePassthru types.Bool `tfsdk:"origin_error_page_passthru"` + Overrides []*ActionParameterOverridesModel `tfsdk:"overrides"` + Phases types.Set `tfsdk:"phases"` + Polish types.String `tfsdk:"polish"` + Products types.Set `tfsdk:"products"` + RequestFields types.Set `tfsdk:"request_fields"` + RespectStrongEtags types.Bool `tfsdk:"respect_strong_etags"` + Response []*ActionParameterResponseModel `tfsdk:"response"` + ResponseFields types.Set `tfsdk:"response_fields"` + RocketLoader types.Bool `tfsdk:"rocket_loader"` + Rules map[string]types.String `tfsdk:"rules"` + Ruleset types.String `tfsdk:"ruleset"` + Rulesets types.Set `tfsdk:"rulesets"` + SecurityLevel types.String `tfsdk:"security_level"` + ServerSideExcludes types.Bool `tfsdk:"server_side_excludes"` + ServeStale []*ActionParameterServeStaleModel `tfsdk:"serve_stale"` + SNI []*ActionParameterSNIModel `tfsdk:"sni"` + SSL types.String `tfsdk:"ssl"` + StatusCode types.Int64 `tfsdk:"status_code"` + SXG types.Bool `tfsdk:"sxg"` + URI []*ActionParametersURIModel `tfsdk:"uri"` + Algorithms []*ActionParametersCompressionAlgorithmModel `tfsdk:"algorithms"` } type ActionParameterOverridesModel struct { @@ -227,6 +228,10 @@ type ActionParameterFromValueTargetURLModel struct { Expression types.String `tfsdk:"expression"` } +type ActionParametersCompressionAlgorithmModel struct { + Name string `tfsdk:"name"` +} + type RatelimitModel struct { Characteristics types.Set `tfsdk:"characteristics"` CountingExpression types.String `tfsdk:"counting_expression"` diff --git a/internal/framework/service/rulesets/resource.go b/internal/framework/service/rulesets/resource.go index 07eb30d64e..985a535784 100644 --- a/internal/framework/service/rulesets/resource.go +++ b/internal/framework/service/rulesets/resource.go @@ -659,6 +659,19 @@ func toRulesetResourceModel(zoneID, accountID basetypes.StringValue, in cloudfla } } + if len(ruleResponse.ActionParameters.Algorithms) > 0 { + var algos []*ActionParametersCompressionAlgorithmModel = nil + + for _, algo := range ruleResponse.ActionParameters.Algorithms { + newAlgo := ActionParametersCompressionAlgorithmModel{ + Name: algo.Name, + } + algos = append(algos, &newAlgo) + } + + rule.ActionParameters[0].Algorithms = algos + } + // ratelimit if !reflect.ValueOf(ruleResponse.RateLimit).IsNil() { var rlCharacteristicsKeys []attr.Value @@ -1230,6 +1243,15 @@ func (r *RulesModel) toRulesetRule() cloudflare.RulesetRule { rr.ActionParameters.ResponseFields = append(rr.ActionParameters.ResponseFields, cloudflare.RulesetActionParametersLogCustomField{Name: request}) } } + + if len(ap.Algorithms) > 0 { + for _, algo := range ap.Algorithms { + newAlgo := cloudflare.RulesetRuleActionParametersCompressionAlgorithm{ + Name: algo.Name, + } + rr.ActionParameters.Algorithms = append(rr.ActionParameters.Algorithms, newAlgo) + } + } } for _, rl := range r.Ratelimit { diff --git a/internal/framework/service/rulesets/resource_test.go b/internal/framework/service/rulesets/resource_test.go index 43af1baf0d..27293ede71 100644 --- a/internal/framework/service/rulesets/resource_test.go +++ b/internal/framework/service/rulesets/resource_test.go @@ -1125,6 +1125,36 @@ func TestAccCloudflareRuleset_TransformationRuleResponseHeaders(t *testing.T) { }) } +func TestAccCloudflareRuleset_ResponseCompression(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + resourceName := "cloudflare_ruleset." + rnd + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCheckCloudflareRulesetResponseCompression(rnd, "my basic response compression ruleset", zoneID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", "my basic response compression ruleset"), + resource.TestCheckResourceAttr(resourceName, "description", rnd+" ruleset description"), + resource.TestCheckResourceAttr(resourceName, "kind", "zone"), + resource.TestCheckResourceAttr(resourceName, "phase", "http_response_compression"), + + resource.TestCheckResourceAttr(resourceName, "rules.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action", "compress_response"), + resource.TestCheckResourceAttr(resourceName, "rules.0.description", rnd+" compress response rule"), + + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.algorithms.0.name", "brotli"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.algorithms.1.name", "default"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.algorithms.#", "2"), + ), + }, + }, + }) +} + func TestAccCloudflareRuleset_ActionParametersMultipleSkips(t *testing.T) { // Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the WAF // service does not yet support the API tokens and it results in @@ -1866,6 +1896,7 @@ func TestAccCloudflareRuleset_Config(t *testing.T) { }, }) } + func TestAccCloudflareRuleset_Redirect(t *testing.T) { rnd := utils.GenerateRandomResourceName() accountId := os.Getenv("CLOUDFLARE_ACCOUNT_ID") @@ -2637,6 +2668,33 @@ func testAccCheckCloudflareRulesetTransformationRuleResponseHeaders(rnd, name, z }`, rnd, name, zoneID, zoneName) } +func testAccCheckCloudflareRulesetResponseCompression(rnd, name, zoneID string) string { + return fmt.Sprintf(` + resource "cloudflare_ruleset" "%[1]s" { + zone_id = "%[3]s" + name = "%[2]s" + description = "%[1]s ruleset description" + kind = "zone" + phase = "http_response_compression" + + rules { + action = "compress_response" + action_parameters { + algorithms { + name = "brotli" + } + algorithms { + name = "default" + } + } + + expression = "true" + description = "%[1]s compress response rule" + enabled = false + } + }`, rnd, name, zoneID) +} + func testAccCheckCloudflareRulesetManagedWAFPayloadLogging(rnd, name, zoneID, zoneName string) string { return fmt.Sprintf(` resource "cloudflare_ruleset" "%[1]s" { diff --git a/internal/framework/service/rulesets/schema.go b/internal/framework/service/rulesets/schema.go index 77b3fdfe8e..dc5485a0eb 100644 --- a/internal/framework/service/rulesets/schema.go +++ b/internal/framework/service/rulesets/schema.go @@ -299,6 +299,23 @@ func (r *RulesetResource) Schema(ctx context.Context, req resource.SchemaRequest }, }, Blocks: map[string]schema.Block{ + "algorithms": schema.ListNestedBlock{ + MarkdownDescription: "Compression algorithms to use in order of preference.", + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Name of the compression algorithm to use.", + Validators: []validator.String{ + stringvalidator.OneOf("gzip", "brotli", "default", "none"), + }, + }, + }, + }, + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + }, + }, "uri": schema.ListNestedBlock{ MarkdownDescription: "List of URI properties to configure for the ruleset rule when performing URL rewrite transformations.", NestedObject: schema.NestedBlockObject{ diff --git a/internal/sdkv2provider/resource_cloudflare_workers_script.go b/internal/sdkv2provider/resource_cloudflare_workers_script.go index 2e5d86f367..b469e6aa3b 100644 --- a/internal/sdkv2provider/resource_cloudflare_workers_script.go +++ b/internal/sdkv2provider/resource_cloudflare_workers_script.go @@ -168,13 +168,13 @@ func resourceCloudflareWorkerScriptCreate(ctx context.Context, d *schema.Resourc logpush := d.Get("logpush").(bool) _, err = client.UploadWorker(ctx, cloudflare.AccountIdentifier(accountID), cloudflare.CreateWorkerParams{ - ScriptName: scriptData.Params.ScriptName, - Script: scriptBody, - CompatibilityDate: d.Get("compatibility_date").(string), + ScriptName: scriptData.Params.ScriptName, + Script: scriptBody, + CompatibilityDate: d.Get("compatibility_date").(string), CompatibilityFlags: getCompatibilityFlags(d), - Module: d.Get("module").(bool), - Bindings: bindings, - Logpush: &logpush, + Module: d.Get("module").(bool), + Bindings: bindings, + Logpush: &logpush, }) if err != nil { return diag.FromErr(errors.Wrap(err, "error creating worker script")) @@ -345,13 +345,13 @@ func resourceCloudflareWorkerScriptUpdate(ctx context.Context, d *schema.Resourc logpush := d.Get("logpush").(bool) _, err = client.UploadWorker(ctx, cloudflare.AccountIdentifier(accountID), cloudflare.CreateWorkerParams{ - ScriptName: scriptData.Params.ScriptName, - Script: scriptBody, - CompatibilityDate: d.Get("compatibility_date").(string), + ScriptName: scriptData.Params.ScriptName, + Script: scriptBody, + CompatibilityDate: d.Get("compatibility_date").(string), CompatibilityFlags: getCompatibilityFlags(d), - Module: d.Get("module").(bool), - Bindings: bindings, - Logpush: &logpush, + Module: d.Get("module").(bool), + Bindings: bindings, + Logpush: &logpush, }) if err != nil { return diag.FromErr(errors.Wrap(err, "error updating worker script")) From ee2de5920dcfa017b8d8e28157e48e934b388e46 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 19 Apr 2023 12:02:35 +1000 Subject: [PATCH 2/3] move .Algorithms into the action parameters block --- .../framework/service/rulesets/resource.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/framework/service/rulesets/resource.go b/internal/framework/service/rulesets/resource.go index 985a535784..2ad9d84af3 100644 --- a/internal/framework/service/rulesets/resource.go +++ b/internal/framework/service/rulesets/resource.go @@ -657,19 +657,19 @@ func toRulesetResourceModel(zoneID, accountID basetypes.StringValue, in cloudfla }}, }} } - } - if len(ruleResponse.ActionParameters.Algorithms) > 0 { - var algos []*ActionParametersCompressionAlgorithmModel = nil + if len(ruleResponse.ActionParameters.Algorithms) > 0 { + var algos []*ActionParametersCompressionAlgorithmModel = nil - for _, algo := range ruleResponse.ActionParameters.Algorithms { - newAlgo := ActionParametersCompressionAlgorithmModel{ - Name: algo.Name, + for _, algo := range ruleResponse.ActionParameters.Algorithms { + newAlgo := ActionParametersCompressionAlgorithmModel{ + Name: algo.Name, + } + algos = append(algos, &newAlgo) } - algos = append(algos, &newAlgo) - } - rule.ActionParameters[0].Algorithms = algos + rule.ActionParameters[0].Algorithms = algos + } } // ratelimit From 927073ab3d9dea7f1f69b0dd2740c011089ee5d4 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 19 Apr 2023 12:06:01 +1000 Subject: [PATCH 3/3] `make docs` --- docs/resources/ruleset.md | 9 +++++++-- examples/resources/cloudflare_ruleset/resource.tf | 7 ++++++- internal/framework/service/rulesets/schema.go | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/resources/ruleset.md b/docs/resources/ruleset.md index 545e5188a8..863bc06533 100644 --- a/docs/resources/ruleset.md +++ b/docs/resources/ruleset.md @@ -427,7 +427,12 @@ resource "cloudflare_ruleset" "response_compress_brotli_html" { rules { action = "compress_response" action_parameters { - algorithms = [ { name: "brotli" }, { name: "default" } ] + algorithms { + name = "brotli" + } + algorithms { + name = "default" + } } expression = "http.response.content_type.media_type == \"text/html\"" description = "Prefer brotli compression for HTML" @@ -537,7 +542,7 @@ Optional: Required: -- `name` (String) Name of the compression algorithm to use. +- `name` (String) Name of the compression algorithm to use. Available values: `gzip`, `brotli`, `default`, `none` diff --git a/examples/resources/cloudflare_ruleset/resource.tf b/examples/resources/cloudflare_ruleset/resource.tf index 00c9ae0fd9..32414b6d7f 100644 --- a/examples/resources/cloudflare_ruleset/resource.tf +++ b/examples/resources/cloudflare_ruleset/resource.tf @@ -395,7 +395,12 @@ resource "cloudflare_ruleset" "response_compress_brotli_html" { rules { action = "compress_response" action_parameters { - algorithms = [ { name: "brotli" }, { name: "default" } ] + algorithms { + name = "brotli" + } + algorithms { + name = "default" + } } expression = "http.response.content_type.media_type == \"text/html\"" description = "Prefer brotli compression for HTML" diff --git a/internal/framework/service/rulesets/schema.go b/internal/framework/service/rulesets/schema.go index dc5485a0eb..a9547d1af9 100644 --- a/internal/framework/service/rulesets/schema.go +++ b/internal/framework/service/rulesets/schema.go @@ -305,7 +305,7 @@ func (r *RulesetResource) Schema(ctx context.Context, req resource.SchemaRequest Attributes: map[string]schema.Attribute{ "name": schema.StringAttribute{ Required: true, - MarkdownDescription: "Name of the compression algorithm to use.", + MarkdownDescription: fmt.Sprintf("Name of the compression algorithm to use. %s", utils.RenderAvailableDocumentationValuesStringSlice([]string{"gzip", "brotli", "default", "none"})), Validators: []validator.String{ stringvalidator.OneOf("gzip", "brotli", "default", "none"), },