From f0fd3ee69ebf3d9e1a6c309d67b9fe1b72800ee9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:44:08 +0000 Subject: [PATCH 001/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 990c6efb47..37e6459931 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b9cf8d97f015bd3c7509f68b4dea2c37dc5f97183372064702ea540b6dd999f8.yml -openapi_spec_hash: 83243c9ee06f88d0fa91e9b185d8a42e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-29174d64a61919dbdebbd0c8d4ab3cb5eec6f9aacff888bdd0469ba2b8d08019.yml +openapi_spec_hash: b5909bd6882171a6ff0158b9f68b47cc config_hash: cce40d4d65a4d67d5df957a75a15b567 From aebd184c1279a5397a423adf7168f129748904cd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 15:48:55 +0000 Subject: [PATCH 002/187] feat(api): api update --- .stats.yml | 4 ++-- .../resources/cloudflare_image/resource.tf | 3 +++ .../cloudflare_logpush_job/resource.tf | 2 +- .../cloudflare_workers_kv/resource.tf | 4 +++- internal/services/image/model.go | 2 +- internal/services/image/schema.go | 6 ++--- .../logpush_dataset_job/data_source_schema.go | 4 ++-- .../logpush_job/data_source_schema.go | 4 ++-- .../logpush_job/list_data_source_schema.go | 4 ++-- internal/services/logpush_job/schema.go | 5 ++-- .../services/workers_kv/data_source_schema.go | 2 +- internal/services/workers_kv/model.go | 13 +++++----- internal/services/workers_kv/schema.go | 11 +++++---- .../data_source_schema.go | 2 +- .../list_data_source_schema.go | 2 +- .../services/workers_kv_namespace/schema.go | 2 +- .../data_source_schema.go | 4 ++-- .../zero_trust_dlp_custom_profile/schema.go | 3 ++- .../data_source_schema.go | 4 ++-- .../list_data_source_schema.go | 4 ++-- .../data_source_schema.go | 4 ++-- internal/services/zero_trust_list/model.go | 24 +++++++++---------- internal/services/zero_trust_list/schema.go | 9 +------ 23 files changed, 61 insertions(+), 61 deletions(-) diff --git a/.stats.yml b/.stats.yml index 37e6459931..a562f0115b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-29174d64a61919dbdebbd0c8d4ab3cb5eec6f9aacff888bdd0469ba2b8d08019.yml -openapi_spec_hash: b5909bd6882171a6ff0158b9f68b47cc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0d0950b4d6565ebd937ab7f58c20ec77ed448ada47e892675290ed602d1f1e5d.yml +openapi_spec_hash: 3471c05655ab2e06b07d7bab145428fa config_hash: cce40d4d65a4d67d5df957a75a15b567 diff --git a/examples/resources/cloudflare_image/resource.tf b/examples/resources/cloudflare_image/resource.tf index aa3749a6e6..1c0a30ed7a 100644 --- a/examples/resources/cloudflare_image/resource.tf +++ b/examples/resources/cloudflare_image/resource.tf @@ -1,5 +1,8 @@ resource "cloudflare_image" "example_image" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" + id = { + + } file = { } diff --git a/examples/resources/cloudflare_logpush_job/resource.tf b/examples/resources/cloudflare_logpush_job/resource.tf index db27efd0b9..b9c3dbe6a1 100644 --- a/examples/resources/cloudflare_logpush_job/resource.tf +++ b/examples/resources/cloudflare_logpush_job/resource.tf @@ -5,7 +5,7 @@ resource "cloudflare_logpush_job" "example_logpush_job" { enabled = false filter = "{\"where\":{\"and\":[{\"key\":\"ClientRequestPath\",\"operator\":\"contains\",\"value\":\"/static\"},{\"key\":\"ClientRequestHost\",\"operator\":\"eq\",\"value\":\"example.com\"}]}}" frequency = "high" - kind = "edge" + kind = "" logpull_options = "fields=RayID,ClientIP,EdgeStartTimestamp×tamps=rfc3339" max_upload_bytes = 5000000 max_upload_interval_seconds = 30 diff --git a/examples/resources/cloudflare_workers_kv/resource.tf b/examples/resources/cloudflare_workers_kv/resource.tf index 0747967d69..7c9bfa2900 100644 --- a/examples/resources/cloudflare_workers_kv/resource.tf +++ b/examples/resources/cloudflare_workers_kv/resource.tf @@ -2,6 +2,8 @@ resource "cloudflare_workers_kv" "example_workers_kv" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" namespace_id = "0f2ac74b498b48028cb68387c421e279" key_name = "My-Key" - metadata = "{\"someMetadataKey\": \"someMetadataValue\"}" value = "Some Value" + metadata = { + + } } diff --git a/internal/services/image/model.go b/internal/services/image/model.go index 34dbe274f7..2ca24fadf8 100644 --- a/internal/services/image/model.go +++ b/internal/services/image/model.go @@ -18,7 +18,7 @@ type ImageResultEnvelope struct { } type ImageModel struct { - ID types.String `tfsdk:"id" json:"id,computed"` + ID jsontypes.Normalized `tfsdk:"id" json:"id,required"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` URL types.String `tfsdk:"url" json:"url,optional,no_refresh"` File jsontypes.Normalized `tfsdk:"file" json:"file,optional,no_refresh"` diff --git a/internal/services/image/schema.go b/internal/services/image/schema.go index 6210176b6c..a44c4a0587 100644 --- a/internal/services/image/schema.go +++ b/internal/services/image/schema.go @@ -22,9 +22,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Description: "Image unique identifier.", - Computed: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + Description: "An optional custom unique identifier for your image.", + Required: true, + CustomType: jsontypes.NormalizedType{}, }, "account_id": schema.StringAttribute{ Description: "Account identifier tag.", diff --git a/internal/services/logpush_dataset_job/data_source_schema.go b/internal/services/logpush_dataset_job/data_source_schema.go index 42b4204d12..358b0db6f1 100644 --- a/internal/services/logpush_dataset_job/data_source_schema.go +++ b/internal/services/logpush_dataset_job/data_source_schema.go @@ -124,10 +124,10 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, "kind": schema.StringAttribute{ - Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset.\nAvailable values: \"edge\".", + Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs (when supported by the dataset).\nAvailable values: \"\", \"edge\".", Computed: true, Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive("edge"), + stringvalidator.OneOfCaseInsensitive("", "edge"), }, }, "last_complete": schema.StringAttribute{ diff --git a/internal/services/logpush_job/data_source_schema.go b/internal/services/logpush_job/data_source_schema.go index 2fbf92ea21..d2635a3a3e 100644 --- a/internal/services/logpush_job/data_source_schema.go +++ b/internal/services/logpush_job/data_source_schema.go @@ -98,10 +98,10 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, "kind": schema.StringAttribute{ - Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset.\nAvailable values: \"edge\".", + Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs (when supported by the dataset).\nAvailable values: \"\", \"edge\".", Computed: true, Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive("edge"), + stringvalidator.OneOfCaseInsensitive("", "edge"), }, }, "last_complete": schema.StringAttribute{ diff --git a/internal/services/logpush_job/list_data_source_schema.go b/internal/services/logpush_job/list_data_source_schema.go index 94f743edb6..e55fa7f557 100644 --- a/internal/services/logpush_job/list_data_source_schema.go +++ b/internal/services/logpush_job/list_data_source_schema.go @@ -104,10 +104,10 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, "kind": schema.StringAttribute{ - Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset.\nAvailable values: \"edge\".", + Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs (when supported by the dataset).\nAvailable values: \"\", \"edge\".", Computed: true, Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive("edge"), + stringvalidator.OneOfCaseInsensitive("", "edge"), }, }, "last_complete": schema.StringAttribute{ diff --git a/internal/services/logpush_job/schema.go b/internal/services/logpush_job/schema.go index 77f35820ab..caaf007d0c 100644 --- a/internal/services/logpush_job/schema.go +++ b/internal/services/logpush_job/schema.go @@ -125,12 +125,13 @@ func ResourceSchema(ctx context.Context) schema.Schema { Default: stringdefault.StaticString("high"), }, "kind": schema.StringAttribute{ - Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset.\nAvailable values: \"edge\".", + Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs (when supported by the dataset).\nAvailable values: \"\", \"edge\".", Computed: true, Optional: true, Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive("edge"), + stringvalidator.OneOfCaseInsensitive("", "edge"), }, + Default: stringdefault.StaticString(""), }, "max_upload_interval_seconds": schema.Int64Attribute{ Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this. This parameter is only used for jobs with `edge` as its kind.", diff --git a/internal/services/workers_kv/data_source_schema.go b/internal/services/workers_kv/data_source_schema.go index 229862c987..0f33e89d6a 100644 --- a/internal/services/workers_kv/data_source_schema.go +++ b/internal/services/workers_kv/data_source_schema.go @@ -15,7 +15,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "account_id": schema.StringAttribute{ - Description: "Identifier", + Description: "Identifier.", Required: true, }, "key_name": schema.StringAttribute{ diff --git a/internal/services/workers_kv/model.go b/internal/services/workers_kv/model.go index 13817426ea..d0cbf4b0c1 100644 --- a/internal/services/workers_kv/model.go +++ b/internal/services/workers_kv/model.go @@ -7,6 +7,7 @@ import ( "mime/multipart" "github.com/cloudflare/terraform-provider-cloudflare/internal/apiform" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -15,12 +16,12 @@ type WorkersKVResultEnvelope struct { } type WorkersKVModel struct { - ID types.String `tfsdk:"id" json:"-,computed"` - KeyName types.String `tfsdk:"key_name" path:"key_name,required"` - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - NamespaceID types.String `tfsdk:"namespace_id" path:"namespace_id,required"` - Metadata types.String `tfsdk:"metadata" json:"metadata,optional,no_refresh"` - Value types.String `tfsdk:"value" json:"value,required,no_refresh"` + ID types.String `tfsdk:"id" json:"-,computed"` + KeyName types.String `tfsdk:"key_name" path:"key_name,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + NamespaceID types.String `tfsdk:"namespace_id" path:"namespace_id,required"` + Value types.String `tfsdk:"value" json:"value,required,no_refresh"` + Metadata jsontypes.Normalized `tfsdk:"metadata" json:"metadata,optional,no_refresh"` } func (r WorkersKVModel) MarshalMultipart() (data []byte, contentType string, err error) { diff --git a/internal/services/workers_kv/schema.go b/internal/services/workers_kv/schema.go index 7aa341cbfe..5cda5f704a 100644 --- a/internal/services/workers_kv/schema.go +++ b/internal/services/workers_kv/schema.go @@ -5,6 +5,7 @@ package workers_kv import ( "context" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -27,7 +28,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, }, "account_id": schema.StringAttribute{ - Description: "Identifier", + Description: "Identifier.", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, @@ -36,14 +37,14 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "metadata": schema.StringAttribute{ - Description: "Arbitrary JSON to be associated with a key/value pair.", - Optional: true, - }, "value": schema.StringAttribute{ Description: "A byte sequence to be stored, up to 25 MiB in length.", Required: true, }, + "metadata": schema.StringAttribute{ + Optional: true, + CustomType: jsontypes.NormalizedType{}, + }, }, } } diff --git a/internal/services/workers_kv_namespace/data_source_schema.go b/internal/services/workers_kv_namespace/data_source_schema.go index 4334a2b91f..7732ca5276 100644 --- a/internal/services/workers_kv_namespace/data_source_schema.go +++ b/internal/services/workers_kv_namespace/data_source_schema.go @@ -27,7 +27,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Optional: true, }, "account_id": schema.StringAttribute{ - Description: "Identifier", + Description: "Identifier.", Required: true, }, "beta": schema.BoolAttribute{ diff --git a/internal/services/workers_kv_namespace/list_data_source_schema.go b/internal/services/workers_kv_namespace/list_data_source_schema.go index d574842856..7dbe18dadb 100644 --- a/internal/services/workers_kv_namespace/list_data_source_schema.go +++ b/internal/services/workers_kv_namespace/list_data_source_schema.go @@ -19,7 +19,7 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "account_id": schema.StringAttribute{ - Description: "Identifier", + Description: "Identifier.", Required: true, }, "direction": schema.StringAttribute{ diff --git a/internal/services/workers_kv_namespace/schema.go b/internal/services/workers_kv_namespace/schema.go index 800b1b61f4..97fd9c74b6 100644 --- a/internal/services/workers_kv_namespace/schema.go +++ b/internal/services/workers_kv_namespace/schema.go @@ -22,7 +22,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "account_id": schema.StringAttribute{ - Description: "Identifier", + Description: "Identifier.", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, diff --git a/internal/services/zero_trust_dlp_custom_profile/data_source_schema.go b/internal/services/zero_trust_dlp_custom_profile/data_source_schema.go index 340996ae77..99b31f4954 100644 --- a/internal/services/zero_trust_dlp_custom_profile/data_source_schema.go +++ b/internal/services/zero_trust_dlp_custom_profile/data_source_schema.go @@ -142,7 +142,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, "type": schema.StringAttribute{ - Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_template", "word_list".`, + Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint", "word_list".`, Computed: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive( @@ -150,7 +150,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "predefined", "integration", "exact_data", - "document_template", + "document_fingerprint", "word_list", ), }, diff --git a/internal/services/zero_trust_dlp_custom_profile/schema.go b/internal/services/zero_trust_dlp_custom_profile/schema.go index 0b41400b3c..c30714ced6 100644 --- a/internal/services/zero_trust_dlp_custom_profile/schema.go +++ b/internal/services/zero_trust_dlp_custom_profile/schema.go @@ -112,7 +112,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, }, "entry_type": schema.StringAttribute{ - Description: `Available values: "custom", "predefined", "integration", "exact_data".`, + Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint".`, Required: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive( @@ -120,6 +120,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "predefined", "integration", "exact_data", + "document_fingerprint", ), }, }, diff --git a/internal/services/zero_trust_dlp_entry/data_source_schema.go b/internal/services/zero_trust_dlp_entry/data_source_schema.go index 8077e51688..8e80536dd7 100644 --- a/internal/services/zero_trust_dlp_entry/data_source_schema.go +++ b/internal/services/zero_trust_dlp_entry/data_source_schema.go @@ -49,7 +49,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Computed: true, }, "type": schema.StringAttribute{ - Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_template", "word_list".`, + Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint", "word_list".`, Computed: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive( @@ -57,7 +57,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "predefined", "integration", "exact_data", - "document_template", + "document_fingerprint", "word_list", ), }, diff --git a/internal/services/zero_trust_dlp_entry/list_data_source_schema.go b/internal/services/zero_trust_dlp_entry/list_data_source_schema.go index 5736bbafa6..d412143c88 100644 --- a/internal/services/zero_trust_dlp_entry/list_data_source_schema.go +++ b/internal/services/zero_trust_dlp_entry/list_data_source_schema.go @@ -67,7 +67,7 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, "type": schema.StringAttribute{ - Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_template", "word_list".`, + Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint", "word_list".`, Computed: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive( @@ -75,7 +75,7 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { "predefined", "integration", "exact_data", - "document_template", + "document_fingerprint", "word_list", ), }, diff --git a/internal/services/zero_trust_dlp_predefined_profile/data_source_schema.go b/internal/services/zero_trust_dlp_predefined_profile/data_source_schema.go index 57e6cce3b6..064696c33d 100644 --- a/internal/services/zero_trust_dlp_predefined_profile/data_source_schema.go +++ b/internal/services/zero_trust_dlp_predefined_profile/data_source_schema.go @@ -142,7 +142,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, "type": schema.StringAttribute{ - Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_template", "word_list".`, + Description: `Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint", "word_list".`, Computed: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive( @@ -150,7 +150,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "predefined", "integration", "exact_data", - "document_template", + "document_fingerprint", "word_list", ), }, diff --git a/internal/services/zero_trust_list/model.go b/internal/services/zero_trust_list/model.go index a7aab21d91..3a758518d8 100644 --- a/internal/services/zero_trust_list/model.go +++ b/internal/services/zero_trust_list/model.go @@ -4,7 +4,6 @@ package zero_trust_list import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -14,15 +13,15 @@ type ZeroTrustListResultEnvelope struct { } type ZeroTrustListModel struct { - ID types.String `tfsdk:"id" json:"id,computed"` - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - Type types.String `tfsdk:"type" json:"type,required"` - Name types.String `tfsdk:"name" json:"name,required"` - Description types.String `tfsdk:"description" json:"description,optional"` - Items customfield.NestedObjectList[ZeroTrustListItemsModel] `tfsdk:"items" json:"items,computed_optional"` - CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` - ListCount types.Float64 `tfsdk:"list_count" json:"count,computed"` - UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` + ID types.String `tfsdk:"id" json:"id,computed"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Type types.String `tfsdk:"type" json:"type,required"` + Name types.String `tfsdk:"name" json:"name,required"` + Description types.String `tfsdk:"description" json:"description,optional"` + Items *[]*ZeroTrustListItemsModel `tfsdk:"items" json:"items,optional"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` + ListCount types.Float64 `tfsdk:"list_count" json:"count,computed"` + UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` } func (m ZeroTrustListModel) MarshalJSON() (data []byte, err error) { @@ -34,7 +33,6 @@ func (m ZeroTrustListModel) MarshalJSONForUpdate(state ZeroTrustListModel) (data } type ZeroTrustListItemsModel struct { - CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` - Description types.String `tfsdk:"description" json:"description,optional"` - Value types.String `tfsdk:"value" json:"value,optional"` + Description types.String `tfsdk:"description" json:"description,optional"` + Value types.String `tfsdk:"value" json:"value,optional"` } diff --git a/internal/services/zero_trust_list/schema.go b/internal/services/zero_trust_list/schema.go index 4f2fc9c5ee..c593962aaa 100644 --- a/internal/services/zero_trust_list/schema.go +++ b/internal/services/zero_trust_list/schema.go @@ -5,7 +5,6 @@ package zero_trust_list import ( "context" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -52,16 +51,10 @@ func ResourceSchema(ctx context.Context) schema.Schema { Optional: true, }, "items": schema.ListNestedAttribute{ - Description: "The items in the list.", - Computed: true, + Description: "items to add to the list.", Optional: true, - CustomType: customfield.NewNestedObjectListType[ZeroTrustListItemsModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ - "created_at": schema.StringAttribute{ - Computed: true, - CustomType: timetypes.RFC3339Type{}, - }, "description": schema.StringAttribute{ Description: "The description of the list item, if present", Optional: true, From 07d0ac258ded515b830fd1f92b8360d49a48806b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 16:47:52 +0000 Subject: [PATCH 003/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a562f0115b..0918cb5fb1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0d0950b4d6565ebd937ab7f58c20ec77ed448ada47e892675290ed602d1f1e5d.yml -openapi_spec_hash: 3471c05655ab2e06b07d7bab145428fa +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-04263c11fcc497830efaecf2e1d4a92964bd7644843b5f844b7732824f7e72f1.yml +openapi_spec_hash: 7218dfe3dcef41955ccebd37926e5ab5 config_hash: cce40d4d65a4d67d5df957a75a15b567 From 856f2cbe07d182796c74e17662c4383288cf03ae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 16:49:31 +0000 Subject: [PATCH 004/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0918cb5fb1..312388e1b1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-04263c11fcc497830efaecf2e1d4a92964bd7644843b5f844b7732824f7e72f1.yml -openapi_spec_hash: 7218dfe3dcef41955ccebd37926e5ab5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3ddf8a069f0ab3fba55a3c2ef565df531a87f4b4e644a417c9b893d0a2caa947.yml +openapi_spec_hash: 5ae460a9c8ba32923bd32c29f4fd8aa7 config_hash: cce40d4d65a4d67d5df957a75a15b567 From 6a607ff4fd6777b5225036de6197fde70de09fe0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 17:08:04 +0000 Subject: [PATCH 005/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 312388e1b1..9a9c5b222e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3ddf8a069f0ab3fba55a3c2ef565df531a87f4b4e644a417c9b893d0a2caa947.yml -openapi_spec_hash: 5ae460a9c8ba32923bd32c29f4fd8aa7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-4fd98a6315cb1b94edd2d2df35e2465c746911b41e1d86f1fba52d3e6d0be815.yml +openapi_spec_hash: 340470e070a8cc8c8f384adb719444d1 config_hash: cce40d4d65a4d67d5df957a75a15b567 From 7e8ef22128d4feabd059a23e181d0bc3dd5e6ec1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 17:12:37 +0000 Subject: [PATCH 006/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9a9c5b222e..4ecf05ede5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-4fd98a6315cb1b94edd2d2df35e2465c746911b41e1d86f1fba52d3e6d0be815.yml -openapi_spec_hash: 340470e070a8cc8c8f384adb719444d1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6032d4dce84efd134480df9d7b9bd707dedead4b87d517a9e3457c188c94f1a3.yml +openapi_spec_hash: 5402c67ce10fff73b2fc27137c2ee436 config_hash: cce40d4d65a4d67d5df957a75a15b567 From f9d659962f67a7927b819bb3823f9b95b194aa01 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 17:30:04 +0000 Subject: [PATCH 007/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4ecf05ede5..bf5b298372 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6032d4dce84efd134480df9d7b9bd707dedead4b87d517a9e3457c188c94f1a3.yml -openapi_spec_hash: 5402c67ce10fff73b2fc27137c2ee436 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-349f60941504b93b7ffd8665d7169fffb3b4b44da7ff7925dfb7735c5dc2c064.yml +openapi_spec_hash: c6dd6121ac070b9e20a3e9fe175434c6 config_hash: cce40d4d65a4d67d5df957a75a15b567 From cbf52f266299bce7aab0fead9fabf46a04f37b87 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:08:59 +0000 Subject: [PATCH 008/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index bf5b298372..7b6dc6a7f6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-349f60941504b93b7ffd8665d7169fffb3b4b44da7ff7925dfb7735c5dc2c064.yml -openapi_spec_hash: c6dd6121ac070b9e20a3e9fe175434c6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c1d9e5c4ba43a9049e1470e1b08ef7039d3eabe34f483a5eaabf4ff18d4e9974.yml +openapi_spec_hash: a5650fa7fa230af9867db1efaa6ade3b config_hash: cce40d4d65a4d67d5df957a75a15b567 From 0a79c8f47b0826841f3085757bed51fee8d57275 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:10:38 +0000 Subject: [PATCH 009/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7b6dc6a7f6..be64b07fb1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c1d9e5c4ba43a9049e1470e1b08ef7039d3eabe34f483a5eaabf4ff18d4e9974.yml -openapi_spec_hash: a5650fa7fa230af9867db1efaa6ade3b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ebb15d2c237bfc6b85dc9443a7b50b363ccae5996a8ed658528c3d8edd3b3eea.yml +openapi_spec_hash: c92360261861594d9b9a99bfe870f571 config_hash: cce40d4d65a4d67d5df957a75a15b567 From 4031102a0331785acc44f6b467e658ad2066448f Mon Sep 17 00:00:00 2001 From: Musa Jundi Date: Fri, 20 Jun 2025 11:40:51 -0500 Subject: [PATCH 010/187] Uncomment list_item resource functions --- .github/workflows/acceptance-tests.yml | 2 +- internal/services/list_item/resource.go | 148 ++++++++++++------------ 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index d087db3ef0..7a4299a687 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -50,7 +50,7 @@ jobs: # run: go test ./internal/services/... -v -sweep="1" -timeout 60m - name: Run acceptance tests # note: not all resources are covered here, only passing ones should be included here (for now). - run: go test ./internal/services/{account,account_api_token_permission_groups,account_dns_settings,account_dns_settings_internal_view,account_permission_group,account_role,account_subscription,account_token,address_map,api_shield,api_shield_discovery_operation,api_shield_schema,api_token_permission_groups,argo_smart_routing,argo_tiered_caching,authenticated_origin_pulls,authenticated_origin_pulls_certificate,authenticated_origin_pulls_settings,botnet_feed_config_asn,byo_ip_prefix,calls_sfu_app,calls_turn_app,certificate_pack,cloud_connector_rules,cloudforce_one_request,cloudforce_one_request_asset,cloudforce_one_request_message,cloudforce_one_request_priority,content_scanning_expression,custom_pages,custom_ssl,dcv_delegation,dns_record,dns_settings_internal_view,dns_zone_transfers_acl,dns_zone_transfers_peer,dns_zone_transfers_tsig,email_routing_address,email_routing_catch_all,email_routing_dns,email_routing_rule,email_security_block_sender,email_security_impersonation_registry,email_security_trusted_domains,image,image_variant,ip_ranges,leaked_credential_check,leaked_credential_check_rule,list,logpull_retention,logpush_dataset_field,logpush_dataset_job,logpush_job,logpush_ownership_challenge,magic_network_monitoring_configuration,magic_network_monitoring_rule,magic_transit_connector,magic_transit_site,magic_transit_site_acl,magic_transit_site_lan,magic_transit_site_wan,magic_wan_gre_tunnel,magic_wan_ipsec_tunnel,magic_wan_static_route,observatory_scheduled_test,origin_ca_certificate,page_rule,page_shield_connections,page_shield_cookies,page_shield_policy,page_shield_scripts,pages_domain,pages_project,queue,queue_consumer,r2_bucket,r2_bucket_cors,r2_bucket_event_notification,r2_bucket_lifecycle,r2_bucket_lock,r2_bucket_sippy,r2_custom_domain,r2_managed_domain,regional_hostname,regional_tiered_cache,registrar_domain,resource_group,ruleset,snippet_rules,snippets,stream,stream_audio_track,stream_caption_language,stream_download,stream_key,stream_live_input,stream_watermark,stream_webhook,tiered_cache,turnstile_widget,url_normalization_settings,user,waiting_room_settings,workers_cron_trigger,workers_custom_domain,workers_deployment,workers_for_platforms_dispatch_namespace,workers_kv_namespace,workers_route,workers_script,workers_script_subdomain,zero_trust_access_infrastructure_target,zero_trust_access_key_configuration,zero_trust_access_mtls_hostname_settings,zero_trust_access_service_token,zero_trust_access_tag,zero_trust_device_custom_profile,zero_trust_device_default_profile,zero_trust_device_default_profile_certificates,zero_trust_device_managed_networks,zero_trust_dlp_custom_profile,zero_trust_dlp_dataset,zero_trust_dlp_entry,zero_trust_dlp_predefined_profile,zero_trust_gateway_app_types,zero_trust_gateway_categories,zero_trust_gateway_certificate,zero_trust_gateway_logging,zero_trust_gateway_proxy_endpoint,zero_trust_list,zero_trust_risk_behavior,zero_trust_risk_scoring_integration,zero_trust_tunnel_cloudflared,zero_trust_tunnel_cloudflared_route,zero_trust_tunnel_cloudflared_token,zero_trust_tunnel_warp_connector_token,zone,zone_cache_reserve,zone_cache_variants,zone_dns_settings,zone_hold,zone_lockdown,zone_setting,zone_subscription} -run "^TestAcc" -count 1 + run: go test ./internal/services/{account,account_api_token_permission_groups,account_dns_settings,account_dns_settings_internal_view,account_permission_group,account_role,account_subscription,account_token,address_map,api_shield,api_shield_discovery_operation,api_shield_schema,api_token_permission_groups,argo_smart_routing,argo_tiered_caching,authenticated_origin_pulls,authenticated_origin_pulls_certificate,authenticated_origin_pulls_settings,botnet_feed_config_asn,byo_ip_prefix,calls_sfu_app,calls_turn_app,certificate_pack,cloud_connector_rules,cloudforce_one_request,cloudforce_one_request_asset,cloudforce_one_request_message,cloudforce_one_request_priority,content_scanning_expression,custom_pages,custom_ssl,dcv_delegation,dns_record,dns_settings_internal_view,dns_zone_transfers_acl,dns_zone_transfers_peer,dns_zone_transfers_tsig,email_routing_address,email_routing_catch_all,email_routing_dns,email_routing_rule,email_security_block_sender,email_security_impersonation_registry,email_security_trusted_domains,image,image_variant,ip_ranges,leaked_credential_check,leaked_credential_check_rule,list,list_item,logpull_retention,logpush_dataset_field,logpush_dataset_job,logpush_job,logpush_ownership_challenge,magic_network_monitoring_configuration,magic_network_monitoring_rule,magic_transit_connector,magic_transit_site,magic_transit_site_acl,magic_transit_site_lan,magic_transit_site_wan,magic_wan_gre_tunnel,magic_wan_ipsec_tunnel,magic_wan_static_route,observatory_scheduled_test,origin_ca_certificate,page_rule,page_shield_connections,page_shield_cookies,page_shield_policy,page_shield_scripts,pages_domain,pages_project,queue,queue_consumer,r2_bucket,r2_bucket_cors,r2_bucket_event_notification,r2_bucket_lifecycle,r2_bucket_lock,r2_bucket_sippy,r2_custom_domain,r2_managed_domain,regional_hostname,regional_tiered_cache,registrar_domain,resource_group,ruleset,snippet_rules,snippets,stream,stream_audio_track,stream_caption_language,stream_download,stream_key,stream_live_input,stream_watermark,stream_webhook,tiered_cache,turnstile_widget,url_normalization_settings,user,waiting_room_settings,workers_cron_trigger,workers_custom_domain,workers_deployment,workers_for_platforms_dispatch_namespace,workers_kv_namespace,workers_route,workers_script,workers_script_subdomain,zero_trust_access_infrastructure_target,zero_trust_access_key_configuration,zero_trust_access_mtls_hostname_settings,zero_trust_access_service_token,zero_trust_access_tag,zero_trust_device_custom_profile,zero_trust_device_default_profile,zero_trust_device_default_profile_certificates,zero_trust_device_managed_networks,zero_trust_dlp_custom_profile,zero_trust_dlp_dataset,zero_trust_dlp_entry,zero_trust_dlp_predefined_profile,zero_trust_gateway_app_types,zero_trust_gateway_categories,zero_trust_gateway_certificate,zero_trust_gateway_logging,zero_trust_gateway_proxy_endpoint,zero_trust_list,zero_trust_risk_behavior,zero_trust_risk_scoring_integration,zero_trust_tunnel_cloudflared,zero_trust_tunnel_cloudflared_route,zero_trust_tunnel_cloudflared_token,zero_trust_tunnel_warp_connector_token,zone,zone_cache_reserve,zone_cache_variants,zone_dns_settings,zone_hold,zone_lockdown,zone_setting,zone_subscription} -run "^TestAcc" -count 1 env: TF_ACC: 1 # when all resources support sweepers, re-enable. diff --git a/internal/services/list_item/resource.go b/internal/services/list_item/resource.go index 162fa2e13c..5dba9ba94e 100644 --- a/internal/services/list_item/resource.go +++ b/internal/services/list_item/resource.go @@ -148,86 +148,86 @@ func (r *ListItemResource) Create(ctx context.Context, req resource.CreateReques func (r *ListItemResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var data *ListItemModel - // resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - - // if resp.Diagnostics.HasError() { - // return - // } - - // var state *ListItemModel - - // resp.Diagnostics.Append(req.State.Get(ctx, &state)...) - - // if resp.Diagnostics.HasError() { - // return - // } - - // dataBytes, err := data.MarshalJSONForUpdate(*state) - // if err != nil { - // resp.Diagnostics.AddError("failed to serialize http request", err.Error()) - // return - // } - // res := new(http.Response) - // env := ListItemResultEnvelope{*data} - // _, err = r.client.Rules.Lists.Items.Update( - // ctx, - // data.ListID.ValueString(), - // rules.ListItemUpdateParams{ - // AccountID: cloudflare.F(data.AccountID.ValueString()), - // }, - // option.WithRequestBody("application/json", dataBytes), - // option.WithResponseBodyInto(&res), - // option.WithMiddleware(logging.Middleware(ctx)), - // ) - // if err != nil { - // resp.Diagnostics.AddError("failed to make http request", err.Error()) - // return - // } - // bytes, _ := io.ReadAll(res.Body) - // err = apijson.UnmarshalComputed(bytes, &env) - // if err != nil { - // resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) - // return - // } - // data = &env.Result + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *ListItemModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := ListItemResultEnvelope{*data} + _, err = r.client.Rules.Lists.Items.Update( + ctx, + data.ListID.ValueString(), + rules.ListItemUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } func (r *ListItemResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data *ListItemModel - // resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - - // if resp.Diagnostics.HasError() { - // return - // } - - // res := new(http.Response) - // env := ListItemResultEnvelope{*data} - // _, err := r.client.Rules.Lists.Items.Get( - // ctx, - // data.AccountID.ValueString(), - // data.ListID.ValueString(), - // data.ID.ValueString(), - // option.WithResponseBodyInto(&res), - // option.WithMiddleware(logging.Middleware(ctx)), - // ) - // if res != nil && res.StatusCode == 404 { - // resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") - // resp.State.RemoveResource(ctx) - // return - // } - // if err != nil { - // resp.Diagnostics.AddError("failed to make http request", err.Error()) - // return - // } - // bytes, _ := io.ReadAll(res.Body) - // err = apijson.Unmarshal(bytes, &env) - // if err != nil { - // resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) - // return - // } - // data = &env.Result + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := ListItemResultEnvelope{*data} + _, err := r.client.Rules.Lists.Items.Get( + ctx, + data.ListID.ValueString(), + data.ID.ValueString(), + rules.ListItemGetParams{AccountID: cloudflare.F(data.AccountID.ValueString())}, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } From c31161033e3aef0cb24fbd3b9b2e1bcd0a3fa24a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:13:13 +0000 Subject: [PATCH 011/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index be64b07fb1..ccbca3b43f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ebb15d2c237bfc6b85dc9443a7b50b363ccae5996a8ed658528c3d8edd3b3eea.yml -openapi_spec_hash: c92360261861594d9b9a99bfe870f571 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3081a2cc870d2021dbfac8fd8fa12de842daf18f852fbdd2e4218785bf8d06b6.yml +openapi_spec_hash: 9d4068cf32af06f75e3f72f49a80ff2a config_hash: cce40d4d65a4d67d5df957a75a15b567 From 664eb2ae8752488374869f3ae5e419705526f156 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:14:29 +0000 Subject: [PATCH 012/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ccbca3b43f..67901f5068 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3081a2cc870d2021dbfac8fd8fa12de842daf18f852fbdd2e4218785bf8d06b6.yml -openapi_spec_hash: 9d4068cf32af06f75e3f72f49a80ff2a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-16ab34528faa2ae52543b8422c2af1097c408494fd15597e492718901146c408.yml +openapi_spec_hash: a73031467be36e0c74bfd258802966e6 config_hash: cce40d4d65a4d67d5df957a75a15b567 From 837107c1fd898516a4a3d26dfb1ad13b3a64935e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:20:47 +0000 Subject: [PATCH 013/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 67901f5068..a6b961ac61 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-16ab34528faa2ae52543b8422c2af1097c408494fd15597e492718901146c408.yml -openapi_spec_hash: a73031467be36e0c74bfd258802966e6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d3a34e6f93d89c344c9a77f60acd970d00e8cec662b990e05b2aaf8f10e6f4a9.yml +openapi_spec_hash: 8dd5131f7f4919729146b3dbe976e9de config_hash: cce40d4d65a4d67d5df957a75a15b567 From ac67f1cff2fed3dfbc6f7b189f234f7f3e42adc0 Mon Sep 17 00:00:00 2001 From: Musa Jundi Date: Fri, 20 Jun 2025 14:23:28 -0500 Subject: [PATCH 014/187] Improve readability of acceptance test list for CI workflow --- .github/workflows/acceptance-tests.yml | 2 +- scripts/run-ci-acceptance-tests | 148 +++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100755 scripts/run-ci-acceptance-tests diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 7a4299a687..1e94a92be6 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -50,7 +50,7 @@ jobs: # run: go test ./internal/services/... -v -sweep="1" -timeout 60m - name: Run acceptance tests # note: not all resources are covered here, only passing ones should be included here (for now). - run: go test ./internal/services/{account,account_api_token_permission_groups,account_dns_settings,account_dns_settings_internal_view,account_permission_group,account_role,account_subscription,account_token,address_map,api_shield,api_shield_discovery_operation,api_shield_schema,api_token_permission_groups,argo_smart_routing,argo_tiered_caching,authenticated_origin_pulls,authenticated_origin_pulls_certificate,authenticated_origin_pulls_settings,botnet_feed_config_asn,byo_ip_prefix,calls_sfu_app,calls_turn_app,certificate_pack,cloud_connector_rules,cloudforce_one_request,cloudforce_one_request_asset,cloudforce_one_request_message,cloudforce_one_request_priority,content_scanning_expression,custom_pages,custom_ssl,dcv_delegation,dns_record,dns_settings_internal_view,dns_zone_transfers_acl,dns_zone_transfers_peer,dns_zone_transfers_tsig,email_routing_address,email_routing_catch_all,email_routing_dns,email_routing_rule,email_security_block_sender,email_security_impersonation_registry,email_security_trusted_domains,image,image_variant,ip_ranges,leaked_credential_check,leaked_credential_check_rule,list,list_item,logpull_retention,logpush_dataset_field,logpush_dataset_job,logpush_job,logpush_ownership_challenge,magic_network_monitoring_configuration,magic_network_monitoring_rule,magic_transit_connector,magic_transit_site,magic_transit_site_acl,magic_transit_site_lan,magic_transit_site_wan,magic_wan_gre_tunnel,magic_wan_ipsec_tunnel,magic_wan_static_route,observatory_scheduled_test,origin_ca_certificate,page_rule,page_shield_connections,page_shield_cookies,page_shield_policy,page_shield_scripts,pages_domain,pages_project,queue,queue_consumer,r2_bucket,r2_bucket_cors,r2_bucket_event_notification,r2_bucket_lifecycle,r2_bucket_lock,r2_bucket_sippy,r2_custom_domain,r2_managed_domain,regional_hostname,regional_tiered_cache,registrar_domain,resource_group,ruleset,snippet_rules,snippets,stream,stream_audio_track,stream_caption_language,stream_download,stream_key,stream_live_input,stream_watermark,stream_webhook,tiered_cache,turnstile_widget,url_normalization_settings,user,waiting_room_settings,workers_cron_trigger,workers_custom_domain,workers_deployment,workers_for_platforms_dispatch_namespace,workers_kv_namespace,workers_route,workers_script,workers_script_subdomain,zero_trust_access_infrastructure_target,zero_trust_access_key_configuration,zero_trust_access_mtls_hostname_settings,zero_trust_access_service_token,zero_trust_access_tag,zero_trust_device_custom_profile,zero_trust_device_default_profile,zero_trust_device_default_profile_certificates,zero_trust_device_managed_networks,zero_trust_dlp_custom_profile,zero_trust_dlp_dataset,zero_trust_dlp_entry,zero_trust_dlp_predefined_profile,zero_trust_gateway_app_types,zero_trust_gateway_categories,zero_trust_gateway_certificate,zero_trust_gateway_logging,zero_trust_gateway_proxy_endpoint,zero_trust_list,zero_trust_risk_behavior,zero_trust_risk_scoring_integration,zero_trust_tunnel_cloudflared,zero_trust_tunnel_cloudflared_route,zero_trust_tunnel_cloudflared_token,zero_trust_tunnel_warp_connector_token,zone,zone_cache_reserve,zone_cache_variants,zone_dns_settings,zone_hold,zone_lockdown,zone_setting,zone_subscription} -run "^TestAcc" -count 1 + run: ./scripts/run-ci-acceptance-tests env: TF_ACC: 1 # when all resources support sweepers, re-enable. diff --git a/scripts/run-ci-acceptance-tests b/scripts/run-ci-acceptance-tests new file mode 100755 index 0000000000..ca1e41adc8 --- /dev/null +++ b/scripts/run-ci-acceptance-tests @@ -0,0 +1,148 @@ +#!/usr/bin/env bash + +go test -run "^TestAcc" -count 1 \ + ./internal/services/account \ + ./internal/services/account_api_token_permission_groups \ + ./internal/services/account_dns_settings \ + ./internal/services/account_dns_settings_internal_view \ + ./internal/services/account_permission_group \ + ./internal/services/account_role \ + ./internal/services/account_subscription \ + ./internal/services/account_token \ + ./internal/services/address_map \ + ./internal/services/api_shield \ + ./internal/services/api_shield_discovery_operation \ + ./internal/services/api_shield_schema \ + ./internal/services/api_token_permission_groups \ + ./internal/services/argo_smart_routing \ + ./internal/services/argo_tiered_caching \ + ./internal/services/authenticated_origin_pulls \ + ./internal/services/authenticated_origin_pulls_certificate \ + ./internal/services/authenticated_origin_pulls_settings \ + ./internal/services/botnet_feed_config_asn \ + ./internal/services/byo_ip_prefix \ + ./internal/services/calls_sfu_app \ + ./internal/services/calls_turn_app \ + ./internal/services/certificate_pack \ + ./internal/services/cloud_connector_rules \ + ./internal/services/cloudforce_one_request \ + ./internal/services/cloudforce_one_request_asset \ + ./internal/services/cloudforce_one_request_message \ + ./internal/services/cloudforce_one_request_priority \ + ./internal/services/content_scanning_expression \ + ./internal/services/custom_pages \ + ./internal/services/custom_ssl \ + ./internal/services/dcv_delegation \ + ./internal/services/dns_record \ + ./internal/services/dns_settings_internal_view \ + ./internal/services/dns_zone_transfers_acl \ + ./internal/services/dns_zone_transfers_peer \ + ./internal/services/dns_zone_transfers_tsig \ + ./internal/services/email_routing_address \ + ./internal/services/email_routing_catch_all \ + ./internal/services/email_routing_dns \ + ./internal/services/email_routing_rule \ + ./internal/services/email_security_block_sender \ + ./internal/services/email_security_impersonation_registry \ + ./internal/services/email_security_trusted_domains \ + ./internal/services/image \ + ./internal/services/image_variant \ + ./internal/services/ip_ranges \ + ./internal/services/leaked_credential_check \ + ./internal/services/leaked_credential_check_rule \ + ./internal/services/list \ + ./internal/services/list_item \ + ./internal/services/logpull_retention \ + ./internal/services/logpush_dataset_field \ + ./internal/services/logpush_dataset_job \ + ./internal/services/logpush_job \ + ./internal/services/logpush_ownership_challenge \ + ./internal/services/magic_network_monitoring_configuration \ + ./internal/services/magic_network_monitoring_rule \ + ./internal/services/magic_transit_connector \ + ./internal/services/magic_transit_site \ + ./internal/services/magic_transit_site_acl \ + ./internal/services/magic_transit_site_lan \ + ./internal/services/magic_transit_site_wan \ + ./internal/services/magic_wan_gre_tunnel \ + ./internal/services/magic_wan_ipsec_tunnel \ + ./internal/services/magic_wan_static_route \ + ./internal/services/observatory_scheduled_test \ + ./internal/services/origin_ca_certificate \ + ./internal/services/page_rule \ + ./internal/services/page_shield_connections \ + ./internal/services/page_shield_cookies \ + ./internal/services/page_shield_policy \ + ./internal/services/page_shield_scripts \ + ./internal/services/pages_domain \ + ./internal/services/pages_project \ + ./internal/services/queue \ + ./internal/services/queue_consumer \ + ./internal/services/r2_bucket \ + ./internal/services/r2_bucket_cors \ + ./internal/services/r2_bucket_event_notification \ ./internal/services/r2_bucket_lifecycle \ + ./internal/services/r2_bucket_lock \ + ./internal/services/r2_bucket_sippy \ + ./internal/services/r2_custom_domain \ + ./internal/services/r2_managed_domain \ + ./internal/services/regional_hostname \ + ./internal/services/regional_tiered_cache \ + ./internal/services/registrar_domain \ + ./internal/services/resource_group \ + ./internal/services/ruleset \ + ./internal/services/snippet_rules \ + ./internal/services/snippets \ + ./internal/services/stream \ + ./internal/services/stream_audio_track \ + ./internal/services/stream_caption_language \ + ./internal/services/stream_download \ + ./internal/services/stream_key \ + ./internal/services/stream_live_input \ + ./internal/services/stream_watermark \ + ./internal/services/stream_webhook \ + ./internal/services/tiered_cache \ + ./internal/services/turnstile_widget \ + ./internal/services/url_normalization_settings \ + ./internal/services/user \ + ./internal/services/waiting_room_settings \ + ./internal/services/workers_cron_trigger \ + ./internal/services/workers_custom_domain \ + ./internal/services/workers_deployment \ + ./internal/services/workers_for_platforms_dispatch_namespace \ + ./internal/services/workers_kv_namespace \ + ./internal/services/workers_route \ + ./internal/services/workers_script \ + ./internal/services/workers_script_subdomain \ + ./internal/services/zero_trust_access_infrastructure_target \ + ./internal/services/zero_trust_access_key_configuration \ + ./internal/services/zero_trust_access_mtls_hostname_settings \ + ./internal/services/zero_trust_access_service_token \ + ./internal/services/zero_trust_access_tag \ + ./internal/services/zero_trust_device_custom_profile \ + ./internal/services/zero_trust_device_default_profile \ + ./internal/services/zero_trust_device_default_profile_certificates \ + ./internal/services/zero_trust_device_managed_networks \ + ./internal/services/zero_trust_dlp_custom_profile \ + ./internal/services/zero_trust_dlp_dataset \ + ./internal/services/zero_trust_dlp_entry \ + ./internal/services/zero_trust_dlp_predefined_profile \ + ./internal/services/zero_trust_gateway_app_types \ + ./internal/services/zero_trust_gateway_categories \ + ./internal/services/zero_trust_gateway_certificate \ + ./internal/services/zero_trust_gateway_logging \ + ./internal/services/zero_trust_gateway_proxy_endpoint \ + ./internal/services/zero_trust_list \ + ./internal/services/zero_trust_risk_behavior \ + ./internal/services/zero_trust_risk_scoring_integration \ + ./internal/services/zero_trust_tunnel_cloudflared \ + ./internal/services/zero_trust_tunnel_cloudflared_route \ + ./internal/services/zero_trust_tunnel_cloudflared_token \ + ./internal/services/zero_trust_tunnel_warp_connector_token \ + ./internal/services/zone \ + ./internal/services/zone_cache_reserve \ + ./internal/services/zone_cache_variants \ + ./internal/services/zone_dns_settings \ + ./internal/services/zone_hold \ + ./internal/services/zone_lockdown \ + ./internal/services/zone_setting \ + ./internal/services/zone_subscription \ From 3c7cc0bcbc9adb05ebfc8e1e015469ee5195f68e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:03:30 +0000 Subject: [PATCH 015/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a6b961ac61..2992dab852 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d3a34e6f93d89c344c9a77f60acd970d00e8cec662b990e05b2aaf8f10e6f4a9.yml -openapi_spec_hash: 8dd5131f7f4919729146b3dbe976e9de +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b8564470fd064b69c2db15ff823829f02578aad21d16eddfbfe1a52759eef23d.yml +openapi_spec_hash: f50ea7ed3619bc31079686f8ab45b67a config_hash: cce40d4d65a4d67d5df957a75a15b567 From f60d54e15c10658de17cec104a47d2754322e3c1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:05:44 +0000 Subject: [PATCH 016/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2992dab852..894ef42a9d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b8564470fd064b69c2db15ff823829f02578aad21d16eddfbfe1a52759eef23d.yml -openapi_spec_hash: f50ea7ed3619bc31079686f8ab45b67a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a05d9d914eec9cd3e9b8819cfc85742b4a0cd61505d6be3f8f0f933c0941bd3d.yml +openapi_spec_hash: ed2f5331f775198f55a81f2b5ca9e50c config_hash: cce40d4d65a4d67d5df957a75a15b567 From 0dfa0bd902e52344f7296a0216f1738fa4a12de5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:20:24 +0000 Subject: [PATCH 017/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 894ef42a9d..a8d869cf54 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a05d9d914eec9cd3e9b8819cfc85742b4a0cd61505d6be3f8f0f933c0941bd3d.yml -openapi_spec_hash: ed2f5331f775198f55a81f2b5ca9e50c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7beb5e4317fc79ba9452e7fc46fece8b5129c2dc98a310275d3f26cb4a840ac2.yml +openapi_spec_hash: 6e856a8f7607fd225670a4c5815ce59b config_hash: cce40d4d65a4d67d5df957a75a15b567 From 2105971905b14f4368f69073bcfad53299004c0b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:22:23 +0000 Subject: [PATCH 018/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a8d869cf54..9cf504f8ba 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7beb5e4317fc79ba9452e7fc46fece8b5129c2dc98a310275d3f26cb4a840ac2.yml -openapi_spec_hash: 6e856a8f7607fd225670a4c5815ce59b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-8ebec5aea767b1c60bdbe9006599da48f89cb979704ab0a129f11faea537f97e.yml +openapi_spec_hash: 0e3f4d68a4497afd17f1a427c8059c3e config_hash: cce40d4d65a4d67d5df957a75a15b567 From 95c75d5fa290f9d602e835094af9bbb1b7878076 Mon Sep 17 00:00:00 2001 From: Vaishak Dinesh Date: Fri, 20 Jun 2025 14:43:28 -0700 Subject: [PATCH 019/187] chore: update docs --- docs/guides/migrating-renamed-resources.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/guides/migrating-renamed-resources.md b/docs/guides/migrating-renamed-resources.md index 5c3a3530d7..9094aa139f 100644 --- a/docs/guides/migrating-renamed-resources.md +++ b/docs/guides/migrating-renamed-resources.md @@ -21,6 +21,8 @@ description: Guide for handling renamed resources in the Cloudflare Provider environment or a small subset resources before performing the changes to all resources. +NOTE: use the environment variable `GRIT_MAX_FILE_SIZE_BYTES=0` if the state file is too big and grit errors out. + ## Using import -> Recommended for most users and migrations. From 5352624f89a1d845334367d5b57109491f6ef88b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:50:09 +0000 Subject: [PATCH 020/187] codegen metadata --- .stats.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9cf504f8ba..38c6d04fe1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-8ebec5aea767b1c60bdbe9006599da48f89cb979704ab0a129f11faea537f97e.yml -openapi_spec_hash: 0e3f4d68a4497afd17f1a427c8059c3e -config_hash: cce40d4d65a4d67d5df957a75a15b567 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a05d9d914eec9cd3e9b8819cfc85742b4a0cd61505d6be3f8f0f933c0941bd3d.yml +openapi_spec_hash: ed2f5331f775198f55a81f2b5ca9e50c +config_hash: 9e096c169b43682069730a4291c62d4a From a903fb5bef21167f616e59815ab5d247625765d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 06:02:41 +0000 Subject: [PATCH 021/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 38c6d04fe1..44a46cb325 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a05d9d914eec9cd3e9b8819cfc85742b4a0cd61505d6be3f8f0f933c0941bd3d.yml -openapi_spec_hash: ed2f5331f775198f55a81f2b5ca9e50c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-349f60941504b93b7ffd8665d7169fffb3b4b44da7ff7925dfb7735c5dc2c064.yml +openapi_spec_hash: c6dd6121ac070b9e20a3e9fe175434c6 config_hash: 9e096c169b43682069730a4291c62d4a From 9cccc73f6e62cbb568bb7b65b67670e051822772 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 06:04:14 +0000 Subject: [PATCH 022/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 44a46cb325..5994e1ddf6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-349f60941504b93b7ffd8665d7169fffb3b4b44da7ff7925dfb7735c5dc2c064.yml -openapi_spec_hash: c6dd6121ac070b9e20a3e9fe175434c6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d20714c9e237c818ece8952fdb4c8707167bd729bc351535fd5ed3f2045c97dd.yml +openapi_spec_hash: f3dd992fb5b9e9f446badf877a677543 config_hash: 9e096c169b43682069730a4291c62d4a From 6bec072fe1eadc831b066dbe7f89f51d89fe4193 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 06:05:53 +0000 Subject: [PATCH 023/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5994e1ddf6..0e6b2f5c9a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d20714c9e237c818ece8952fdb4c8707167bd729bc351535fd5ed3f2045c97dd.yml -openapi_spec_hash: f3dd992fb5b9e9f446badf877a677543 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-14dad5f4c5f9ffd273396e1b5717a4479e308c3f84046ea2ecd431666ff1aac9.yml +openapi_spec_hash: cde80d758d24a8ef13fc45a9e960dfe3 config_hash: 9e096c169b43682069730a4291c62d4a From 0bc2e16b8e8dbda0fe402dce1719167f2033f035 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 06:10:02 +0000 Subject: [PATCH 024/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0e6b2f5c9a..a413355280 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-14dad5f4c5f9ffd273396e1b5717a4479e308c3f84046ea2ecd431666ff1aac9.yml -openapi_spec_hash: cde80d758d24a8ef13fc45a9e960dfe3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-cacb2bc17495e079bf82c8e57a2985fc9f5b6c6adaa09f13e901add6b7ae8868.yml +openapi_spec_hash: 54762993aa1e76437be8b1155712ad79 config_hash: 9e096c169b43682069730a4291c62d4a From 09acc3c9544c56f4df1d0f227f100a264a7e1f16 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 11:28:53 +0000 Subject: [PATCH 025/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a413355280..8a2536f41b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-cacb2bc17495e079bf82c8e57a2985fc9f5b6c6adaa09f13e901add6b7ae8868.yml -openapi_spec_hash: 54762993aa1e76437be8b1155712ad79 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-67a5e0862d2e4406e310cc08157e2c8f1ea02f62132ecb144295729ff1e00d4b.yml +openapi_spec_hash: 47daba1c1a2478b88715abb5c9d64f52 config_hash: 9e096c169b43682069730a4291c62d4a From 7d4df074d7e9809af3974d722b77d36cb9d3e500 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 11:30:23 +0000 Subject: [PATCH 026/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8a2536f41b..65565a1dc8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-67a5e0862d2e4406e310cc08157e2c8f1ea02f62132ecb144295729ff1e00d4b.yml -openapi_spec_hash: 47daba1c1a2478b88715abb5c9d64f52 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3081a2cc870d2021dbfac8fd8fa12de842daf18f852fbdd2e4218785bf8d06b6.yml +openapi_spec_hash: 9d4068cf32af06f75e3f72f49a80ff2a config_hash: 9e096c169b43682069730a4291c62d4a From b1273e72e13326861eceeb624583934f8f4a5632 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 12:57:54 +0000 Subject: [PATCH 027/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 65565a1dc8..3862b17885 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3081a2cc870d2021dbfac8fd8fa12de842daf18f852fbdd2e4218785bf8d06b6.yml -openapi_spec_hash: 9d4068cf32af06f75e3f72f49a80ff2a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-dbdd79e3320279d9b30bb56dff3ad67624292fcbdef0a8c3ece0627aec85a8aa.yml +openapi_spec_hash: f60aa52659ef55ace5e0986dd87e8adb config_hash: 9e096c169b43682069730a4291c62d4a From 0363aaaaf2bfd6a28d753754c28ca6bcce9d8e45 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 13:07:35 +0000 Subject: [PATCH 028/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3862b17885..be90fd6416 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-dbdd79e3320279d9b30bb56dff3ad67624292fcbdef0a8c3ece0627aec85a8aa.yml -openapi_spec_hash: f60aa52659ef55ace5e0986dd87e8adb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b405a8731383039c519ebfaf6fcdec33a714502a5a11f1f8036206fd55e9e735.yml +openapi_spec_hash: 0488b58100e434defaeee50c66a512d0 config_hash: 9e096c169b43682069730a4291c62d4a From 355477bd94d4f2846a75affced7e49a2dec29bc0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 14:01:46 +0000 Subject: [PATCH 029/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index be90fd6416..d4755a50ac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b405a8731383039c519ebfaf6fcdec33a714502a5a11f1f8036206fd55e9e735.yml -openapi_spec_hash: 0488b58100e434defaeee50c66a512d0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3344d61337767cb7a666535ee455787a19a9220441fdc6fb46de9d2d4d2e9494.yml +openapi_spec_hash: 0074630178000445ee720d7f2a4a06da config_hash: 9e096c169b43682069730a4291c62d4a From b02f3e5dce60540240bf16b634ac5b2fb6c718cb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 14:31:40 +0000 Subject: [PATCH 030/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d4755a50ac..c62fffe93c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3344d61337767cb7a666535ee455787a19a9220441fdc6fb46de9d2d4d2e9494.yml -openapi_spec_hash: 0074630178000445ee720d7f2a4a06da +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6cde4e76444147a1a610c21bfecfaa04d7f29ef55a2665e45c7869dc7aa7e8a2.yml +openapi_spec_hash: ca14ff449d8cd3aff742013eec1f515e config_hash: 9e096c169b43682069730a4291c62d4a From c0d898a8be42dc97f3749abe2db774b19eb18620 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 14:33:25 +0000 Subject: [PATCH 031/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c62fffe93c..a7b178cd37 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6cde4e76444147a1a610c21bfecfaa04d7f29ef55a2665e45c7869dc7aa7e8a2.yml -openapi_spec_hash: ca14ff449d8cd3aff742013eec1f515e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-25e9f1be186d00c5b9bcc8338b7e727a00124238d67a9b6dc59e4847365ef2bc.yml +openapi_spec_hash: 13c5b5e48838765119323276c64028e4 config_hash: 9e096c169b43682069730a4291c62d4a From 609a4db6d917f950415a5535ac2493ae43f4fbf8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:03:20 +0000 Subject: [PATCH 032/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a7b178cd37..de0ae68ea5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-25e9f1be186d00c5b9bcc8338b7e727a00124238d67a9b6dc59e4847365ef2bc.yml -openapi_spec_hash: 13c5b5e48838765119323276c64028e4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9b7869ddf0ce114bedf6eca7a921dbea2655c1b6a5ad7aa3e490cbc26594cb77.yml +openapi_spec_hash: 87fa679f43184486ff0554e647b26916 config_hash: 9e096c169b43682069730a4291c62d4a From ccfbfc2e50ca77aa01a6c7d09363ae869b9c28d3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:22:32 +0000 Subject: [PATCH 033/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index de0ae68ea5..683995293c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9b7869ddf0ce114bedf6eca7a921dbea2655c1b6a5ad7aa3e490cbc26594cb77.yml -openapi_spec_hash: 87fa679f43184486ff0554e647b26916 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-671e840d7cdd52e06a947b36adfcef68b8e688a74c6fad5c00fef52f1ea6e7f3.yml +openapi_spec_hash: 76074df96067f56c88813d8158a3e75a config_hash: 9e096c169b43682069730a4291c62d4a From 9a10d163106f59347e888632c0cf481e71534423 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:27:53 +0000 Subject: [PATCH 034/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 683995293c..16130209aa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-671e840d7cdd52e06a947b36adfcef68b8e688a74c6fad5c00fef52f1ea6e7f3.yml -openapi_spec_hash: 76074df96067f56c88813d8158a3e75a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c1d9e5c4ba43a9049e1470e1b08ef7039d3eabe34f483a5eaabf4ff18d4e9974.yml +openapi_spec_hash: a5650fa7fa230af9867db1efaa6ade3b config_hash: 9e096c169b43682069730a4291c62d4a From f58266522dc2693735d4943fcf68553e0d90532c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:29:21 +0000 Subject: [PATCH 035/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 16130209aa..1b24b164ce 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c1d9e5c4ba43a9049e1470e1b08ef7039d3eabe34f483a5eaabf4ff18d4e9974.yml -openapi_spec_hash: a5650fa7fa230af9867db1efaa6ade3b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9cc47834e1666985a5ae1341c67ce570509422cd075fe5467edd8c00dc53213f.yml +openapi_spec_hash: 509872b62ebe2182855c3102f5286ba9 config_hash: 9e096c169b43682069730a4291c62d4a From a2bcb781e3ff109720492f6f71bfcde47a6317f7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:33:34 +0000 Subject: [PATCH 036/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1b24b164ce..7be9644939 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9cc47834e1666985a5ae1341c67ce570509422cd075fe5467edd8c00dc53213f.yml -openapi_spec_hash: 509872b62ebe2182855c3102f5286ba9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-92e5e5651b9ee691d24c7a775170ec27917e4de06613ad6fc6d82329f150675c.yml +openapi_spec_hash: 07a5f2fc1656cd858474997daa8c8f96 config_hash: 9e096c169b43682069730a4291c62d4a From ad353c641cbbfc1dcadb9394b2c5c3e846afe67c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:39:53 +0000 Subject: [PATCH 037/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7be9644939..eb3edc5d4e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-92e5e5651b9ee691d24c7a775170ec27917e4de06613ad6fc6d82329f150675c.yml -openapi_spec_hash: 07a5f2fc1656cd858474997daa8c8f96 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0ff1269522794871718450224a9111474658e16d065a037f60d4f44b12a12c70.yml +openapi_spec_hash: 98c67bff0005024b7c7d68261b4bed6f config_hash: 9e096c169b43682069730a4291c62d4a From 6326d891bdcc15c42dc7be8fd45432bdd31061d4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 16:36:22 +0000 Subject: [PATCH 038/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index eb3edc5d4e..4ddf092136 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0ff1269522794871718450224a9111474658e16d065a037f60d4f44b12a12c70.yml -openapi_spec_hash: 98c67bff0005024b7c7d68261b4bed6f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-70934da901922eb862da3aba05b17b42a13ca65fa88a89b7e0c4faa7326391ea.yml +openapi_spec_hash: 096257d75e7d5fefef56d88ee413eb23 config_hash: 9e096c169b43682069730a4291c62d4a From cd1c3239b74892874c83f12cd6e78de88c809c19 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 16:37:53 +0000 Subject: [PATCH 039/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4ddf092136..cec1e3a50f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-70934da901922eb862da3aba05b17b42a13ca65fa88a89b7e0c4faa7326391ea.yml -openapi_spec_hash: 096257d75e7d5fefef56d88ee413eb23 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-adc0ed694f51384aff0ba5b6c04741694904404ffa5547663afa13b1d230e6dd.yml +openapi_spec_hash: 5bb4adaa614e8fcc772ed7180970e02a config_hash: 9e096c169b43682069730a4291c62d4a From b29ee2cd869ea7b2f66bd2be100ef2da7ae5c928 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 17:28:11 +0000 Subject: [PATCH 040/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index cec1e3a50f..a8e111e30f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-adc0ed694f51384aff0ba5b6c04741694904404ffa5547663afa13b1d230e6dd.yml -openapi_spec_hash: 5bb4adaa614e8fcc772ed7180970e02a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-75a92b1f25d63f81fd723193358b7356ed796a5cfdc0d6259a7b03571b808782.yml +openapi_spec_hash: b2de0a8c1ed6cf256a9c3f541f955f37 config_hash: 9e096c169b43682069730a4291c62d4a From b48b88a9e452fc67d3e835fafc793bea86cb5214 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 17:29:40 +0000 Subject: [PATCH 041/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a8e111e30f..7fd97a2eb9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-75a92b1f25d63f81fd723193358b7356ed796a5cfdc0d6259a7b03571b808782.yml -openapi_spec_hash: b2de0a8c1ed6cf256a9c3f541f955f37 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-aa0337b305b3d79b209eefc114b2cbe293bdf128c75104b1d89887872e761d43.yml +openapi_spec_hash: 5a8202afb0d1d2050fcba0d5779d5169 config_hash: 9e096c169b43682069730a4291c62d4a From 199e51cdf908d5d048376af8b8e025395af28626 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:31:20 +0000 Subject: [PATCH 042/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7fd97a2eb9..ee87af4596 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-aa0337b305b3d79b209eefc114b2cbe293bdf128c75104b1d89887872e761d43.yml -openapi_spec_hash: 5a8202afb0d1d2050fcba0d5779d5169 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-903f6d63acbda9607e4791deb7427a3a8c7142ff19cedc5cfe75c4e6a345048c.yml +openapi_spec_hash: e4143e845d5c5b8016afeb1928cc6f71 config_hash: 9e096c169b43682069730a4291c62d4a From 0cc8457ad5c6dbb439a213201a1817718c656421 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:33:15 +0000 Subject: [PATCH 043/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ee87af4596..8db87ea464 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-903f6d63acbda9607e4791deb7427a3a8c7142ff19cedc5cfe75c4e6a345048c.yml -openapi_spec_hash: e4143e845d5c5b8016afeb1928cc6f71 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-57bc4e0d69b397012a04aaa76e4672c0c0ae3c6f38c9420a15ec0bddd4227846.yml +openapi_spec_hash: 93646b50bd878bc31823b293d87b47f1 config_hash: 9e096c169b43682069730a4291c62d4a From b94a7fe827f001c83ea8c345642a57356092731c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:36:14 +0000 Subject: [PATCH 044/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8db87ea464..332001739a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-57bc4e0d69b397012a04aaa76e4672c0c0ae3c6f38c9420a15ec0bddd4227846.yml -openapi_spec_hash: 93646b50bd878bc31823b293d87b47f1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bd55c0224e409315fee1e7aa43e5a2e4892df4e18d82ab13e355ba0363e3f256.yml +openapi_spec_hash: abac34e9bbe3e584e73c6cf77b714bc5 config_hash: 9e096c169b43682069730a4291c62d4a From 24f9ff303e39024482df3dd54d730ef2fd349e40 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:14:57 +0000 Subject: [PATCH 045/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 332001739a..e622797a13 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bd55c0224e409315fee1e7aa43e5a2e4892df4e18d82ab13e355ba0363e3f256.yml -openapi_spec_hash: abac34e9bbe3e584e73c6cf77b714bc5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-8f6b7acb72d565d6f5794184bf4688258692715a20ed3aa70b28bb1bc570aa94.yml +openapi_spec_hash: 4c9d388c0b5ffa9d80ecdda14726a66f config_hash: 9e096c169b43682069730a4291c62d4a From f7c9d9a63d37f903fab5cee4a2fe0a4df23c277e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:16:27 +0000 Subject: [PATCH 046/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index e622797a13..f713dbdeea 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-8f6b7acb72d565d6f5794184bf4688258692715a20ed3aa70b28bb1bc570aa94.yml -openapi_spec_hash: 4c9d388c0b5ffa9d80ecdda14726a66f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-56947bd2c6b1f4bf5f07ab0769508349faf77717a87391b1a2051f35d2bf0f8a.yml +openapi_spec_hash: 48b43ff43bc536686dbafb54cebab06d config_hash: 9e096c169b43682069730a4291c62d4a From 9dd59b638584f358a0108a43dd046c51d02880f9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:18:05 +0000 Subject: [PATCH 047/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f713dbdeea..11111124e7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-56947bd2c6b1f4bf5f07ab0769508349faf77717a87391b1a2051f35d2bf0f8a.yml -openapi_spec_hash: 48b43ff43bc536686dbafb54cebab06d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-84cdb42deaeb2cd022b8c1ef2bee405c477ae6c6e5fcbba48a8e1c4620cac5f8.yml +openapi_spec_hash: cf0a147de17fe592d20c05eba116cc87 config_hash: 9e096c169b43682069730a4291c62d4a From 4b0317838e67de6e143f1a5550e3549b8ffc4358 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:19:35 +0000 Subject: [PATCH 048/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 11111124e7..81043a01b1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-84cdb42deaeb2cd022b8c1ef2bee405c477ae6c6e5fcbba48a8e1c4620cac5f8.yml -openapi_spec_hash: cf0a147de17fe592d20c05eba116cc87 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6d58f921a51577ab0afb79f995570ac115e9a1f06c46f986895c2a5c10761205.yml +openapi_spec_hash: 492a14af63fee94b08b4435a3cfb361f config_hash: 9e096c169b43682069730a4291c62d4a From 86fbfb77728f07239b14df4b89e68327e3657721 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:21:01 +0000 Subject: [PATCH 049/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 81043a01b1..f0aa734c90 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6d58f921a51577ab0afb79f995570ac115e9a1f06c46f986895c2a5c10761205.yml -openapi_spec_hash: 492a14af63fee94b08b4435a3cfb361f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c9b26219d0146ef4151cb6ec3ba56f8093d085a706c3eee41dba4c5fbf2ea1ae.yml +openapi_spec_hash: 47fef79d2d528c7821d27b462dce754c config_hash: 9e096c169b43682069730a4291c62d4a From 06459683e59bb8d27753bdbae9a8faf6f64ade40 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 20:03:08 +0000 Subject: [PATCH 050/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f0aa734c90..318f25e910 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c9b26219d0146ef4151cb6ec3ba56f8093d085a706c3eee41dba4c5fbf2ea1ae.yml -openapi_spec_hash: 47fef79d2d528c7821d27b462dce754c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d3de6af5d824821ab36a7648910ac22729e4dac3ea1673ef92335c73ba3dc4af.yml +openapi_spec_hash: 14ced5a7ced400ccd1628e3890189b0c config_hash: 9e096c169b43682069730a4291c62d4a From 139b07e8d31fd5296d442574c3dd733803e71d1d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 20:05:19 +0000 Subject: [PATCH 051/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 318f25e910..4ddf092136 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d3de6af5d824821ab36a7648910ac22729e4dac3ea1673ef92335c73ba3dc4af.yml -openapi_spec_hash: 14ced5a7ced400ccd1628e3890189b0c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-70934da901922eb862da3aba05b17b42a13ca65fa88a89b7e0c4faa7326391ea.yml +openapi_spec_hash: 096257d75e7d5fefef56d88ee413eb23 config_hash: 9e096c169b43682069730a4291c62d4a From 2ab05f0e007a55f8385128f325ddcf11e4ecb229 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 20:07:48 +0000 Subject: [PATCH 052/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4ddf092136..68d620f902 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-70934da901922eb862da3aba05b17b42a13ca65fa88a89b7e0c4faa7326391ea.yml -openapi_spec_hash: 096257d75e7d5fefef56d88ee413eb23 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7c99d34533c8cdde024271eeff63042f5978c930937de5e80257eac7d4ef3921.yml +openapi_spec_hash: f2291b7d2c763855a8a43c60c220dce1 config_hash: 9e096c169b43682069730a4291c62d4a From b25620d26a837af8de6f2ce57c0bfb963bde2b66 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:17:41 +0000 Subject: [PATCH 053/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 68d620f902..f24c7ec838 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7c99d34533c8cdde024271eeff63042f5978c930937de5e80257eac7d4ef3921.yml -openapi_spec_hash: f2291b7d2c763855a8a43c60c220dce1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d6e8b85dc53b760548a67deef36714a2b22efcef27bda10255faf638629b9309.yml +openapi_spec_hash: ddf39a8be15f726b54505c5257add3c7 config_hash: 9e096c169b43682069730a4291c62d4a From 492d0890545853159ccf35784208152f89a375d8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:19:18 +0000 Subject: [PATCH 054/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f24c7ec838..265f5295a4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d6e8b85dc53b760548a67deef36714a2b22efcef27bda10255faf638629b9309.yml -openapi_spec_hash: ddf39a8be15f726b54505c5257add3c7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bec04dbc197f2b185830494be1b742d18b970817908ae2b09a1fc2dcbea1cafa.yml +openapi_spec_hash: 96ae4d868754cdb37936275c63a21c70 config_hash: 9e096c169b43682069730a4291c62d4a From 51cc2734dd0cbf232091d09d848dc83f152d4499 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 23:12:07 +0000 Subject: [PATCH 055/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 265f5295a4..cec1e3a50f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bec04dbc197f2b185830494be1b742d18b970817908ae2b09a1fc2dcbea1cafa.yml -openapi_spec_hash: 96ae4d868754cdb37936275c63a21c70 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-adc0ed694f51384aff0ba5b6c04741694904404ffa5547663afa13b1d230e6dd.yml +openapi_spec_hash: 5bb4adaa614e8fcc772ed7180970e02a config_hash: 9e096c169b43682069730a4291c62d4a From 887a1eb167dee69763c95ee0c689f39343cf9ac7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 23:13:59 +0000 Subject: [PATCH 056/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index cec1e3a50f..aeceaa7865 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-adc0ed694f51384aff0ba5b6c04741694904404ffa5547663afa13b1d230e6dd.yml -openapi_spec_hash: 5bb4adaa614e8fcc772ed7180970e02a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7c29b1d214b6a4e76e2ced67db66c4790d4e087506ad9cb94893bfc799d4e46c.yml +openapi_spec_hash: 6dfa5d19b8e15737b8b54db21fff9c57 config_hash: 9e096c169b43682069730a4291c62d4a From 12a004067b2c312dab11eb8c877b728b729885d8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 00:12:55 +0000 Subject: [PATCH 057/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index aeceaa7865..7745ea7b58 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7c29b1d214b6a4e76e2ced67db66c4790d4e087506ad9cb94893bfc799d4e46c.yml -openapi_spec_hash: 6dfa5d19b8e15737b8b54db21fff9c57 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6ce9e39e60d3c345a61172a18384864abbdb7451cb1dba283f50598889d49a3c.yml +openapi_spec_hash: 7c7bfd44f65a34e81d5c446247f0a9bf config_hash: 9e096c169b43682069730a4291c62d4a From e27e114a9b202a61f875ef6dfef91e442a3d0254 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 00:14:41 +0000 Subject: [PATCH 058/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7745ea7b58..d7c97d71aa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6ce9e39e60d3c345a61172a18384864abbdb7451cb1dba283f50598889d49a3c.yml -openapi_spec_hash: 7c7bfd44f65a34e81d5c446247f0a9bf +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-73c9cb18e9d579ddfa8a6f0350c406b16d080f9754e0a9f47b335a36687b0cb8.yml +openapi_spec_hash: 6cbd9d58b303124692ff3b7c80cefc50 config_hash: 9e096c169b43682069730a4291c62d4a From c48798ff5a79adce1311f2023cd4f33d65f1368c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 06:08:07 +0000 Subject: [PATCH 059/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d7c97d71aa..4ddf092136 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-73c9cb18e9d579ddfa8a6f0350c406b16d080f9754e0a9f47b335a36687b0cb8.yml -openapi_spec_hash: 6cbd9d58b303124692ff3b7c80cefc50 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-70934da901922eb862da3aba05b17b42a13ca65fa88a89b7e0c4faa7326391ea.yml +openapi_spec_hash: 096257d75e7d5fefef56d88ee413eb23 config_hash: 9e096c169b43682069730a4291c62d4a From cde3e06cd3aba254aab2984a78a10f94d6a7cfa7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 06:10:24 +0000 Subject: [PATCH 060/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4ddf092136..7faa31a622 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-70934da901922eb862da3aba05b17b42a13ca65fa88a89b7e0c4faa7326391ea.yml -openapi_spec_hash: 096257d75e7d5fefef56d88ee413eb23 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-db2f9d242d107deab5e4d69d606bd54ebd003e54e94156f136ca1324df334c7f.yml +openapi_spec_hash: bdf1d4cf0ae9861c64a4c4b22e551924 config_hash: 9e096c169b43682069730a4291c62d4a From 060b0225f9df32cb7c20efa3be7dc811cb86bb86 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 09:32:44 +0000 Subject: [PATCH 061/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7faa31a622..b030dd3e6d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-db2f9d242d107deab5e4d69d606bd54ebd003e54e94156f136ca1324df334c7f.yml -openapi_spec_hash: bdf1d4cf0ae9861c64a4c4b22e551924 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-da85a5e0c248a58ff0d95db4bc77e6be504fb63f8b8dcb4e65c9453f1f767152.yml +openapi_spec_hash: a6b2a5b6bf529bf25b8f80857c2911b2 config_hash: 9e096c169b43682069730a4291c62d4a From f40f473867777d4a40af3c7534bc5c2a7f50e6ab Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 12:28:25 +0000 Subject: [PATCH 062/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b030dd3e6d..48fd2f3e26 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-da85a5e0c248a58ff0d95db4bc77e6be504fb63f8b8dcb4e65c9453f1f767152.yml -openapi_spec_hash: a6b2a5b6bf529bf25b8f80857c2911b2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-4d71d3db7336587e78774cdb927c53c8646be019bbb032201ff198b4fd9ea707.yml +openapi_spec_hash: 44c405a3d4cda9f2bd55686bef79f3e2 config_hash: 9e096c169b43682069730a4291c62d4a From 7954dbcd514fe39673a3a492aa513014a3fe67ac Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:37:50 +0000 Subject: [PATCH 063/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 48fd2f3e26..cb39a576f9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-4d71d3db7336587e78774cdb927c53c8646be019bbb032201ff198b4fd9ea707.yml -openapi_spec_hash: 44c405a3d4cda9f2bd55686bef79f3e2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a359f271891b014c73c3d4d342f22abfbeb36bd8eb66dbdcb951fa02c91b9a04.yml +openapi_spec_hash: 6c9b7d296ddc8265a5f7894f15207dcd config_hash: 9e096c169b43682069730a4291c62d4a From d1cd638047c045ae95b4f63d72346748b4e296f7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:48:39 +0000 Subject: [PATCH 064/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index cb39a576f9..78952bf779 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a359f271891b014c73c3d4d342f22abfbeb36bd8eb66dbdcb951fa02c91b9a04.yml -openapi_spec_hash: 6c9b7d296ddc8265a5f7894f15207dcd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-e341e6b99986a582a6f62a91df3c195578789a1449725c1992e7baab9968b7cd.yml +openapi_spec_hash: 18e1d9b29fed67b1c2eefc4033727028 config_hash: 9e096c169b43682069730a4291c62d4a From a6b68dc68d99b5168bf34f3e4d8f1c7d64358dfd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:53:31 +0000 Subject: [PATCH 065/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 78952bf779..c3768fb167 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-e341e6b99986a582a6f62a91df3c195578789a1449725c1992e7baab9968b7cd.yml -openapi_spec_hash: 18e1d9b29fed67b1c2eefc4033727028 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-38118aeb8d98024487e7ed131f71513d92cc2755d1fa142e0595a8f16da253f7.yml +openapi_spec_hash: ac59cca36c7c1984186692bead828e03 config_hash: 9e096c169b43682069730a4291c62d4a From 4fd31f81fb06d9d5819ff886a1b6c93ee2bb0f76 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:30:23 +0000 Subject: [PATCH 066/187] feat(api): api update --- .stats.yml | 4 ++-- .../resource.tf | 3 --- .../zero_trust_gateway_settings/data_source_model.go | 5 ----- .../zero_trust_gateway_settings/data_source_schema.go | 11 ----------- .../services/zero_trust_gateway_settings/model.go | 5 ----- .../services/zero_trust_gateway_settings/schema.go | 10 ---------- 6 files changed, 2 insertions(+), 36 deletions(-) diff --git a/.stats.yml b/.stats.yml index c3768fb167..975ab24fac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-38118aeb8d98024487e7ed131f71513d92cc2755d1fa142e0595a8f16da253f7.yml -openapi_spec_hash: ac59cca36c7c1984186692bead828e03 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d66cccbb6e68a04a563b4b97948a510c4575857b8ca14bd89490ad4a67dfcf98.yml +openapi_spec_hash: 64ed30f8af381273583738989e6019bc config_hash: 9e096c169b43682069730a4291c62d4a diff --git a/examples/resources/cloudflare_zero_trust_gateway_settings/resource.tf b/examples/resources/cloudflare_zero_trust_gateway_settings/resource.tf index 148f41f287..1bff7690d5 100644 --- a/examples/resources/cloudflare_zero_trust_gateway_settings/resource.tf +++ b/examples/resources/cloudflare_zero_trust_gateway_settings/resource.tf @@ -15,9 +15,6 @@ resource "cloudflare_zero_trust_gateway_settings" "example_zero_trust_gateway_se support_url = "support_url" } } - app_control_settings = { - enabled = false - } block_page = { background_color = "background_color" enabled = true diff --git a/internal/services/zero_trust_gateway_settings/data_source_model.go b/internal/services/zero_trust_gateway_settings/data_source_model.go index 032ba6de59..bd3d124384 100644 --- a/internal/services/zero_trust_gateway_settings/data_source_model.go +++ b/internal/services/zero_trust_gateway_settings/data_source_model.go @@ -35,7 +35,6 @@ func (m *ZeroTrustGatewaySettingsDataSourceModel) toReadParams(_ context.Context type ZeroTrustGatewaySettingsSettingsDataSourceModel struct { ActivityLog customfield.NestedObject[ZeroTrustGatewaySettingsSettingsActivityLogDataSourceModel] `tfsdk:"activity_log" json:"activity_log,computed"` Antivirus customfield.NestedObject[ZeroTrustGatewaySettingsSettingsAntivirusDataSourceModel] `tfsdk:"antivirus" json:"antivirus,computed"` - AppControlSettings customfield.NestedObject[ZeroTrustGatewaySettingsSettingsAppControlSettingsDataSourceModel] `tfsdk:"app_control_settings" json:"app-control-settings,computed"` BlockPage customfield.NestedObject[ZeroTrustGatewaySettingsSettingsBlockPageDataSourceModel] `tfsdk:"block_page" json:"block_page,computed"` BodyScanning customfield.NestedObject[ZeroTrustGatewaySettingsSettingsBodyScanningDataSourceModel] `tfsdk:"body_scanning" json:"body_scanning,computed"` BrowserIsolation customfield.NestedObject[ZeroTrustGatewaySettingsSettingsBrowserIsolationDataSourceModel] `tfsdk:"browser_isolation" json:"browser_isolation,computed"` @@ -67,10 +66,6 @@ type ZeroTrustGatewaySettingsSettingsAntivirusNotificationSettingsDataSourceMode SupportURL types.String `tfsdk:"support_url" json:"support_url,computed"` } -type ZeroTrustGatewaySettingsSettingsAppControlSettingsDataSourceModel struct { - Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` -} - type ZeroTrustGatewaySettingsSettingsBlockPageDataSourceModel struct { BackgroundColor types.String `tfsdk:"background_color" json:"background_color,computed"` Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` diff --git a/internal/services/zero_trust_gateway_settings/data_source_schema.go b/internal/services/zero_trust_gateway_settings/data_source_schema.go index e710c5fb6d..fbf7fa27fd 100644 --- a/internal/services/zero_trust_gateway_settings/data_source_schema.go +++ b/internal/services/zero_trust_gateway_settings/data_source_schema.go @@ -87,17 +87,6 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, - "app_control_settings": schema.SingleNestedAttribute{ - Description: "Setting to enable App Control", - Computed: true, - CustomType: customfield.NewNestedObjectType[ZeroTrustGatewaySettingsSettingsAppControlSettingsDataSourceModel](ctx), - Attributes: map[string]schema.Attribute{ - "enabled": schema.BoolAttribute{ - Description: "Enable App Control", - Computed: true, - }, - }, - }, "block_page": schema.SingleNestedAttribute{ Description: "Block page layout settings.", Computed: true, diff --git a/internal/services/zero_trust_gateway_settings/model.go b/internal/services/zero_trust_gateway_settings/model.go index d5989d54cf..dda7321cdf 100644 --- a/internal/services/zero_trust_gateway_settings/model.go +++ b/internal/services/zero_trust_gateway_settings/model.go @@ -32,7 +32,6 @@ func (m ZeroTrustGatewaySettingsModel) MarshalJSONForUpdate(state ZeroTrustGatew type ZeroTrustGatewaySettingsSettingsModel struct { ActivityLog *ZeroTrustGatewaySettingsSettingsActivityLogModel `tfsdk:"activity_log" json:"activity_log,optional"` Antivirus *ZeroTrustGatewaySettingsSettingsAntivirusModel `tfsdk:"antivirus" json:"antivirus,optional"` - AppControlSettings *ZeroTrustGatewaySettingsSettingsAppControlSettingsModel `tfsdk:"app_control_settings" json:"app-control-settings,optional"` BlockPage customfield.NestedObject[ZeroTrustGatewaySettingsSettingsBlockPageModel] `tfsdk:"block_page" json:"block_page,computed_optional"` BodyScanning *ZeroTrustGatewaySettingsSettingsBodyScanningModel `tfsdk:"body_scanning" json:"body_scanning,optional"` BrowserIsolation *ZeroTrustGatewaySettingsSettingsBrowserIsolationModel `tfsdk:"browser_isolation" json:"browser_isolation,optional"` @@ -64,10 +63,6 @@ type ZeroTrustGatewaySettingsSettingsAntivirusNotificationSettingsModel struct { SupportURL types.String `tfsdk:"support_url" json:"support_url,optional"` } -type ZeroTrustGatewaySettingsSettingsAppControlSettingsModel struct { - Enabled types.Bool `tfsdk:"enabled" json:"enabled,optional"` -} - type ZeroTrustGatewaySettingsSettingsBlockPageModel struct { BackgroundColor types.String `tfsdk:"background_color" json:"background_color,optional"` Enabled types.Bool `tfsdk:"enabled" json:"enabled,optional"` diff --git a/internal/services/zero_trust_gateway_settings/schema.go b/internal/services/zero_trust_gateway_settings/schema.go index bbc0cca09b..218da3955d 100644 --- a/internal/services/zero_trust_gateway_settings/schema.go +++ b/internal/services/zero_trust_gateway_settings/schema.go @@ -85,16 +85,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, - "app_control_settings": schema.SingleNestedAttribute{ - Description: "Setting to enable App Control", - Optional: true, - Attributes: map[string]schema.Attribute{ - "enabled": schema.BoolAttribute{ - Description: "Enable App Control", - Optional: true, - }, - }, - }, "block_page": schema.SingleNestedAttribute{ Description: "Block page layout settings.", Computed: true, From 2be036a8e6ee0f0d7f229d36993040b95fa6abf5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:32:12 +0000 Subject: [PATCH 067/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 975ab24fac..c7ccb4a5e5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d66cccbb6e68a04a563b4b97948a510c4575857b8ca14bd89490ad4a67dfcf98.yml -openapi_spec_hash: 64ed30f8af381273583738989e6019bc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-01e4580b68e733092b0f1d47da05225ee0e66993968786fe047bab4715605ee5.yml +openapi_spec_hash: 6290eb2355f5e7033eeb6aa4f2708aef config_hash: 9e096c169b43682069730a4291c62d4a From 127957d14471cbb122ad2196f9748eb61c3d8730 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:15:20 +0000 Subject: [PATCH 068/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c7ccb4a5e5..bd5d46e2f1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-01e4580b68e733092b0f1d47da05225ee0e66993968786fe047bab4715605ee5.yml -openapi_spec_hash: 6290eb2355f5e7033eeb6aa4f2708aef +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b45da271fede9a1b0d86e7214a1929d4c58185a7ba4a13b81dbc810ae28bc946.yml +openapi_spec_hash: 12c96c5a3be55ca50041304e4fa879cb config_hash: 9e096c169b43682069730a4291c62d4a From 42613a44dc1651429063d01c2df089c9cd1ece3d Mon Sep 17 00:00:00 2001 From: Vaishak Dinesh Date: Tue, 24 Jun 2025 11:24:03 -0700 Subject: [PATCH 069/187] chore: update docs --- docs/data-sources/logpush_dataset_job.md | 4 ++-- docs/data-sources/logpush_job.md | 4 ++-- docs/data-sources/logpush_jobs.md | 4 ++-- docs/data-sources/workers_kv.md | 2 +- docs/data-sources/workers_kv_namespace.md | 2 +- docs/data-sources/workers_kv_namespaces.md | 2 +- docs/data-sources/zero_trust_dlp_custom_profile.md | 2 +- docs/data-sources/zero_trust_dlp_entries.md | 2 +- docs/data-sources/zero_trust_dlp_entry.md | 2 +- .../zero_trust_dlp_predefined_profile.md | 2 +- docs/data-sources/zero_trust_gateway_settings.md | 9 --------- docs/guides/migrating-renamed-resources.md | 2 -- docs/resources/dns_record.md | 2 +- docs/resources/image.md | 5 ++++- docs/resources/logpush_job.md | 6 +++--- docs/resources/ruleset.md | 1 - docs/resources/workers_kv.md | 8 +++++--- docs/resources/workers_kv_namespace.md | 2 +- docs/resources/zero_trust_dlp_custom_profile.md | 2 +- docs/resources/zero_trust_gateway_settings.md | 12 ------------ docs/resources/zero_trust_list.md | 6 +----- examples/resources/cloudflare_ruleset/resource.tf | 1 - 22 files changed, 29 insertions(+), 53 deletions(-) diff --git a/docs/data-sources/logpush_dataset_job.md b/docs/data-sources/logpush_dataset_job.md index 6ff9322462..b7ecdd80a9 100644 --- a/docs/data-sources/logpush_dataset_job.md +++ b/docs/data-sources/logpush_dataset_job.md @@ -39,8 +39,8 @@ Available values: "access_requests", "audit_logs", "biso_user_actions", "casb_fi - `frequency` (String, Deprecated) This field is deprecated. Please use `max_upload_*` parameters instead. The frequency at which Cloudflare sends batches of logs to your destination. Setting frequency to high sends your logs in larger quantities of smaller files. Setting frequency to low sends logs in smaller quantities of larger files. Available values: "high", "low". - `id` (Number) Unique id of the job. -- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset. -Available values: "edge". +- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs (when supported by the dataset). +Available values: "", "edge". - `last_complete` (String) Records the last time for which logs have been successfully pushed. If the last successful push was for logs range 2018-07-23T10:00:00Z to 2018-07-23T10:01:00Z then the value of this field will be 2018-07-23T10:01:00Z. If the job has never run or has just been enabled and hasn't run yet then the field will be empty. - `last_error` (String) Records the last time the job failed. If not null, the job is currently failing. If null, the job has either never failed or has run successfully at least once since last failure. See also the error_message field. - `logpull_options` (String, Deprecated) This field is deprecated. Use `output_options` instead. Configuration string. It specifies things like requested fields and timestamp formats. If migrating from the logpull api, copy the url (full url or just the query string) of your call here, and logpush will keep on making this call for you, setting start and end times appropriately. diff --git a/docs/data-sources/logpush_job.md b/docs/data-sources/logpush_job.md index 0bdd8960ab..5bfb7c06ef 100644 --- a/docs/data-sources/logpush_job.md +++ b/docs/data-sources/logpush_job.md @@ -38,8 +38,8 @@ Available values: "access_requests", "audit_logs", "biso_user_actions", "casb_fi - `frequency` (String, Deprecated) This field is deprecated. Please use `max_upload_*` parameters instead. The frequency at which Cloudflare sends batches of logs to your destination. Setting frequency to high sends your logs in larger quantities of smaller files. Setting frequency to low sends logs in smaller quantities of larger files. Available values: "high", "low". - `id` (Number) Unique id of the job. -- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset. -Available values: "edge". +- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs (when supported by the dataset). +Available values: "", "edge". - `last_complete` (String) Records the last time for which logs have been successfully pushed. If the last successful push was for logs range 2018-07-23T10:00:00Z to 2018-07-23T10:01:00Z then the value of this field will be 2018-07-23T10:01:00Z. If the job has never run or has just been enabled and hasn't run yet then the field will be empty. - `last_error` (String) Records the last time the job failed. If not null, the job is currently failing. If null, the job has either never failed or has run successfully at least once since last failure. See also the error_message field. - `logpull_options` (String, Deprecated) This field is deprecated. Use `output_options` instead. Configuration string. It specifies things like requested fields and timestamp formats. If migrating from the logpull api, copy the url (full url or just the query string) of your call here, and logpush will keep on making this call for you, setting start and end times appropriately. diff --git a/docs/data-sources/logpush_jobs.md b/docs/data-sources/logpush_jobs.md index 66cbf404a8..a847d32a09 100644 --- a/docs/data-sources/logpush_jobs.md +++ b/docs/data-sources/logpush_jobs.md @@ -44,8 +44,8 @@ Available values: "access_requests", "audit_logs", "biso_user_actions", "casb_fi - `frequency` (String, Deprecated) This field is deprecated. Please use `max_upload_*` parameters instead. The frequency at which Cloudflare sends batches of logs to your destination. Setting frequency to high sends your logs in larger quantities of smaller files. Setting frequency to low sends logs in smaller quantities of larger files. Available values: "high", "low". - `id` (Number) Unique id of the job. -- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset. -Available values: "edge". +- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs (when supported by the dataset). +Available values: "", "edge". - `last_complete` (String) Records the last time for which logs have been successfully pushed. If the last successful push was for logs range 2018-07-23T10:00:00Z to 2018-07-23T10:01:00Z then the value of this field will be 2018-07-23T10:01:00Z. If the job has never run or has just been enabled and hasn't run yet then the field will be empty. - `last_error` (String) Records the last time the job failed. If not null, the job is currently failing. If null, the job has either never failed or has run successfully at least once since last failure. See also the error_message field. - `logpull_options` (String, Deprecated) This field is deprecated. Use `output_options` instead. Configuration string. It specifies things like requested fields and timestamp formats. If migrating from the logpull api, copy the url (full url or just the query string) of your call here, and logpush will keep on making this call for you, setting start and end times appropriately. diff --git a/docs/data-sources/workers_kv.md b/docs/data-sources/workers_kv.md index 65490c3ecd..b9f77974aa 100644 --- a/docs/data-sources/workers_kv.md +++ b/docs/data-sources/workers_kv.md @@ -24,7 +24,7 @@ data "cloudflare_workers_kv" "example_workers_kv" { ### Required -- `account_id` (String) Identifier +- `account_id` (String) Identifier. - `key_name` (String) A key's name. The name may be at most 512 bytes. All printable, non-whitespace characters are valid. Use percent-encoding to define key names as part of a URL. - `namespace_id` (String) Namespace identifier tag. diff --git a/docs/data-sources/workers_kv_namespace.md b/docs/data-sources/workers_kv_namespace.md index b8edea9d87..48a13be296 100644 --- a/docs/data-sources/workers_kv_namespace.md +++ b/docs/data-sources/workers_kv_namespace.md @@ -23,7 +23,7 @@ data "cloudflare_workers_kv_namespace" "example_workers_kv_namespace" { ### Required -- `account_id` (String) Identifier +- `account_id` (String) Identifier. ### Optional diff --git a/docs/data-sources/workers_kv_namespaces.md b/docs/data-sources/workers_kv_namespaces.md index 265660c806..abcd983ae1 100644 --- a/docs/data-sources/workers_kv_namespaces.md +++ b/docs/data-sources/workers_kv_namespaces.md @@ -24,7 +24,7 @@ data "cloudflare_workers_kv_namespaces" "example_workers_kv_namespaces" { ### Required -- `account_id` (String) Identifier +- `account_id` (String) Identifier. ### Optional diff --git a/docs/data-sources/zero_trust_dlp_custom_profile.md b/docs/data-sources/zero_trust_dlp_custom_profile.md index 0354e2f7bd..85dd9ced1f 100644 --- a/docs/data-sources/zero_trust_dlp_custom_profile.md +++ b/docs/data-sources/zero_trust_dlp_custom_profile.md @@ -75,7 +75,7 @@ Cannot be set to false if secret is true - `pattern` (Attributes) (see [below for nested schema](#nestedatt--entries--pattern)) - `profile_id` (String) - `secret` (Boolean) -- `type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_template", "word_list". +- `type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint", "word_list". - `updated_at` (String) - `word_list` (String) diff --git a/docs/data-sources/zero_trust_dlp_entries.md b/docs/data-sources/zero_trust_dlp_entries.md index 8ce909b225..3ea327e881 100644 --- a/docs/data-sources/zero_trust_dlp_entries.md +++ b/docs/data-sources/zero_trust_dlp_entries.md @@ -48,7 +48,7 @@ Cannot be set to false if secret is true - `pattern` (Attributes) (see [below for nested schema](#nestedatt--result--pattern)) - `profile_id` (String) - `secret` (Boolean) -- `type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_template", "word_list". +- `type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint", "word_list". - `updated_at` (String) - `word_list` (String) diff --git a/docs/data-sources/zero_trust_dlp_entry.md b/docs/data-sources/zero_trust_dlp_entry.md index 4dbefa1420..80d12ca282 100644 --- a/docs/data-sources/zero_trust_dlp_entry.md +++ b/docs/data-sources/zero_trust_dlp_entry.md @@ -42,7 +42,7 @@ Cannot be set to false if secret is true - `pattern` (Attributes) (see [below for nested schema](#nestedatt--pattern)) - `profile_id` (String) - `secret` (Boolean) -- `type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_template", "word_list". +- `type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint", "word_list". - `updated_at` (String) - `word_list` (String) diff --git a/docs/data-sources/zero_trust_dlp_predefined_profile.md b/docs/data-sources/zero_trust_dlp_predefined_profile.md index 9a1110f234..539f0af48d 100644 --- a/docs/data-sources/zero_trust_dlp_predefined_profile.md +++ b/docs/data-sources/zero_trust_dlp_predefined_profile.md @@ -75,7 +75,7 @@ Cannot be set to false if secret is true - `pattern` (Attributes) (see [below for nested schema](#nestedatt--entries--pattern)) - `profile_id` (String) - `secret` (Boolean) -- `type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_template", "word_list". +- `type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint", "word_list". - `updated_at` (String) - `word_list` (String) diff --git a/docs/data-sources/zero_trust_gateway_settings.md b/docs/data-sources/zero_trust_gateway_settings.md index d92708fb56..5580f651c8 100644 --- a/docs/data-sources/zero_trust_gateway_settings.md +++ b/docs/data-sources/zero_trust_gateway_settings.md @@ -37,7 +37,6 @@ Read-Only: - `activity_log` (Attributes) Activity log settings. (see [below for nested schema](#nestedatt--settings--activity_log)) - `antivirus` (Attributes) Anti-virus settings. (see [below for nested schema](#nestedatt--settings--antivirus)) -- `app_control_settings` (Attributes) Setting to enable App Control (see [below for nested schema](#nestedatt--settings--app_control_settings)) - `block_page` (Attributes) Block page layout settings. (see [below for nested schema](#nestedatt--settings--block_page)) - `body_scanning` (Attributes) DLP body scanning settings. (see [below for nested schema](#nestedatt--settings--body_scanning)) - `browser_isolation` (Attributes) Browser isolation settings. (see [below for nested schema](#nestedatt--settings--browser_isolation)) @@ -80,14 +79,6 @@ Read-Only: - -### Nested Schema for `settings.app_control_settings` - -Read-Only: - -- `enabled` (Boolean) Enable App Control - - ### Nested Schema for `settings.block_page` diff --git a/docs/guides/migrating-renamed-resources.md b/docs/guides/migrating-renamed-resources.md index 9094aa139f..5c3a3530d7 100644 --- a/docs/guides/migrating-renamed-resources.md +++ b/docs/guides/migrating-renamed-resources.md @@ -21,8 +21,6 @@ description: Guide for handling renamed resources in the Cloudflare Provider environment or a small subset resources before performing the changes to all resources. -NOTE: use the environment variable `GRIT_MAX_FILE_SIZE_BYTES=0` if the state file is too big and grit errors out. - ## Using import -> Recommended for most users and migrations. diff --git a/docs/resources/dns_record.md b/docs/resources/dns_record.md index f01b7488c9..a23cb0b36e 100644 --- a/docs/resources/dns_record.md +++ b/docs/resources/dns_record.md @@ -15,6 +15,7 @@ description: |- resource "cloudflare_dns_record" "example_dns_record" { zone_id = "023e105f4ecef8ad9ca31a8372d0c353" name = "example.com" + ttl = 3600 type = "A" comment = "Domain verification record" content = "198.51.100.4" @@ -24,7 +25,6 @@ resource "cloudflare_dns_record" "example_dns_record" { ipv6_only = true } tags = ["owner:dns-team"] - ttl = 3600 } ``` diff --git a/docs/resources/image.md b/docs/resources/image.md index fbde4aabf7..1ca40ab66f 100644 --- a/docs/resources/image.md +++ b/docs/resources/image.md @@ -14,6 +14,9 @@ description: |- ```terraform resource "cloudflare_image" "example_image" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" + id = { + + } file = { } @@ -31,6 +34,7 @@ resource "cloudflare_image" "example_image" { ### Required - `account_id` (String) Account identifier tag. +- `id` (String) An optional custom unique identifier for your image. ### Optional @@ -42,7 +46,6 @@ resource "cloudflare_image" "example_image" { ### Read-Only - `filename` (String) Image file name. -- `id` (String) Image unique identifier. - `meta` (String) User modifiable key-value store. Can be used for keeping references to another system of record for managing images. Metadata must not exceed 1024 bytes. - `uploaded` (String) When the media item was uploaded. - `variants` (List of String) Object specifying available variants for an image. diff --git a/docs/resources/logpush_job.md b/docs/resources/logpush_job.md index fc716e6256..e59f7a05ef 100644 --- a/docs/resources/logpush_job.md +++ b/docs/resources/logpush_job.md @@ -19,7 +19,7 @@ resource "cloudflare_logpush_job" "example_logpush_job" { enabled = false filter = "{\"where\":{\"and\":[{\"key\":\"ClientRequestPath\",\"operator\":\"contains\",\"value\":\"/static\"},{\"key\":\"ClientRequestHost\",\"operator\":\"eq\",\"value\":\"example.com\"}]}}" frequency = "high" - kind = "edge" + kind = "" logpull_options = "fields=RayID,ClientIP,EdgeStartTimestamp×tamps=rfc3339" max_upload_bytes = 5000000 max_upload_interval_seconds = 30 @@ -59,8 +59,8 @@ Available values: "access_requests", "audit_logs", "biso_user_actions", "casb_fi - `filter` (String) The filters to select the events to include and/or remove from your logs. For more information, refer to [Filters](https://developers.cloudflare.com/logs/reference/filters/). - `frequency` (String, Deprecated) This field is deprecated. Please use `max_upload_*` parameters instead. The frequency at which Cloudflare sends batches of logs to your destination. Setting frequency to high sends your logs in larger quantities of smaller files. Setting frequency to low sends logs in smaller quantities of larger files. Available values: "high", "low". -- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset. -Available values: "edge". +- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs (when supported by the dataset). +Available values: "", "edge". - `logpull_options` (String, Deprecated) This field is deprecated. Use `output_options` instead. Configuration string. It specifies things like requested fields and timestamp formats. If migrating from the logpull api, copy the url (full url or just the query string) of your call here, and logpush will keep on making this call for you, setting start and end times appropriately. - `max_upload_bytes` (Number) The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size. This parameter is not available for jobs with `edge` as its kind. - `max_upload_interval_seconds` (Number) The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this. This parameter is only used for jobs with `edge` as its kind. diff --git a/docs/resources/ruleset.md b/docs/resources/ruleset.md index d5364357b5..eb997bfe9f 100644 --- a/docs/resources/ruleset.md +++ b/docs/resources/ruleset.md @@ -19,7 +19,6 @@ resource "cloudflare_ruleset" "example_ruleset" { zone_id = "zone_id" description = "My ruleset to execute managed rulesets" rules = [{ - id = "3a03d665bac047339bb530ecb439a90d" action = "block" action_parameters = { response = { diff --git a/docs/resources/workers_kv.md b/docs/resources/workers_kv.md index baa91ac1bd..66b4d7df92 100644 --- a/docs/resources/workers_kv.md +++ b/docs/resources/workers_kv.md @@ -16,8 +16,10 @@ resource "cloudflare_workers_kv" "example_workers_kv" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" namespace_id = "0f2ac74b498b48028cb68387c421e279" key_name = "My-Key" - metadata = "{\"someMetadataKey\": \"someMetadataValue\"}" value = "Some Value" + metadata = { + + } } ``` @@ -26,14 +28,14 @@ resource "cloudflare_workers_kv" "example_workers_kv" { ### Required -- `account_id` (String) Identifier +- `account_id` (String) Identifier. - `key_name` (String) A key's name. The name may be at most 512 bytes. All printable, non-whitespace characters are valid. Use percent-encoding to define key names as part of a URL. - `namespace_id` (String) Namespace identifier tag. - `value` (String) A byte sequence to be stored, up to 25 MiB in length. ### Optional -- `metadata` (String) Arbitrary JSON to be associated with a key/value pair. +- `metadata` (String) ### Read-Only diff --git a/docs/resources/workers_kv_namespace.md b/docs/resources/workers_kv_namespace.md index c72b3cfd7a..11aefebc96 100644 --- a/docs/resources/workers_kv_namespace.md +++ b/docs/resources/workers_kv_namespace.md @@ -23,7 +23,7 @@ resource "cloudflare_workers_kv_namespace" "example_workers_kv_namespace" { ### Required -- `account_id` (String) Identifier +- `account_id` (String) Identifier. - `title` (String) A human-readable string name for a Namespace. ### Read-Only diff --git a/docs/resources/zero_trust_dlp_custom_profile.md b/docs/resources/zero_trust_dlp_custom_profile.md index ee81a368aa..f3df2be443 100644 --- a/docs/resources/zero_trust_dlp_custom_profile.md +++ b/docs/resources/zero_trust_dlp_custom_profile.md @@ -119,7 +119,7 @@ Required: - `enabled` (Boolean) - `entry_id` (String) -- `entry_type` (String) Available values: "custom", "predefined", "integration", "exact_data". +- `entry_type` (String) Available values: "custom", "predefined", "integration", "exact_data", "document_fingerprint". ## Import diff --git a/docs/resources/zero_trust_gateway_settings.md b/docs/resources/zero_trust_gateway_settings.md index 9360f68bca..69c7b8736f 100644 --- a/docs/resources/zero_trust_gateway_settings.md +++ b/docs/resources/zero_trust_gateway_settings.md @@ -29,9 +29,6 @@ resource "cloudflare_zero_trust_gateway_settings" "example_zero_trust_gateway_se support_url = "support_url" } } - app_control_settings = { - enabled = false - } block_page = { background_color = "background_color" enabled = true @@ -107,7 +104,6 @@ Optional: - `activity_log` (Attributes) Activity log settings. (see [below for nested schema](#nestedatt--settings--activity_log)) - `antivirus` (Attributes) Anti-virus settings. (see [below for nested schema](#nestedatt--settings--antivirus)) -- `app_control_settings` (Attributes) Setting to enable App Control (see [below for nested schema](#nestedatt--settings--app_control_settings)) - `block_page` (Attributes) Block page layout settings. (see [below for nested schema](#nestedatt--settings--block_page)) - `body_scanning` (Attributes) DLP body scanning settings. (see [below for nested schema](#nestedatt--settings--body_scanning)) - `browser_isolation` (Attributes) Browser isolation settings. (see [below for nested schema](#nestedatt--settings--browser_isolation)) @@ -150,14 +146,6 @@ Optional: - -### Nested Schema for `settings.app_control_settings` - -Optional: - -- `enabled` (Boolean) Enable App Control - - ### Nested Schema for `settings.block_page` diff --git a/docs/resources/zero_trust_list.md b/docs/resources/zero_trust_list.md index 673c738349..c68dae0406 100644 --- a/docs/resources/zero_trust_list.md +++ b/docs/resources/zero_trust_list.md @@ -37,7 +37,7 @@ Available values: "SERIAL", "URL", "DOMAIN", "EMAIL", "IP". ### Optional - `description` (String) The description of the list. -- `items` (Attributes List) The items in the list. (see [below for nested schema](#nestedatt--items)) +- `items` (Attributes List) items to add to the list. (see [below for nested schema](#nestedatt--items)) ### Read-Only @@ -54,10 +54,6 @@ Optional: - `description` (String) The description of the list item, if present - `value` (String) The value of the item in a list. -Read-Only: - -- `created_at` (String) - ## Import Import is supported using the following syntax: diff --git a/examples/resources/cloudflare_ruleset/resource.tf b/examples/resources/cloudflare_ruleset/resource.tf index c255defc5a..7378c2d833 100644 --- a/examples/resources/cloudflare_ruleset/resource.tf +++ b/examples/resources/cloudflare_ruleset/resource.tf @@ -5,7 +5,6 @@ resource "cloudflare_ruleset" "example_ruleset" { zone_id = "zone_id" description = "My ruleset to execute managed rulesets" rules = [{ - id = "3a03d665bac047339bb530ecb439a90d" action = "block" action_parameters = { response = { From bedbc6b27666917c5ab428d92b2fb863d6cdaf29 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:03:11 +0000 Subject: [PATCH 070/187] feat(api): api update --- .stats.yml | 6 +- .../data-source.tf | 4 + .../data-source.tf | 12 + .../import.sh | 1 + .../resource.tf | 4 + internal/provider.go | 4 + .../data_source.go | 118 ++++++++ .../data_source_model.go | 109 ++++++++ .../data_source_schema.go | 202 ++++++++++++++ .../data_source_schema_test.go | 19 ++ .../list_data_source.go | 100 +++++++ .../list_data_source_model.go | 101 +++++++ .../list_data_source_schema.go | 206 ++++++++++++++ .../list_data_source_schema_test.go | 19 ++ .../migrations.go | 15 + .../zero_trust_tunnel_warp_connector/model.go | 51 ++++ .../resource.go | 259 ++++++++++++++++++ .../resource_schema_test.go | 19 ++ .../schema.go | 156 +++++++++++ 19 files changed, 1402 insertions(+), 3 deletions(-) create mode 100644 examples/data-sources/cloudflare_zero_trust_tunnel_warp_connector/data-source.tf create mode 100644 examples/data-sources/cloudflare_zero_trust_tunnel_warp_connectors/data-source.tf create mode 100644 examples/resources/cloudflare_zero_trust_tunnel_warp_connector/import.sh create mode 100644 examples/resources/cloudflare_zero_trust_tunnel_warp_connector/resource.tf create mode 100644 internal/services/zero_trust_tunnel_warp_connector/data_source.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/data_source_model.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/data_source_schema.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/data_source_schema_test.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/list_data_source.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/list_data_source_model.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/list_data_source_schema.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/list_data_source_schema_test.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/migrations.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/model.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/resource.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/resource_schema_test.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/schema.go diff --git a/.stats.yml b/.stats.yml index bd5d46e2f1..6423dc9abd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b45da271fede9a1b0d86e7214a1929d4c58185a7ba4a13b81dbc810ae28bc946.yml -openapi_spec_hash: 12c96c5a3be55ca50041304e4fa879cb -config_hash: 9e096c169b43682069730a4291c62d4a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-92ecd398f18b65eff60080117a9e72a330dc59e34f31f63f7e860130be19dd37.yml +openapi_spec_hash: 79c5a29b646a18da296d1a15fa1c35e6 +config_hash: 3638b66b63ea825ab6a770e729104836 diff --git a/examples/data-sources/cloudflare_zero_trust_tunnel_warp_connector/data-source.tf b/examples/data-sources/cloudflare_zero_trust_tunnel_warp_connector/data-source.tf new file mode 100644 index 0000000000..2a15409e6e --- /dev/null +++ b/examples/data-sources/cloudflare_zero_trust_tunnel_warp_connector/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_zero_trust_tunnel_warp_connector" "example_zero_trust_tunnel_warp_connector" { + account_id = "699d98642c564d2e855e9661899b7252" + tunnel_id = "f70ff985-a4ef-4643-bbbc-4a0ed4fc8415" +} diff --git a/examples/data-sources/cloudflare_zero_trust_tunnel_warp_connectors/data-source.tf b/examples/data-sources/cloudflare_zero_trust_tunnel_warp_connectors/data-source.tf new file mode 100644 index 0000000000..eaf356bffa --- /dev/null +++ b/examples/data-sources/cloudflare_zero_trust_tunnel_warp_connectors/data-source.tf @@ -0,0 +1,12 @@ +data "cloudflare_zero_trust_tunnel_warp_connectors" "example_zero_trust_tunnel_warp_connectors" { + account_id = "699d98642c564d2e855e9661899b7252" + exclude_prefix = "vpc1-" + existed_at = "2019-10-12T07%3A20%3A50.52Z" + include_prefix = "vpc1-" + is_deleted = true + name = "blog" + status = "healthy" + uuid = "f70ff985-a4ef-4643-bbbc-4a0ed4fc8415" + was_active_at = "2009-11-10T23:00:00Z" + was_inactive_at = "2009-11-10T23:00:00Z" +} diff --git a/examples/resources/cloudflare_zero_trust_tunnel_warp_connector/import.sh b/examples/resources/cloudflare_zero_trust_tunnel_warp_connector/import.sh new file mode 100644 index 0000000000..cf3b69b07d --- /dev/null +++ b/examples/resources/cloudflare_zero_trust_tunnel_warp_connector/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_zero_trust_tunnel_warp_connector.example '/' diff --git a/examples/resources/cloudflare_zero_trust_tunnel_warp_connector/resource.tf b/examples/resources/cloudflare_zero_trust_tunnel_warp_connector/resource.tf new file mode 100644 index 0000000000..da85cff42c --- /dev/null +++ b/examples/resources/cloudflare_zero_trust_tunnel_warp_connector/resource.tf @@ -0,0 +1,4 @@ +resource "cloudflare_zero_trust_tunnel_warp_connector" "example_zero_trust_tunnel_warp_connector" { + account_id = "699d98642c564d2e855e9661899b7252" + name = "blog" +} diff --git a/internal/provider.go b/internal/provider.go index 97267c1a87..08d1dd396d 100644 --- a/internal/provider.go +++ b/internal/provider.go @@ -207,6 +207,7 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared_route" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared_token" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared_virtual_network" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_warp_connector" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_warp_connector_token" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zone" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zone_cache_reserve" @@ -535,6 +536,7 @@ func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Re zero_trust_access_policy.NewResource, zero_trust_tunnel_cloudflared.NewResource, zero_trust_tunnel_cloudflared_config.NewResource, + zero_trust_tunnel_warp_connector.NewResource, zero_trust_dlp_dataset.NewResource, zero_trust_dlp_custom_profile.NewResource, zero_trust_dlp_predefined_profile.NewResource, @@ -824,6 +826,8 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc zero_trust_tunnel_cloudflared.NewZeroTrustTunnelCloudflaredsDataSource, zero_trust_tunnel_cloudflared_config.NewZeroTrustTunnelCloudflaredConfigDataSource, zero_trust_tunnel_cloudflared_token.NewZeroTrustTunnelCloudflaredTokenDataSource, + zero_trust_tunnel_warp_connector.NewZeroTrustTunnelWARPConnectorDataSource, + zero_trust_tunnel_warp_connector.NewZeroTrustTunnelWARPConnectorsDataSource, zero_trust_tunnel_warp_connector_token.NewZeroTrustTunnelWARPConnectorTokenDataSource, zero_trust_dlp_dataset.NewZeroTrustDLPDatasetDataSource, zero_trust_dlp_dataset.NewZeroTrustDLPDatasetsDataSource, diff --git a/internal/services/zero_trust_tunnel_warp_connector/data_source.go b/internal/services/zero_trust_tunnel_warp_connector/data_source.go new file mode 100644 index 0000000000..99bb2cc9a2 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/data_source.go @@ -0,0 +1,118 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type ZeroTrustTunnelWARPConnectorDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*ZeroTrustTunnelWARPConnectorDataSource)(nil) + +func NewZeroTrustTunnelWARPConnectorDataSource() datasource.DataSource { + return &ZeroTrustTunnelWARPConnectorDataSource{} +} + +func (d *ZeroTrustTunnelWARPConnectorDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_zero_trust_tunnel_warp_connector" +} + +func (d *ZeroTrustTunnelWARPConnectorDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *ZeroTrustTunnelWARPConnectorDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *ZeroTrustTunnelWARPConnectorDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + if data.Filter != nil { + params, diags := data.toListParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + env := ZeroTrustTunnelWARPConnectorsResultListDataSourceEnvelope{} + page, err := d.client.ZeroTrust.Tunnels.WARPConnector.List(ctx, params) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + bytes := []byte(page.JSON.RawJSON()) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to unmarshal http request", err.Error()) + return + } + + if count := len(env.Result.Elements()); count != 1 { + resp.Diagnostics.AddError("failed to find exactly one result", fmt.Sprint(count)+" found") + return + } + ts, diags := env.Result.AsStructSliceT(ctx) + resp.Diagnostics.Append(diags...) + data.TunnelID = ts[0].ID + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := ZeroTrustTunnelWARPConnectorResultDataSourceEnvelope{*data} + _, err := d.client.ZeroTrust.Tunnels.WARPConnector.Get( + ctx, + data.TunnelID.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/data_source_model.go b/internal/services/zero_trust_tunnel_warp_connector/data_source_model.go new file mode 100644 index 0000000000..e4e8aac6bb --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/data_source_model.go @@ -0,0 +1,109 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ZeroTrustTunnelWARPConnectorResultDataSourceEnvelope struct { + Result ZeroTrustTunnelWARPConnectorDataSourceModel `json:"result,computed"` +} + +type ZeroTrustTunnelWARPConnectorDataSourceModel struct { + ID types.String `tfsdk:"id" path:"tunnel_id,computed"` + TunnelID types.String `tfsdk:"tunnel_id" path:"tunnel_id,optional"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + AccountTag types.String `tfsdk:"account_tag" json:"account_tag,computed"` + ConnsActiveAt timetypes.RFC3339 `tfsdk:"conns_active_at" json:"conns_active_at,computed" format:"date-time"` + ConnsInactiveAt timetypes.RFC3339 `tfsdk:"conns_inactive_at" json:"conns_inactive_at,computed" format:"date-time"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` + DeletedAt timetypes.RFC3339 `tfsdk:"deleted_at" json:"deleted_at,computed" format:"date-time"` + Name types.String `tfsdk:"name" json:"name,computed"` + RemoteConfig types.Bool `tfsdk:"remote_config" json:"remote_config,computed"` + Status types.String `tfsdk:"status" json:"status,computed"` + TunType types.String `tfsdk:"tun_type" json:"tun_type,computed"` + Connections customfield.NestedObjectList[ZeroTrustTunnelWARPConnectorConnectionsDataSourceModel] `tfsdk:"connections" json:"connections,computed"` + Metadata jsontypes.Normalized `tfsdk:"metadata" json:"metadata,computed"` + Filter *ZeroTrustTunnelWARPConnectorFindOneByDataSourceModel `tfsdk:"filter"` +} + +func (m *ZeroTrustTunnelWARPConnectorDataSourceModel) toReadParams(_ context.Context) (params zero_trust.TunnelWARPConnectorGetParams, diags diag.Diagnostics) { + params = zero_trust.TunnelWARPConnectorGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + +func (m *ZeroTrustTunnelWARPConnectorDataSourceModel) toListParams(_ context.Context) (params zero_trust.TunnelWARPConnectorListParams, diags diag.Diagnostics) { + mFilterWasActiveAt, errs := m.Filter.WasActiveAt.ValueRFC3339Time() + diags.Append(errs...) + mFilterWasInactiveAt, errs := m.Filter.WasInactiveAt.ValueRFC3339Time() + diags.Append(errs...) + + params = zero_trust.TunnelWARPConnectorListParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + if !m.Filter.ExcludePrefix.IsNull() { + params.ExcludePrefix = cloudflare.F(m.Filter.ExcludePrefix.ValueString()) + } + if !m.Filter.ExistedAt.IsNull() { + params.ExistedAt = cloudflare.F(m.Filter.ExistedAt.ValueString()) + } + if !m.Filter.IncludePrefix.IsNull() { + params.IncludePrefix = cloudflare.F(m.Filter.IncludePrefix.ValueString()) + } + if !m.Filter.IsDeleted.IsNull() { + params.IsDeleted = cloudflare.F(m.Filter.IsDeleted.ValueBool()) + } + if !m.Filter.Name.IsNull() { + params.Name = cloudflare.F(m.Filter.Name.ValueString()) + } + if !m.Filter.Status.IsNull() { + params.Status = cloudflare.F(zero_trust.TunnelWARPConnectorListParamsStatus(m.Filter.Status.ValueString())) + } + if !m.Filter.UUID.IsNull() { + params.UUID = cloudflare.F(m.Filter.UUID.ValueString()) + } + if !m.Filter.WasActiveAt.IsNull() { + params.WasActiveAt = cloudflare.F(mFilterWasActiveAt) + } + if !m.Filter.WasInactiveAt.IsNull() { + params.WasInactiveAt = cloudflare.F(mFilterWasInactiveAt) + } + + return +} + +type ZeroTrustTunnelWARPConnectorConnectionsDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + ClientID types.String `tfsdk:"client_id" json:"client_id,computed"` + ClientVersion types.String `tfsdk:"client_version" json:"client_version,computed"` + ColoName types.String `tfsdk:"colo_name" json:"colo_name,computed"` + IsPendingReconnect types.Bool `tfsdk:"is_pending_reconnect" json:"is_pending_reconnect,computed"` + OpenedAt timetypes.RFC3339 `tfsdk:"opened_at" json:"opened_at,computed" format:"date-time"` + OriginIP types.String `tfsdk:"origin_ip" json:"origin_ip,computed"` + UUID types.String `tfsdk:"uuid" json:"uuid,computed"` +} + +type ZeroTrustTunnelWARPConnectorFindOneByDataSourceModel struct { + ExcludePrefix types.String `tfsdk:"exclude_prefix" query:"exclude_prefix,optional"` + ExistedAt types.String `tfsdk:"existed_at" query:"existed_at,optional"` + IncludePrefix types.String `tfsdk:"include_prefix" query:"include_prefix,optional"` + IsDeleted types.Bool `tfsdk:"is_deleted" query:"is_deleted,optional"` + Name types.String `tfsdk:"name" query:"name,optional"` + Status types.String `tfsdk:"status" query:"status,optional"` + UUID types.String `tfsdk:"uuid" query:"uuid,optional"` + WasActiveAt timetypes.RFC3339 `tfsdk:"was_active_at" query:"was_active_at,optional" format:"date-time"` + WasInactiveAt timetypes.RFC3339 `tfsdk:"was_inactive_at" query:"was_inactive_at,optional" format:"date-time"` +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/data_source_schema.go b/internal/services/zero_trust_tunnel_warp_connector/data_source_schema.go new file mode 100644 index 0000000000..8aac58ef37 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/data_source_schema.go @@ -0,0 +1,202 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ datasource.DataSourceWithConfigValidators = (*ZeroTrustTunnelWARPConnectorDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "UUID of the tunnel.", + Computed: true, + }, + "tunnel_id": schema.StringAttribute{ + Description: "UUID of the tunnel.", + Optional: true, + }, + "account_id": schema.StringAttribute{ + Description: "Cloudflare account ID", + Required: true, + }, + "account_tag": schema.StringAttribute{ + Description: "Cloudflare account ID", + Computed: true, + }, + "conns_active_at": schema.StringAttribute{ + Description: "Timestamp of when the tunnel established at least one connection to Cloudflare's edge. If `null`, the tunnel is inactive.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "conns_inactive_at": schema.StringAttribute{ + Description: "Timestamp of when the tunnel became inactive (no connections to Cloudflare's edge). If `null`, the tunnel is active.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "created_at": schema.StringAttribute{ + Description: "Timestamp of when the resource was created.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "deleted_at": schema.StringAttribute{ + Description: "Timestamp of when the resource was deleted. If `null`, the resource has not been deleted.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "name": schema.StringAttribute{ + Description: "A user-friendly name for a tunnel.", + Computed: true, + }, + "remote_config": schema.BoolAttribute{ + Description: "If `true`, the tunnel can be configured remotely from the Zero Trust dashboard. If `false`, the tunnel must be configured locally on the origin machine.", + Computed: true, + }, + "status": schema.StringAttribute{ + Description: "The status of the tunnel. Valid values are `inactive` (tunnel has never been run), `degraded` (tunnel is active and able to serve traffic but in an unhealthy state), `healthy` (tunnel is active and able to serve traffic), or `down` (tunnel can not serve traffic as it has no connections to the Cloudflare Edge).\nAvailable values: \"inactive\", \"degraded\", \"healthy\", \"down\".", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "inactive", + "degraded", + "healthy", + "down", + ), + }, + }, + "tun_type": schema.StringAttribute{ + Description: "The type of tunnel.\nAvailable values: \"cfd_tunnel\", \"warp_connector\", \"warp\", \"magic\", \"ip_sec\", \"gre\", \"cni\".", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "cfd_tunnel", + "warp_connector", + "warp", + "magic", + "ip_sec", + "gre", + "cni", + ), + }, + }, + "connections": schema.ListNestedAttribute{ + Description: "The Cloudflare Tunnel connections between your origin and Cloudflare's edge.", + Computed: true, + DeprecationMessage: "This field will start returning an empty array. To fetch the connections of a given tunnel, please use the dedicated endpoint `/accounts/{account_id}/{tunnel_type}/{tunnel_id}/connections`", + CustomType: customfield.NewNestedObjectListType[ZeroTrustTunnelWARPConnectorConnectionsDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connection.", + Computed: true, + }, + "client_id": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connector.", + Computed: true, + }, + "client_version": schema.StringAttribute{ + Description: "The cloudflared version used to establish this connection.", + Computed: true, + }, + "colo_name": schema.StringAttribute{ + Description: "The Cloudflare data center used for this connection.", + Computed: true, + }, + "is_pending_reconnect": schema.BoolAttribute{ + Description: "Cloudflare continues to track connections for several minutes after they disconnect. This is an optimization to improve latency and reliability of reconnecting. If `true`, the connection has disconnected but is still being tracked. If `false`, the connection is actively serving traffic.", + Computed: true, + }, + "opened_at": schema.StringAttribute{ + Description: "Timestamp of when the connection was established.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "origin_ip": schema.StringAttribute{ + Description: "The public IP address of the host running cloudflared.", + Computed: true, + }, + "uuid": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connection.", + Computed: true, + }, + }, + }, + }, + "metadata": schema.StringAttribute{ + Description: "Metadata associated with the tunnel.", + Computed: true, + CustomType: jsontypes.NormalizedType{}, + }, + "filter": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "exclude_prefix": schema.StringAttribute{ + Optional: true, + }, + "existed_at": schema.StringAttribute{ + Description: "If provided, include only resources that were created (and not deleted) before this time. URL encoded.", + Optional: true, + }, + "include_prefix": schema.StringAttribute{ + Optional: true, + }, + "is_deleted": schema.BoolAttribute{ + Description: "If `true`, only include deleted tunnels. If `false`, exclude deleted tunnels. If empty, all tunnels will be included.", + Optional: true, + }, + "name": schema.StringAttribute{ + Description: "A user-friendly name for the tunnel.", + Optional: true, + }, + "status": schema.StringAttribute{ + Description: "The status of the tunnel. Valid values are `inactive` (tunnel has never been run), `degraded` (tunnel is active and able to serve traffic but in an unhealthy state), `healthy` (tunnel is active and able to serve traffic), or `down` (tunnel can not serve traffic as it has no connections to the Cloudflare Edge).\nAvailable values: \"inactive\", \"degraded\", \"healthy\", \"down\".", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "inactive", + "degraded", + "healthy", + "down", + ), + }, + }, + "uuid": schema.StringAttribute{ + Description: "UUID of the tunnel.", + Optional: true, + }, + "was_active_at": schema.StringAttribute{ + Optional: true, + CustomType: timetypes.RFC3339Type{}, + }, + "was_inactive_at": schema.StringAttribute{ + Optional: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + }, + }, + } +} + +func (d *ZeroTrustTunnelWARPConnectorDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *ZeroTrustTunnelWARPConnectorDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf(path.MatchRoot("tunnel_id"), path.MatchRoot("filter")), + } +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/data_source_schema_test.go b/internal/services/zero_trust_tunnel_warp_connector/data_source_schema_test.go new file mode 100644 index 0000000000..58a796c99d --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_warp_connector" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestZeroTrustTunnelWARPConnectorDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*zero_trust_tunnel_warp_connector.ZeroTrustTunnelWARPConnectorDataSourceModel)(nil) + schema := zero_trust_tunnel_warp_connector.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/list_data_source.go b/internal/services/zero_trust_tunnel_warp_connector/list_data_source.go new file mode 100644 index 0000000000..86d1a342c5 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/list_data_source.go @@ -0,0 +1,100 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + "fmt" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type ZeroTrustTunnelWARPConnectorsDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*ZeroTrustTunnelWARPConnectorsDataSource)(nil) + +func NewZeroTrustTunnelWARPConnectorsDataSource() datasource.DataSource { + return &ZeroTrustTunnelWARPConnectorsDataSource{} +} + +func (d *ZeroTrustTunnelWARPConnectorsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_zero_trust_tunnel_warp_connectors" +} + +func (d *ZeroTrustTunnelWARPConnectorsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *ZeroTrustTunnelWARPConnectorsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *ZeroTrustTunnelWARPConnectorsDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toListParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + env := ZeroTrustTunnelWARPConnectorsResultListDataSourceEnvelope{} + maxItems := int(data.MaxItems.ValueInt64()) + acc := []attr.Value{} + if maxItems <= 0 { + maxItems = 1000 + } + page, err := d.client.ZeroTrust.Tunnels.WARPConnector.List(ctx, params) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + for page != nil && len(page.Result) > 0 { + bytes := []byte(page.JSON.RawJSON()) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to unmarshal http request", err.Error()) + return + } + acc = append(acc, env.Result.Elements()...) + if len(acc) >= maxItems { + break + } + page, err = page.GetNextPage() + if err != nil { + resp.Diagnostics.AddError("failed to fetch next page", err.Error()) + return + } + } + + acc = acc[:min(len(acc), maxItems)] + result, diags := customfield.NewObjectListFromAttributes[ZeroTrustTunnelWARPConnectorsResultDataSourceModel](ctx, acc) + resp.Diagnostics.Append(diags...) + data.Result = result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/list_data_source_model.go b/internal/services/zero_trust_tunnel_warp_connector/list_data_source_model.go new file mode 100644 index 0000000000..2b2aa01102 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/list_data_source_model.go @@ -0,0 +1,101 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ZeroTrustTunnelWARPConnectorsResultListDataSourceEnvelope struct { + Result customfield.NestedObjectList[ZeroTrustTunnelWARPConnectorsResultDataSourceModel] `json:"result,computed"` +} + +type ZeroTrustTunnelWARPConnectorsDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + ExcludePrefix types.String `tfsdk:"exclude_prefix" query:"exclude_prefix,optional"` + ExistedAt types.String `tfsdk:"existed_at" query:"existed_at,optional"` + IncludePrefix types.String `tfsdk:"include_prefix" query:"include_prefix,optional"` + IsDeleted types.Bool `tfsdk:"is_deleted" query:"is_deleted,optional"` + Name types.String `tfsdk:"name" query:"name,optional"` + Status types.String `tfsdk:"status" query:"status,optional"` + UUID types.String `tfsdk:"uuid" query:"uuid,optional"` + WasActiveAt timetypes.RFC3339 `tfsdk:"was_active_at" query:"was_active_at,optional" format:"date-time"` + WasInactiveAt timetypes.RFC3339 `tfsdk:"was_inactive_at" query:"was_inactive_at,optional" format:"date-time"` + MaxItems types.Int64 `tfsdk:"max_items"` + Result customfield.NestedObjectList[ZeroTrustTunnelWARPConnectorsResultDataSourceModel] `tfsdk:"result"` +} + +func (m *ZeroTrustTunnelWARPConnectorsDataSourceModel) toListParams(_ context.Context) (params zero_trust.TunnelWARPConnectorListParams, diags diag.Diagnostics) { + mWasActiveAt, errs := m.WasActiveAt.ValueRFC3339Time() + diags.Append(errs...) + mWasInactiveAt, errs := m.WasInactiveAt.ValueRFC3339Time() + diags.Append(errs...) + + params = zero_trust.TunnelWARPConnectorListParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + if !m.ExcludePrefix.IsNull() { + params.ExcludePrefix = cloudflare.F(m.ExcludePrefix.ValueString()) + } + if !m.ExistedAt.IsNull() { + params.ExistedAt = cloudflare.F(m.ExistedAt.ValueString()) + } + if !m.IncludePrefix.IsNull() { + params.IncludePrefix = cloudflare.F(m.IncludePrefix.ValueString()) + } + if !m.IsDeleted.IsNull() { + params.IsDeleted = cloudflare.F(m.IsDeleted.ValueBool()) + } + if !m.Name.IsNull() { + params.Name = cloudflare.F(m.Name.ValueString()) + } + if !m.Status.IsNull() { + params.Status = cloudflare.F(zero_trust.TunnelWARPConnectorListParamsStatus(m.Status.ValueString())) + } + if !m.UUID.IsNull() { + params.UUID = cloudflare.F(m.UUID.ValueString()) + } + if !m.WasActiveAt.IsNull() { + params.WasActiveAt = cloudflare.F(mWasActiveAt) + } + if !m.WasInactiveAt.IsNull() { + params.WasInactiveAt = cloudflare.F(mWasInactiveAt) + } + + return +} + +type ZeroTrustTunnelWARPConnectorsResultDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + AccountTag types.String `tfsdk:"account_tag" json:"account_tag,computed"` + Connections customfield.NestedObjectList[ZeroTrustTunnelWARPConnectorsConnectionsDataSourceModel] `tfsdk:"connections" json:"connections,computed"` + ConnsActiveAt timetypes.RFC3339 `tfsdk:"conns_active_at" json:"conns_active_at,computed" format:"date-time"` + ConnsInactiveAt timetypes.RFC3339 `tfsdk:"conns_inactive_at" json:"conns_inactive_at,computed" format:"date-time"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` + DeletedAt timetypes.RFC3339 `tfsdk:"deleted_at" json:"deleted_at,computed" format:"date-time"` + Metadata jsontypes.Normalized `tfsdk:"metadata" json:"metadata,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` + RemoteConfig types.Bool `tfsdk:"remote_config" json:"remote_config,computed"` + Status types.String `tfsdk:"status" json:"status,computed"` + TunType types.String `tfsdk:"tun_type" json:"tun_type,computed"` +} + +type ZeroTrustTunnelWARPConnectorsConnectionsDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + ClientID types.String `tfsdk:"client_id" json:"client_id,computed"` + ClientVersion types.String `tfsdk:"client_version" json:"client_version,computed"` + ColoName types.String `tfsdk:"colo_name" json:"colo_name,computed"` + IsPendingReconnect types.Bool `tfsdk:"is_pending_reconnect" json:"is_pending_reconnect,computed"` + OpenedAt timetypes.RFC3339 `tfsdk:"opened_at" json:"opened_at,computed" format:"date-time"` + OriginIP types.String `tfsdk:"origin_ip" json:"origin_ip,computed"` + UUID types.String `tfsdk:"uuid" json:"uuid,computed"` +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/list_data_source_schema.go b/internal/services/zero_trust_tunnel_warp_connector/list_data_source_schema.go new file mode 100644 index 0000000000..10a101bb0b --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/list_data_source_schema.go @@ -0,0 +1,206 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ datasource.DataSourceWithConfigValidators = (*ZeroTrustTunnelWARPConnectorsDataSource)(nil) + +func ListDataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Cloudflare account ID", + Required: true, + }, + "exclude_prefix": schema.StringAttribute{ + Optional: true, + }, + "existed_at": schema.StringAttribute{ + Description: "If provided, include only resources that were created (and not deleted) before this time. URL encoded.", + Optional: true, + }, + "include_prefix": schema.StringAttribute{ + Optional: true, + }, + "is_deleted": schema.BoolAttribute{ + Description: "If `true`, only include deleted tunnels. If `false`, exclude deleted tunnels. If empty, all tunnels will be included.", + Optional: true, + }, + "name": schema.StringAttribute{ + Description: "A user-friendly name for the tunnel.", + Optional: true, + }, + "status": schema.StringAttribute{ + Description: "The status of the tunnel. Valid values are `inactive` (tunnel has never been run), `degraded` (tunnel is active and able to serve traffic but in an unhealthy state), `healthy` (tunnel is active and able to serve traffic), or `down` (tunnel can not serve traffic as it has no connections to the Cloudflare Edge).\nAvailable values: \"inactive\", \"degraded\", \"healthy\", \"down\".", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "inactive", + "degraded", + "healthy", + "down", + ), + }, + }, + "uuid": schema.StringAttribute{ + Description: "UUID of the tunnel.", + Optional: true, + }, + "was_active_at": schema.StringAttribute{ + Optional: true, + CustomType: timetypes.RFC3339Type{}, + }, + "was_inactive_at": schema.StringAttribute{ + Optional: true, + CustomType: timetypes.RFC3339Type{}, + }, + "max_items": schema.Int64Attribute{ + Description: "Max items to fetch, default: 1000", + Optional: true, + Validators: []validator.Int64{ + int64validator.AtLeast(0), + }, + }, + "result": schema.ListNestedAttribute{ + Description: "The items returned by the data source", + Computed: true, + CustomType: customfield.NewNestedObjectListType[ZeroTrustTunnelWARPConnectorsResultDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "UUID of the tunnel.", + Computed: true, + }, + "account_tag": schema.StringAttribute{ + Description: "Cloudflare account ID", + Computed: true, + }, + "connections": schema.ListNestedAttribute{ + Description: "The Cloudflare Tunnel connections between your origin and Cloudflare's edge.", + Computed: true, + DeprecationMessage: "This field will start returning an empty array. To fetch the connections of a given tunnel, please use the dedicated endpoint `/accounts/{account_id}/{tunnel_type}/{tunnel_id}/connections`", + CustomType: customfield.NewNestedObjectListType[ZeroTrustTunnelWARPConnectorsConnectionsDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connection.", + Computed: true, + }, + "client_id": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connector.", + Computed: true, + }, + "client_version": schema.StringAttribute{ + Description: "The cloudflared version used to establish this connection.", + Computed: true, + }, + "colo_name": schema.StringAttribute{ + Description: "The Cloudflare data center used for this connection.", + Computed: true, + }, + "is_pending_reconnect": schema.BoolAttribute{ + Description: "Cloudflare continues to track connections for several minutes after they disconnect. This is an optimization to improve latency and reliability of reconnecting. If `true`, the connection has disconnected but is still being tracked. If `false`, the connection is actively serving traffic.", + Computed: true, + }, + "opened_at": schema.StringAttribute{ + Description: "Timestamp of when the connection was established.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "origin_ip": schema.StringAttribute{ + Description: "The public IP address of the host running cloudflared.", + Computed: true, + }, + "uuid": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connection.", + Computed: true, + }, + }, + }, + }, + "conns_active_at": schema.StringAttribute{ + Description: "Timestamp of when the tunnel established at least one connection to Cloudflare's edge. If `null`, the tunnel is inactive.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "conns_inactive_at": schema.StringAttribute{ + Description: "Timestamp of when the tunnel became inactive (no connections to Cloudflare's edge). If `null`, the tunnel is active.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "created_at": schema.StringAttribute{ + Description: "Timestamp of when the resource was created.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "deleted_at": schema.StringAttribute{ + Description: "Timestamp of when the resource was deleted. If `null`, the resource has not been deleted.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "metadata": schema.StringAttribute{ + Description: "Metadata associated with the tunnel.", + Computed: true, + CustomType: jsontypes.NormalizedType{}, + }, + "name": schema.StringAttribute{ + Description: "A user-friendly name for a tunnel.", + Computed: true, + }, + "remote_config": schema.BoolAttribute{ + Description: "If `true`, the tunnel can be configured remotely from the Zero Trust dashboard. If `false`, the tunnel must be configured locally on the origin machine.", + Computed: true, + }, + "status": schema.StringAttribute{ + Description: "The status of the tunnel. Valid values are `inactive` (tunnel has never been run), `degraded` (tunnel is active and able to serve traffic but in an unhealthy state), `healthy` (tunnel is active and able to serve traffic), or `down` (tunnel can not serve traffic as it has no connections to the Cloudflare Edge).\nAvailable values: \"inactive\", \"degraded\", \"healthy\", \"down\".", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "inactive", + "degraded", + "healthy", + "down", + ), + }, + }, + "tun_type": schema.StringAttribute{ + Description: "The type of tunnel.\nAvailable values: \"cfd_tunnel\", \"warp_connector\", \"warp\", \"magic\", \"ip_sec\", \"gre\", \"cni\".", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "cfd_tunnel", + "warp_connector", + "warp", + "magic", + "ip_sec", + "gre", + "cni", + ), + }, + }, + }, + }, + }, + }, + } +} + +func (d *ZeroTrustTunnelWARPConnectorsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = ListDataSourceSchema(ctx) +} + +func (d *ZeroTrustTunnelWARPConnectorsDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/list_data_source_schema_test.go b/internal/services/zero_trust_tunnel_warp_connector/list_data_source_schema_test.go new file mode 100644 index 0000000000..bdc0521f38 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/list_data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_warp_connector" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestZeroTrustTunnelWARPConnectorsDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*zero_trust_tunnel_warp_connector.ZeroTrustTunnelWARPConnectorsDataSourceModel)(nil) + schema := zero_trust_tunnel_warp_connector.ListDataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/migrations.go b/internal/services/zero_trust_tunnel_warp_connector/migrations.go new file mode 100644 index 0000000000..6d18b3fa46 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*ZeroTrustTunnelWARPConnectorResource)(nil) + +func (r *ZeroTrustTunnelWARPConnectorResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/model.go b/internal/services/zero_trust_tunnel_warp_connector/model.go new file mode 100644 index 0000000000..0931cec11e --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/model.go @@ -0,0 +1,51 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ZeroTrustTunnelWARPConnectorResultEnvelope struct { + Result ZeroTrustTunnelWARPConnectorModel `json:"result"` +} + +type ZeroTrustTunnelWARPConnectorModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Name types.String `tfsdk:"name" json:"name,required"` + TunnelSecret types.String `tfsdk:"tunnel_secret" json:"tunnel_secret,optional,no_refresh"` + AccountTag types.String `tfsdk:"account_tag" json:"account_tag,computed"` + ConnsActiveAt timetypes.RFC3339 `tfsdk:"conns_active_at" json:"conns_active_at,computed" format:"date-time"` + ConnsInactiveAt timetypes.RFC3339 `tfsdk:"conns_inactive_at" json:"conns_inactive_at,computed" format:"date-time"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` + DeletedAt timetypes.RFC3339 `tfsdk:"deleted_at" json:"deleted_at,computed" format:"date-time"` + RemoteConfig types.Bool `tfsdk:"remote_config" json:"remote_config,computed"` + Status types.String `tfsdk:"status" json:"status,computed"` + TunType types.String `tfsdk:"tun_type" json:"tun_type,computed"` + Connections customfield.NestedObjectList[ZeroTrustTunnelWARPConnectorConnectionsModel] `tfsdk:"connections" json:"connections,computed"` + Metadata jsontypes.Normalized `tfsdk:"metadata" json:"metadata,computed"` +} + +func (m ZeroTrustTunnelWARPConnectorModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m ZeroTrustTunnelWARPConnectorModel) MarshalJSONForUpdate(state ZeroTrustTunnelWARPConnectorModel) (data []byte, err error) { + return apijson.MarshalForPatch(m, state) +} + +type ZeroTrustTunnelWARPConnectorConnectionsModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + ClientID types.String `tfsdk:"client_id" json:"client_id,computed"` + ClientVersion types.String `tfsdk:"client_version" json:"client_version,computed"` + ColoName types.String `tfsdk:"colo_name" json:"colo_name,computed"` + IsPendingReconnect types.Bool `tfsdk:"is_pending_reconnect" json:"is_pending_reconnect,computed"` + OpenedAt timetypes.RFC3339 `tfsdk:"opened_at" json:"opened_at,computed" format:"date-time"` + OriginIP types.String `tfsdk:"origin_ip" json:"origin_ip,computed"` + UUID types.String `tfsdk:"uuid" json:"uuid,computed"` +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/resource.go b/internal/services/zero_trust_tunnel_warp_connector/resource.go new file mode 100644 index 0000000000..a692f77c9e --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/resource.go @@ -0,0 +1,259 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*ZeroTrustTunnelWARPConnectorResource)(nil) +var _ resource.ResourceWithModifyPlan = (*ZeroTrustTunnelWARPConnectorResource)(nil) +var _ resource.ResourceWithImportState = (*ZeroTrustTunnelWARPConnectorResource)(nil) + +func NewResource() resource.Resource { + return &ZeroTrustTunnelWARPConnectorResource{} +} + +// ZeroTrustTunnelWARPConnectorResource defines the resource implementation. +type ZeroTrustTunnelWARPConnectorResource struct { + client *cloudflare.Client +} + +func (r *ZeroTrustTunnelWARPConnectorResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_zero_trust_tunnel_warp_connector" +} + +func (r *ZeroTrustTunnelWARPConnectorResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *ZeroTrustTunnelWARPConnectorResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *ZeroTrustTunnelWARPConnectorModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := ZeroTrustTunnelWARPConnectorResultEnvelope{*data} + _, err = r.client.ZeroTrust.Tunnels.WARPConnector.New( + ctx, + zero_trust.TunnelWARPConnectorNewParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ZeroTrustTunnelWARPConnectorResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *ZeroTrustTunnelWARPConnectorModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *ZeroTrustTunnelWARPConnectorModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := ZeroTrustTunnelWARPConnectorResultEnvelope{*data} + _, err = r.client.ZeroTrust.Tunnels.WARPConnector.Edit( + ctx, + data.ID.ValueString(), + zero_trust.TunnelWARPConnectorEditParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ZeroTrustTunnelWARPConnectorResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *ZeroTrustTunnelWARPConnectorModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := ZeroTrustTunnelWARPConnectorResultEnvelope{*data} + _, err := r.client.ZeroTrust.Tunnels.WARPConnector.Get( + ctx, + data.ID.ValueString(), + zero_trust.TunnelWARPConnectorGetParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ZeroTrustTunnelWARPConnectorResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *ZeroTrustTunnelWARPConnectorModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.ZeroTrust.Tunnels.WARPConnector.Delete( + ctx, + data.ID.ValueString(), + zero_trust.TunnelWARPConnectorDeleteParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ZeroTrustTunnelWARPConnectorResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *ZeroTrustTunnelWARPConnectorModel = new(ZeroTrustTunnelWARPConnectorModel) + + path_account_id := "" + path_tunnel_id := "" + diags := importpath.ParseImportID( + req.ID, + "/", + &path_account_id, + &path_tunnel_id, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.AccountID = types.StringValue(path_account_id) + data.ID = types.StringValue(path_tunnel_id) + + res := new(http.Response) + env := ZeroTrustTunnelWARPConnectorResultEnvelope{*data} + _, err := r.client.ZeroTrust.Tunnels.WARPConnector.Get( + ctx, + path_tunnel_id, + zero_trust.TunnelWARPConnectorGetParams{ + AccountID: cloudflare.F(path_account_id), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ZeroTrustTunnelWARPConnectorResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { + +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/resource_schema_test.go b/internal/services/zero_trust_tunnel_warp_connector/resource_schema_test.go new file mode 100644 index 0000000000..789c0fe786 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_warp_connector" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestZeroTrustTunnelWARPConnectorModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*zero_trust_tunnel_warp_connector.ZeroTrustTunnelWARPConnectorModel)(nil) + schema := zero_trust_tunnel_warp_connector.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/schema.go b/internal/services/zero_trust_tunnel_warp_connector/schema.go new file mode 100644 index 0000000000..e95ed4d947 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/schema.go @@ -0,0 +1,156 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_warp_connector + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ resource.ResourceWithConfigValidators = (*ZeroTrustTunnelWARPConnectorResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "UUID of the tunnel.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + "account_id": schema.StringAttribute{ + Description: "Cloudflare account ID", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "name": schema.StringAttribute{ + Description: "A user-friendly name for a tunnel.", + Required: true, + }, + "tunnel_secret": schema.StringAttribute{ + Description: "Sets the password required to run a locally-managed tunnel. Must be at least 32 bytes and encoded as a base64 string.", + Optional: true, + Sensitive: true, + }, + "account_tag": schema.StringAttribute{ + Description: "Cloudflare account ID", + Computed: true, + }, + "conns_active_at": schema.StringAttribute{ + Description: "Timestamp of when the tunnel established at least one connection to Cloudflare's edge. If `null`, the tunnel is inactive.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "conns_inactive_at": schema.StringAttribute{ + Description: "Timestamp of when the tunnel became inactive (no connections to Cloudflare's edge). If `null`, the tunnel is active.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "created_at": schema.StringAttribute{ + Description: "Timestamp of when the resource was created.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "deleted_at": schema.StringAttribute{ + Description: "Timestamp of when the resource was deleted. If `null`, the resource has not been deleted.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "remote_config": schema.BoolAttribute{ + Description: "If `true`, the tunnel can be configured remotely from the Zero Trust dashboard. If `false`, the tunnel must be configured locally on the origin machine.", + Computed: true, + }, + "status": schema.StringAttribute{ + Description: "The status of the tunnel. Valid values are `inactive` (tunnel has never been run), `degraded` (tunnel is active and able to serve traffic but in an unhealthy state), `healthy` (tunnel is active and able to serve traffic), or `down` (tunnel can not serve traffic as it has no connections to the Cloudflare Edge).\nAvailable values: \"inactive\", \"degraded\", \"healthy\", \"down\".", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "inactive", + "degraded", + "healthy", + "down", + ), + }, + }, + "tun_type": schema.StringAttribute{ + Description: "The type of tunnel.\nAvailable values: \"cfd_tunnel\", \"warp_connector\", \"warp\", \"magic\", \"ip_sec\", \"gre\", \"cni\".", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "cfd_tunnel", + "warp_connector", + "warp", + "magic", + "ip_sec", + "gre", + "cni", + ), + }, + }, + "connections": schema.ListNestedAttribute{ + Description: "The Cloudflare Tunnel connections between your origin and Cloudflare's edge.", + Computed: true, + DeprecationMessage: "This field will start returning an empty array. To fetch the connections of a given tunnel, please use the dedicated endpoint `/accounts/{account_id}/{tunnel_type}/{tunnel_id}/connections`", + CustomType: customfield.NewNestedObjectListType[ZeroTrustTunnelWARPConnectorConnectionsModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connection.", + Computed: true, + }, + "client_id": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connector.", + Computed: true, + }, + "client_version": schema.StringAttribute{ + Description: "The cloudflared version used to establish this connection.", + Computed: true, + }, + "colo_name": schema.StringAttribute{ + Description: "The Cloudflare data center used for this connection.", + Computed: true, + }, + "is_pending_reconnect": schema.BoolAttribute{ + Description: "Cloudflare continues to track connections for several minutes after they disconnect. This is an optimization to improve latency and reliability of reconnecting. If `true`, the connection has disconnected but is still being tracked. If `false`, the connection is actively serving traffic.", + Computed: true, + }, + "opened_at": schema.StringAttribute{ + Description: "Timestamp of when the connection was established.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "origin_ip": schema.StringAttribute{ + Description: "The public IP address of the host running cloudflared.", + Computed: true, + }, + "uuid": schema.StringAttribute{ + Description: "UUID of the Cloudflare Tunnel connection.", + Computed: true, + }, + }, + }, + }, + "metadata": schema.StringAttribute{ + Description: "Metadata associated with the tunnel.", + Computed: true, + CustomType: jsontypes.NormalizedType{}, + }, + }, + } +} + +func (r *ZeroTrustTunnelWARPConnectorResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *ZeroTrustTunnelWARPConnectorResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} From f165be65a34d7940f431be1bd2f856c86154a64e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:18:09 +0000 Subject: [PATCH 071/187] feat(api): Add 'zero_trust_tunnel_warp_connector' Terraform resource --- .stats.yml | 4 ++-- .../cloudflare_zero_trust_tunnel_warp_connector/import.sh | 0 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 examples/resources/cloudflare_zero_trust_tunnel_warp_connector/import.sh diff --git a/.stats.yml b/.stats.yml index 6423dc9abd..809a27c92a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-92ecd398f18b65eff60080117a9e72a330dc59e34f31f63f7e860130be19dd37.yml -openapi_spec_hash: 79c5a29b646a18da296d1a15fa1c35e6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b45da271fede9a1b0d86e7214a1929d4c58185a7ba4a13b81dbc810ae28bc946.yml +openapi_spec_hash: 12c96c5a3be55ca50041304e4fa879cb config_hash: 3638b66b63ea825ab6a770e729104836 diff --git a/examples/resources/cloudflare_zero_trust_tunnel_warp_connector/import.sh b/examples/resources/cloudflare_zero_trust_tunnel_warp_connector/import.sh old mode 100644 new mode 100755 From b54927e09a4bd3beed2cf958fe655d9c1b2a9547 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:19:38 +0000 Subject: [PATCH 072/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 809a27c92a..c6d72e4cdf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b45da271fede9a1b0d86e7214a1929d4c58185a7ba4a13b81dbc810ae28bc946.yml -openapi_spec_hash: 12c96c5a3be55ca50041304e4fa879cb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7080494be93b05a9ea5b7909a3fc8d312557479a2768fca5c655b5ddc61b16ee.yml +openapi_spec_hash: 94c0a35e53a85e422689d55816be30b4 config_hash: 3638b66b63ea825ab6a770e729104836 From a6fdb6ce5871e1640c69e980bbf8c82dc160c667 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:21:05 +0000 Subject: [PATCH 073/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c6d72e4cdf..25dba73b59 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7080494be93b05a9ea5b7909a3fc8d312557479a2768fca5c655b5ddc61b16ee.yml -openapi_spec_hash: 94c0a35e53a85e422689d55816be30b4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c667925e3595b576306158090003d728469b395646462047d2f28c2632fe5371.yml +openapi_spec_hash: d4753462069b3cd387f2e15049140387 config_hash: 3638b66b63ea825ab6a770e729104836 From f13c3cfc3095ab20caa87e518523098ac3e6ec00 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:27:09 +0000 Subject: [PATCH 074/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 25dba73b59..c6d72e4cdf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c667925e3595b576306158090003d728469b395646462047d2f28c2632fe5371.yml -openapi_spec_hash: d4753462069b3cd387f2e15049140387 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7080494be93b05a9ea5b7909a3fc8d312557479a2768fca5c655b5ddc61b16ee.yml +openapi_spec_hash: 94c0a35e53a85e422689d55816be30b4 config_hash: 3638b66b63ea825ab6a770e729104836 From 8a56165dbbea21bf898fd221626907406ff55518 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:28:39 +0000 Subject: [PATCH 075/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c6d72e4cdf..b50cc4186c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7080494be93b05a9ea5b7909a3fc8d312557479a2768fca5c655b5ddc61b16ee.yml -openapi_spec_hash: 94c0a35e53a85e422689d55816be30b4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ced28b0ffe2aa275d2e1e7ccfc010a25e8c5484ab61bfa5fcd395dcbec7e352b.yml +openapi_spec_hash: 1d705e23ba7bd7ad4243800b0adfc7df config_hash: 3638b66b63ea825ab6a770e729104836 From 296b2f89f68840fc59b0fdf8f6c8ac3a3bcc133a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:30:12 +0000 Subject: [PATCH 076/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b50cc4186c..6819f6c60b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ced28b0ffe2aa275d2e1e7ccfc010a25e8c5484ab61bfa5fcd395dcbec7e352b.yml -openapi_spec_hash: 1d705e23ba7bd7ad4243800b0adfc7df +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6adef39d4e3b845daad61a5a30a5d200af25304ced651c2f93eb5b1b75d523f0.yml +openapi_spec_hash: a917d7a20e48e89936a371612d589f5e config_hash: 3638b66b63ea825ab6a770e729104836 From e9325b557e2b20205d772412e8f574aac1e2cd37 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 21:27:12 +0000 Subject: [PATCH 077/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6819f6c60b..582db8d6e2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6adef39d4e3b845daad61a5a30a5d200af25304ced651c2f93eb5b1b75d523f0.yml -openapi_spec_hash: a917d7a20e48e89936a371612d589f5e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ae4bf24b1b318c1c3ffec8cb29de7efb19993fe579e3614d7a35597ad9254e4b.yml +openapi_spec_hash: dd7adf375f6eaacd9f9629a587b06725 config_hash: 3638b66b63ea825ab6a770e729104836 From 3f801818d67b75ddfb28a2ff635db9633dc4435e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 21:28:48 +0000 Subject: [PATCH 078/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 582db8d6e2..5da4b00270 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ae4bf24b1b318c1c3ffec8cb29de7efb19993fe579e3614d7a35597ad9254e4b.yml -openapi_spec_hash: dd7adf375f6eaacd9f9629a587b06725 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d2cf625552bb02e129bccd3e3d2920e4c9224ab3a1cd5c8f011a06be268fa9ef.yml +openapi_spec_hash: b402fe5a97a55834eed6d948370d590f config_hash: 3638b66b63ea825ab6a770e729104836 From 3bbf4bf23eaa6e899850e06ccc0d2cd8e734bbfa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 23:23:48 +0000 Subject: [PATCH 079/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5da4b00270..ddfc641f50 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d2cf625552bb02e129bccd3e3d2920e4c9224ab3a1cd5c8f011a06be268fa9ef.yml -openapi_spec_hash: b402fe5a97a55834eed6d948370d590f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6ccff587761cbff8646c095027b068a240aa08d9fa2a982c2dc9dbc124e629e6.yml +openapi_spec_hash: baecd2a5b389b2e94744455c7e3ed543 config_hash: 3638b66b63ea825ab6a770e729104836 From 8cbfada0224d12c5b08d5093ecfe63c44f4bc939 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 23:25:30 +0000 Subject: [PATCH 080/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ddfc641f50..d5151cc2d6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6ccff587761cbff8646c095027b068a240aa08d9fa2a982c2dc9dbc124e629e6.yml -openapi_spec_hash: baecd2a5b389b2e94744455c7e3ed543 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-4a4fb0e05ae35f1acaa110d8b3bf80850118b8175857500b4f9435cbf422359a.yml +openapi_spec_hash: a24522aeb0353456fb342db4e8cc613f config_hash: 3638b66b63ea825ab6a770e729104836 From 9359c7d869fbf742aec68ef5ad6731ea11772dbb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 06:11:02 +0000 Subject: [PATCH 081/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d5151cc2d6..c6d72e4cdf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-4a4fb0e05ae35f1acaa110d8b3bf80850118b8175857500b4f9435cbf422359a.yml -openapi_spec_hash: a24522aeb0353456fb342db4e8cc613f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7080494be93b05a9ea5b7909a3fc8d312557479a2768fca5c655b5ddc61b16ee.yml +openapi_spec_hash: 94c0a35e53a85e422689d55816be30b4 config_hash: 3638b66b63ea825ab6a770e729104836 From a1116c9cb48628920e0da842f70ce899be4f585c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 06:12:36 +0000 Subject: [PATCH 082/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c6d72e4cdf..f321168757 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7080494be93b05a9ea5b7909a3fc8d312557479a2768fca5c655b5ddc61b16ee.yml -openapi_spec_hash: 94c0a35e53a85e422689d55816be30b4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a201a0b95ef9694a68b539c154e2f8af9403e69c2a76a96c23da678a5cf63c53.yml +openapi_spec_hash: c16687b3d3c29c614112df5cd8c6e925 config_hash: 3638b66b63ea825ab6a770e729104836 From bd16366808bb32d3f71cc68ef620d5f3cdffcd0c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 09:07:18 +0000 Subject: [PATCH 083/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f321168757..ad7b15cb80 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a201a0b95ef9694a68b539c154e2f8af9403e69c2a76a96c23da678a5cf63c53.yml -openapi_spec_hash: c16687b3d3c29c614112df5cd8c6e925 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d8a7ce4f68df26a83bd19468c74188753cf389273d4101dc59d116c6fca64838.yml +openapi_spec_hash: 6b7f2df36a4d80206a47eb4b07d71dae config_hash: 3638b66b63ea825ab6a770e729104836 From 8e6817375b9f11805c3e0542c2ac0dd8ebc1f9cc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 09:08:48 +0000 Subject: [PATCH 084/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ad7b15cb80..b2f1d87483 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d8a7ce4f68df26a83bd19468c74188753cf389273d4101dc59d116c6fca64838.yml -openapi_spec_hash: 6b7f2df36a4d80206a47eb4b07d71dae +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3bc6b65d629a866d64b39350a583179299328b8fe73eb212fc7fd4c67fbc83c3.yml +openapi_spec_hash: 6275054e9962f29189cb31f9fe6369ca config_hash: 3638b66b63ea825ab6a770e729104836 From cd969da9874628d71dbca42f6656d36827da2cd8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:26:27 +0000 Subject: [PATCH 085/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b2f1d87483..756f374654 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3bc6b65d629a866d64b39350a583179299328b8fe73eb212fc7fd4c67fbc83c3.yml -openapi_spec_hash: 6275054e9962f29189cb31f9fe6369ca +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9dc17a506c1df867a77569a5cffa0e6e9eb2941d4f1f7c88b64bb01fad1e33b2.yml +openapi_spec_hash: 4bd3256c9da0d34eaa03ae6ab22cba99 config_hash: 3638b66b63ea825ab6a770e729104836 From bf14c62d9ab943c3e839d9e6a43c64ef0a81abef Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:27:52 +0000 Subject: [PATCH 086/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 756f374654..4e7a1ee49a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9dc17a506c1df867a77569a5cffa0e6e9eb2941d4f1f7c88b64bb01fad1e33b2.yml -openapi_spec_hash: 4bd3256c9da0d34eaa03ae6ab22cba99 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a22046d4a9b5e5e9b36331de4dea5ba429451df690271adfadc375b5090cb8eb.yml +openapi_spec_hash: faae6fa6426ea9f96c4e9d2aaba4e2fa config_hash: 3638b66b63ea825ab6a770e729104836 From 37bc6aff339054bdc93dd0e04acf353debe65b5e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:44:03 +0000 Subject: [PATCH 087/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4e7a1ee49a..c6d72e4cdf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a22046d4a9b5e5e9b36331de4dea5ba429451df690271adfadc375b5090cb8eb.yml -openapi_spec_hash: faae6fa6426ea9f96c4e9d2aaba4e2fa +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7080494be93b05a9ea5b7909a3fc8d312557479a2768fca5c655b5ddc61b16ee.yml +openapi_spec_hash: 94c0a35e53a85e422689d55816be30b4 config_hash: 3638b66b63ea825ab6a770e729104836 From 605811d4f1f102b659492ecc45202aba411a3c30 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 12:59:37 +0000 Subject: [PATCH 088/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c6d72e4cdf..f3c02f4c52 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7080494be93b05a9ea5b7909a3fc8d312557479a2768fca5c655b5ddc61b16ee.yml -openapi_spec_hash: 94c0a35e53a85e422689d55816be30b4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-1409db7dd8a8b59d833af4f09b7353c565a205b840e6ff4e694702cf5686d8d2.yml +openapi_spec_hash: 4d5df642952f0e402551b5066ce30b41 config_hash: 3638b66b63ea825ab6a770e729104836 From e518e53cdc970245fc6ca41bdfd9abb527cd8a3f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 13:12:34 +0000 Subject: [PATCH 089/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f3c02f4c52..bd8da6ea87 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-1409db7dd8a8b59d833af4f09b7353c565a205b840e6ff4e694702cf5686d8d2.yml -openapi_spec_hash: 4d5df642952f0e402551b5066ce30b41 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c6d04193013f3bca4f9030482ae5dcdac989bf669a5eb16ca7704962e68ed429.yml +openapi_spec_hash: 13d91ceaf866ae973047a549b0f96908 config_hash: 3638b66b63ea825ab6a770e729104836 From cfbe9295fc23c35a7edaea62c9c966ba3d65cc7d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:58:27 +0000 Subject: [PATCH 090/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index bd8da6ea87..028652ecb6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c6d04193013f3bca4f9030482ae5dcdac989bf669a5eb16ca7704962e68ed429.yml -openapi_spec_hash: 13d91ceaf866ae973047a549b0f96908 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-91c68e11008e79ba229f5fa091964709bf55870b4ee9f24d7205dca88eaf15f4.yml +openapi_spec_hash: cef77eba54a04db771bd48c221b1ec10 config_hash: 3638b66b63ea825ab6a770e729104836 From b828d7c37d2c4e35310d1332710b32d88af92618 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 15:21:24 +0000 Subject: [PATCH 091/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 028652ecb6..390288af57 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-91c68e11008e79ba229f5fa091964709bf55870b4ee9f24d7205dca88eaf15f4.yml -openapi_spec_hash: cef77eba54a04db771bd48c221b1ec10 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-68f3cc9a7565e1f19d566051cf708a3b6d96a589d640d03f9c11ec8f0b1faa5e.yml +openapi_spec_hash: 0c0a591ea8213f5556dee68ac0651b90 config_hash: 3638b66b63ea825ab6a770e729104836 From 848a0583e348791d6af9434b7ea94c36dd2cdf26 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 15:23:10 +0000 Subject: [PATCH 092/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 390288af57..cdcb1da621 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-68f3cc9a7565e1f19d566051cf708a3b6d96a589d640d03f9c11ec8f0b1faa5e.yml -openapi_spec_hash: 0c0a591ea8213f5556dee68ac0651b90 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-e0150846da617451f0dc5aff338e0c20215dcf2507dc1a3c889e1d5d5bda317b.yml +openapi_spec_hash: 28d0894d131291bf2370d2940f595b23 config_hash: 3638b66b63ea825ab6a770e729104836 From 56d4428a75dd0b4d73a0e8a7441e0767bf133a2c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 15:30:08 +0000 Subject: [PATCH 093/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index cdcb1da621..c898aa5fe6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-e0150846da617451f0dc5aff338e0c20215dcf2507dc1a3c889e1d5d5bda317b.yml -openapi_spec_hash: 28d0894d131291bf2370d2940f595b23 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c6f415778aca76189fe9ddebb99060c936ecbb2e7143f0f50693a52b78b31198.yml +openapi_spec_hash: 10d7307213405688d8b011de684401cb config_hash: 3638b66b63ea825ab6a770e729104836 From 49008c09bade2c95bc6ba49d3247eb1df5b040c7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 15:31:45 +0000 Subject: [PATCH 094/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c898aa5fe6..04fb2358be 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c6f415778aca76189fe9ddebb99060c936ecbb2e7143f0f50693a52b78b31198.yml -openapi_spec_hash: 10d7307213405688d8b011de684401cb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7eecc1e5a75fcd319c74067c2db0220e829e1ee4a0596a8712c27cac22735c40.yml +openapi_spec_hash: 6a42b6ec6570beb963776d32bfe1bf2c config_hash: 3638b66b63ea825ab6a770e729104836 From 63045deb657321df35257227683bd32e1a6d14d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 16:06:10 +0000 Subject: [PATCH 095/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 04fb2358be..98e7eaeb46 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7eecc1e5a75fcd319c74067c2db0220e829e1ee4a0596a8712c27cac22735c40.yml -openapi_spec_hash: 6a42b6ec6570beb963776d32bfe1bf2c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-00c1dcccfd2527174e7982f568d3efb2d6d7d53e072da0d6b2c0b21c418996d6.yml +openapi_spec_hash: 5096c78955104c32ab5971d5dee33a61 config_hash: 3638b66b63ea825ab6a770e729104836 From 6f64d25a0b4e86f08335bba424b0b366481c7882 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 16:07:42 +0000 Subject: [PATCH 096/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 98e7eaeb46..c8895550c9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-00c1dcccfd2527174e7982f568d3efb2d6d7d53e072da0d6b2c0b21c418996d6.yml -openapi_spec_hash: 5096c78955104c32ab5971d5dee33a61 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ba39266e525fd940251fb354f87a29849939d87a2bdff9568b3bf0185b1a91a9.yml +openapi_spec_hash: 7373bb7ea141c1a9c5ea4932d760d1f4 config_hash: 3638b66b63ea825ab6a770e729104836 From 2bb102c6732a3d7ecb59e6d4e4769732fba9138f Mon Sep 17 00:00:00 2001 From: Musa Jundi Date: Tue, 24 Jun 2025 15:06:03 -0500 Subject: [PATCH 097/187] Add scaffolding for zero_trust_tunnel_warp_connector acceptance tests --- .../data_source_test.go | 36 +++++++++++++++++++ .../resource_test.go | 36 +++++++++++++++++++ .../testdata/basic.tf | 1 + .../testdata/datasource_basic.tf | 1 + 4 files changed, 74 insertions(+) create mode 100644 internal/services/zero_trust_tunnel_warp_connector/data_source_test.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/resource_test.go create mode 100644 internal/services/zero_trust_tunnel_warp_connector/testdata/basic.tf create mode 100644 internal/services/zero_trust_tunnel_warp_connector/testdata/datasource_basic.tf diff --git a/internal/services/zero_trust_tunnel_warp_connector/data_source_test.go b/internal/services/zero_trust_tunnel_warp_connector/data_source_test.go new file mode 100644 index 0000000000..72e90ba113 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/data_source_test.go @@ -0,0 +1,36 @@ +package zero_trust_tunnel_warp_connector_test + +import ( + "errors" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" + "github.com/cloudflare/terraform-provider-cloudflare/internal/utils" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccCloudflareZeroTrustTunnelWarpConnectorDataSource_Basic(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_zero_trust_tunnel_warp_connector." + rnd + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccZeroTrustTunnelWarpConnectorDataSourceConfig(rnd), + Check: resource.ComposeTestCheckFunc( + func(s *terraform.State) error { + return errors.New("test not implemented") + }, + resource.TestCheckResourceAttr(name, "some_string_attribute", "string_value"), + ), + }, + }, + }) +} + +func testAccZeroTrustTunnelWarpConnectorDataSourceConfig(rnd string) string { + return acctest.LoadTestCase("datasource_basic.tf", rnd) +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/resource_test.go b/internal/services/zero_trust_tunnel_warp_connector/resource_test.go new file mode 100644 index 0000000000..b6c8f9934c --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/resource_test.go @@ -0,0 +1,36 @@ +package zero_trust_tunnel_warp_connector_test + +import ( + "errors" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" + "github.com/cloudflare/terraform-provider-cloudflare/internal/utils" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccCloudflareZeroTrustTunnelWarpConnector_Basic(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_zero_trust_tunnel_warp_connector." + rnd + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccZeroTrustTunnelWarpConnectorConfig(rnd), + Check: resource.ComposeTestCheckFunc( + func(s *terraform.State) error { + return errors.New("test not implemented") + }, + resource.TestCheckResourceAttr(name, "some_string_attribute", "string_value"), + ), + }, + }, + }) +} + +func testAccZeroTrustTunnelWarpConnectorConfig(rnd string) string { + return acctest.LoadTestCase("basic.tf", rnd) +} diff --git a/internal/services/zero_trust_tunnel_warp_connector/testdata/basic.tf b/internal/services/zero_trust_tunnel_warp_connector/testdata/basic.tf new file mode 100644 index 0000000000..d3b606f4c0 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/testdata/basic.tf @@ -0,0 +1 @@ +resource "cloudflare_zero_trust_tunnel_warp_connector" "%[1]s" {} \ No newline at end of file diff --git a/internal/services/zero_trust_tunnel_warp_connector/testdata/datasource_basic.tf b/internal/services/zero_trust_tunnel_warp_connector/testdata/datasource_basic.tf new file mode 100644 index 0000000000..8fbfb45370 --- /dev/null +++ b/internal/services/zero_trust_tunnel_warp_connector/testdata/datasource_basic.tf @@ -0,0 +1 @@ +data "cloudflare_zero_trust_tunnel_warp_connector" "%[1]s" {} \ No newline at end of file From e22f287e339cb7f42c4c705430bc59f4e104631e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 16:15:29 +0000 Subject: [PATCH 098/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c8895550c9..6e195152d7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ba39266e525fd940251fb354f87a29849939d87a2bdff9568b3bf0185b1a91a9.yml -openapi_spec_hash: 7373bb7ea141c1a9c5ea4932d760d1f4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-8fcab185d7535e99f17098c2b6408f56da36353ee06be9e9632e800c7f0b0651.yml +openapi_spec_hash: ec02a9aae2abfc09df63c8cabd292d14 config_hash: 3638b66b63ea825ab6a770e729104836 From ae74c9b88fb537bdc9c77d1dccb9d95fd6f96324 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 16:16:59 +0000 Subject: [PATCH 099/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6e195152d7..1207823b41 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-8fcab185d7535e99f17098c2b6408f56da36353ee06be9e9632e800c7f0b0651.yml -openapi_spec_hash: ec02a9aae2abfc09df63c8cabd292d14 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-23528d4e5b2612372f502a17fddc73d6838fbe33b4858addce96b5ce30734344.yml +openapi_spec_hash: b537036f40b8b22df4279e5011a0c908 config_hash: 3638b66b63ea825ab6a770e729104836 From f9a9dfd43bda4ffad8ab5c28e7653c52bce37726 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 16:18:38 +0000 Subject: [PATCH 100/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1207823b41..deb34bf1a3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-23528d4e5b2612372f502a17fddc73d6838fbe33b4858addce96b5ce30734344.yml -openapi_spec_hash: b537036f40b8b22df4279e5011a0c908 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bba1601d2e3e02c77025a0ee3811a75e70432c9cc8a938679555e412dfaa031f.yml +openapi_spec_hash: 255519aded8ac6fe5b0105bfae2e9bdd config_hash: 3638b66b63ea825ab6a770e729104836 From 36280df2515a1a3b2246c8d0eb753fee4cbffc54 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 16:58:05 +0000 Subject: [PATCH 101/187] fix: null nested attribute decoding --- internal/apijson/decoder.go | 3 +- internal/apijson/json_test.go | 45 +++++++++++++++++++++++++++++ internal/customfield/object_list.go | 5 ++++ internal/customfield/object_set.go | 4 +++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/internal/apijson/decoder.go b/internal/apijson/decoder.go index 12ac2da30c..ca4124eaf3 100644 --- a/internal/apijson/decoder.go +++ b/internal/apijson/decoder.go @@ -758,9 +758,10 @@ func (d *decoderBuilder) newTerraformTypeDecoder(t reflect.Type) decoderFunc { } existingObjectListValue := value.Interface().(customfield.NestedObjectListLike) if node.Type == gjson.Null { - if b == Always { + if b == Always || existingObjectListValue.IsNullOrUnknown() { nullValue := existingObjectListValue.NullValue(ctx) value.Set(reflect.ValueOf(nullValue)) + return nil } } diff --git a/internal/apijson/json_test.go b/internal/apijson/json_test.go index b6ccee27b7..7f2b58dece 100644 --- a/internal/apijson/json_test.go +++ b/internal/apijson/json_test.go @@ -1366,6 +1366,51 @@ func TestDecodeFromValue(t *testing.T) { } } +var decode_unset_tests = map[string]struct { + buf string + val interface{} +}{ + "nested_object_list_is_omitted_null": { + `{}`, + ListWithNestedObj{ + A: customfield.NullObjectList[Embedded2](ctx), + }, + }, + "nested_object_list_is_explicit_null": { + `{"a": null}`, + ListWithNestedObj{ + A: customfield.NullObjectList[Embedded2](ctx), + }, + }, + "nested_object_list_is_empty": { + `{"a": []}`, + ListWithNestedObj{ + A: customfield.NewObjectListMust(ctx, []Embedded2{}), + }, + }, +} + +func TestDecodeUnsetBehaviour(t *testing.T) { + spew.Config.SortKeys = true + for name, test := range merge(decode_unset_tests) { + t.Run(name, func(t *testing.T) { + resultValue := reflect.New(reflect.TypeOf(test.val)) + d := &decoderBuilder{ + dateFormat: time.RFC3339, + unmarshalComputedOnly: false, + updateBehavior: IfUnset, + } + if err := d.unmarshal([]byte(test.buf), resultValue.Interface()); err != nil { + t.Fatalf("deserialization of %v failed with error %v", resultValue, err) + } + result := resultValue.Elem().Interface() + if !reflect.DeepEqual(result, test.val) { + t.Fatalf("incorrect deserialization for '%s':\nexpected:\n%s\nactual:\n%s\n", test.buf, spew.Sdump(test.val), spew.Sdump(result)) + } + }) + } +} + type StructWithComputedFields struct { RegStr types.String `tfsdk:"str" json:"str,optional"` CompStr types.String `tfsdk:"comp_str" json:"comp_str,computed"` diff --git a/internal/customfield/object_list.go b/internal/customfield/object_list.go index 65f9852495..d27c02656c 100644 --- a/internal/customfield/object_list.go +++ b/internal/customfield/object_list.go @@ -108,6 +108,7 @@ type NestedObjectListLike interface { NullValue(ctx context.Context) NestedObjectListLike UnknownValue(ctx context.Context) NestedObjectListLike KnownValue(ctx context.Context, T any) NestedObjectListLike + IsNullOrUnknown() bool } var _ NestedObjectListLike = (*NestedObjectList[basetypes.StringValue])(nil) @@ -143,6 +144,10 @@ func (v NestedObjectList[T]) KnownValue(ctx context.Context, anyValues any) Nest return r } +func (v NestedObjectList[T]) IsNullOrUnknown() bool { + return v.IsNull() || v.IsUnknown() +} + func (v NestedObjectList[T]) Equal(o attr.Value) bool { other, ok := o.(NestedObjectList[T]) if !ok { diff --git a/internal/customfield/object_set.go b/internal/customfield/object_set.go index d0a02dace6..f6d6e5a27f 100644 --- a/internal/customfield/object_set.go +++ b/internal/customfield/object_set.go @@ -131,6 +131,10 @@ func (v NestedObjectSet[T]) KnownValue(ctx context.Context, anyValues any) Neste return r } +func (v NestedObjectSet[T]) IsNullOrUnknown() bool { + return v.IsNull() || v.IsUnknown() +} + func (v NestedObjectSet[T]) Equal(o attr.Value) bool { other, ok := o.(NestedObjectSet[T]) if !ok { From 6932e3416d7ba957a71116bb26f62357173e2107 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:04:02 +0000 Subject: [PATCH 102/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index deb34bf1a3..7e2c56777c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bba1601d2e3e02c77025a0ee3811a75e70432c9cc8a938679555e412dfaa031f.yml -openapi_spec_hash: 255519aded8ac6fe5b0105bfae2e9bdd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-5ccac92d493bcce2b0fca1a3ec459695ec3252e37d63ef66f2db34397bb0db1a.yml +openapi_spec_hash: f2eae47824fee247ab66e833b02674d7 config_hash: 3638b66b63ea825ab6a770e729104836 From 9a7f3d7667c6bddfba3992bb3a2427d6621770f5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:05:38 +0000 Subject: [PATCH 103/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7e2c56777c..8ee4900c59 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-5ccac92d493bcce2b0fca1a3ec459695ec3252e37d63ef66f2db34397bb0db1a.yml -openapi_spec_hash: f2eae47824fee247ab66e833b02674d7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-f5c1ed5936a04820b15f8d97ec4be0522dda9da07233a80013ec5dbe109a3b4c.yml +openapi_spec_hash: cf5aaa763029cfad7b24014130e20a7b config_hash: 3638b66b63ea825ab6a770e729104836 From d141eed16ff2fe185116d84df26fa117451356af Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:07:14 +0000 Subject: [PATCH 104/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8ee4900c59..4602eff85d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-f5c1ed5936a04820b15f8d97ec4be0522dda9da07233a80013ec5dbe109a3b4c.yml -openapi_spec_hash: cf5aaa763029cfad7b24014130e20a7b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-81772bedd3ba0f08ca58bc417950a99109f9e117621b0a4b0caac32148337edf.yml +openapi_spec_hash: e08b1f2b42d10b39471a6dcab294c6f7 config_hash: 3638b66b63ea825ab6a770e729104836 From 46faf680a0e3e336c638e011e825a0901c8cae5d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:56:20 +0000 Subject: [PATCH 105/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4602eff85d..feb6520f90 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-81772bedd3ba0f08ca58bc417950a99109f9e117621b0a4b0caac32148337edf.yml -openapi_spec_hash: e08b1f2b42d10b39471a6dcab294c6f7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-e22b1754d3420c20bf1b0114b3dde0ca22512f13321455d089b8250f57472054.yml +openapi_spec_hash: ad117e623b45de231a825003f0ad89c2 config_hash: 3638b66b63ea825ab6a770e729104836 From 3ed9a9afb88a8fe30821ed6c154404f24e885243 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:57:54 +0000 Subject: [PATCH 106/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index feb6520f90..df073fd376 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-e22b1754d3420c20bf1b0114b3dde0ca22512f13321455d089b8250f57472054.yml -openapi_spec_hash: ad117e623b45de231a825003f0ad89c2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ad090764c228f1c55e39edb4b87489c763fde8bf4db1a4888b5032731b188abc.yml +openapi_spec_hash: c6765a3f9cf5c7531ecf7bebebd0e94f config_hash: 3638b66b63ea825ab6a770e729104836 From 9c937e5ed7ba38f2f2cfa8ef94f0185646f18be5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:59:29 +0000 Subject: [PATCH 107/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index df073fd376..6d5c36376c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ad090764c228f1c55e39edb4b87489c763fde8bf4db1a4888b5032731b188abc.yml -openapi_spec_hash: c6765a3f9cf5c7531ecf7bebebd0e94f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-f3e42a1e6e513f6760a7cf166fb11d894b92cdc0a58a69c981bb892c99878351.yml +openapi_spec_hash: 8a6697b2a09832f2eb1bdd14a8b79c4a config_hash: 3638b66b63ea825ab6a770e729104836 From dd2a78544a60b0da0c11673894032359da7ee4f8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 19:31:58 +0000 Subject: [PATCH 108/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6d5c36376c..261d53683a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-f3e42a1e6e513f6760a7cf166fb11d894b92cdc0a58a69c981bb892c99878351.yml -openapi_spec_hash: 8a6697b2a09832f2eb1bdd14a8b79c4a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-1085f96a3f10071c41ec9bf9d00c11d76e323ad4b129a5fc5ec2315e04d57749.yml +openapi_spec_hash: 84600b9fc2cc720fb4c024d3d1602fa2 config_hash: 3638b66b63ea825ab6a770e729104836 From 4db5517263559af9ee07a0ebac6bbb6198753c1f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 19:33:39 +0000 Subject: [PATCH 109/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 261d53683a..38cd55e512 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-1085f96a3f10071c41ec9bf9d00c11d76e323ad4b129a5fc5ec2315e04d57749.yml -openapi_spec_hash: 84600b9fc2cc720fb4c024d3d1602fa2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-773d6234a9a735fe7ab749fffa2c6132201c00256b4a8a67ecdd9339f61fbdce.yml +openapi_spec_hash: c4c0fab1ccfb42fa7d23d4fc02739c6c config_hash: 3638b66b63ea825ab6a770e729104836 From c8b770c1e4f315b6af9d2f094e4bcaa5d9c19fde Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 20:00:07 +0000 Subject: [PATCH 110/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 38cd55e512..971ad9f6fd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-773d6234a9a735fe7ab749fffa2c6132201c00256b4a8a67ecdd9339f61fbdce.yml -openapi_spec_hash: c4c0fab1ccfb42fa7d23d4fc02739c6c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-968b3292c77c608128673a72b76439289ce1a7331ebea75e488b0813ef87d405.yml +openapi_spec_hash: 524557493cb69cafbc7d15c5f08ce762 config_hash: 3638b66b63ea825ab6a770e729104836 From d98090fda309d63ea1e16b57ea7e77e6ce80d545 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:25:06 +0000 Subject: [PATCH 111/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 971ad9f6fd..0725166bec 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-968b3292c77c608128673a72b76439289ce1a7331ebea75e488b0813ef87d405.yml -openapi_spec_hash: 524557493cb69cafbc7d15c5f08ce762 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0bbcf30a5f0f4adab9137040e0fec4258b210de9640f1e3b5cf32aa59fa6d8c1.yml +openapi_spec_hash: 4e70a20442a89618cdae7208f72634ef config_hash: 3638b66b63ea825ab6a770e729104836 From dd210c6c8d4754ab1771d79c0b49b71264e92d8d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:50:09 +0000 Subject: [PATCH 112/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0725166bec..b62e614dc4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0bbcf30a5f0f4adab9137040e0fec4258b210de9640f1e3b5cf32aa59fa6d8c1.yml -openapi_spec_hash: 4e70a20442a89618cdae7208f72634ef +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ab136e7bc1eb52ec981aec86fcc57175d1512517813b2bb1b1ad5347e8a79df5.yml +openapi_spec_hash: 6ccd9306e6f3799dcae56dc4b8b07d7b config_hash: 3638b66b63ea825ab6a770e729104836 From e377785de4b698db515a3402bc491a5e46d1ba85 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 21:53:25 +0000 Subject: [PATCH 113/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b62e614dc4..eed1cf159c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ab136e7bc1eb52ec981aec86fcc57175d1512517813b2bb1b1ad5347e8a79df5.yml -openapi_spec_hash: 6ccd9306e6f3799dcae56dc4b8b07d7b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6588112f47f25ab1b947342bfc30854370192f46f61d728fe5f408f44ac733b3.yml +openapi_spec_hash: 2bc739c52d568d16d5f0768898336d54 config_hash: 3638b66b63ea825ab6a770e729104836 From cd12c85389afb30be54993d3a1b9ae896aaa3e05 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 23:40:26 +0000 Subject: [PATCH 114/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index eed1cf159c..6df6890666 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6588112f47f25ab1b947342bfc30854370192f46f61d728fe5f408f44ac733b3.yml -openapi_spec_hash: 2bc739c52d568d16d5f0768898336d54 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-19706cee8d6617008bcf5e8adb41233f05ebd19ba8c6934f36234c9dbbff2611.yml +openapi_spec_hash: 2d14cc640d64fbde306a1f2841419068 config_hash: 3638b66b63ea825ab6a770e729104836 From 7dba6d9aeb50584455daf85a1738b0a9cd8d64b8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 23:42:03 +0000 Subject: [PATCH 115/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6df6890666..deb34bf1a3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-19706cee8d6617008bcf5e8adb41233f05ebd19ba8c6934f36234c9dbbff2611.yml -openapi_spec_hash: 2d14cc640d64fbde306a1f2841419068 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bba1601d2e3e02c77025a0ee3811a75e70432c9cc8a938679555e412dfaa031f.yml +openapi_spec_hash: 255519aded8ac6fe5b0105bfae2e9bdd config_hash: 3638b66b63ea825ab6a770e729104836 From bb1c85454c84af5f4bea71c67af4716d3ecd5721 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 06:10:00 +0000 Subject: [PATCH 116/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index deb34bf1a3..c898aa5fe6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bba1601d2e3e02c77025a0ee3811a75e70432c9cc8a938679555e412dfaa031f.yml -openapi_spec_hash: 255519aded8ac6fe5b0105bfae2e9bdd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c6f415778aca76189fe9ddebb99060c936ecbb2e7143f0f50693a52b78b31198.yml +openapi_spec_hash: 10d7307213405688d8b011de684401cb config_hash: 3638b66b63ea825ab6a770e729104836 From 461235c67407456992409cc87ed3110ae98f5df6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 09:22:49 +0000 Subject: [PATCH 117/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c898aa5fe6..08f43caa48 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c6f415778aca76189fe9ddebb99060c936ecbb2e7143f0f50693a52b78b31198.yml -openapi_spec_hash: 10d7307213405688d8b011de684401cb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b96027a3d3b3bd4347cbcddd48aceb66e7346aafe482665b572f974c74cae5f1.yml +openapi_spec_hash: f9883dd03232f6a9f1ce3401b45c75e1 config_hash: 3638b66b63ea825ab6a770e729104836 From 27962cae942f2bf0ad0435388465232d8e555311 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 10:57:05 +0000 Subject: [PATCH 118/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 08f43caa48..591a88fb86 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b96027a3d3b3bd4347cbcddd48aceb66e7346aafe482665b572f974c74cae5f1.yml -openapi_spec_hash: f9883dd03232f6a9f1ce3401b45c75e1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-caf8a61380400df01211533e1394edf01cf3651df960a470f37c8e37ea33d1f8.yml +openapi_spec_hash: 09ed9ea8e5027a48cacb6860cc063139 config_hash: 3638b66b63ea825ab6a770e729104836 From 1452417aca6e2324fe305ddce3b93d71cb9e08d1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:30:57 +0000 Subject: [PATCH 119/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 591a88fb86..118e45a7a7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-caf8a61380400df01211533e1394edf01cf3651df960a470f37c8e37ea33d1f8.yml -openapi_spec_hash: 09ed9ea8e5027a48cacb6860cc063139 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b02ff7d1baf39c23c51ecf64bb3544b2bc7a0239082cfb46ad02ecb3fe6b67d6.yml +openapi_spec_hash: 5bf79360e380ac890e19f54ce4e867d3 config_hash: 3638b66b63ea825ab6a770e729104836 From d41fc1fe911c9aef0a980964d61b4ae3349656ce Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:53:40 +0000 Subject: [PATCH 120/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 118e45a7a7..591a88fb86 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b02ff7d1baf39c23c51ecf64bb3544b2bc7a0239082cfb46ad02ecb3fe6b67d6.yml -openapi_spec_hash: 5bf79360e380ac890e19f54ce4e867d3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-caf8a61380400df01211533e1394edf01cf3651df960a470f37c8e37ea33d1f8.yml +openapi_spec_hash: 09ed9ea8e5027a48cacb6860cc063139 config_hash: 3638b66b63ea825ab6a770e729104836 From 5ac0b5b5d96c4f12cc253be73b18dee6d219c56c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 14:03:24 +0000 Subject: [PATCH 121/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 591a88fb86..3200273e61 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-caf8a61380400df01211533e1394edf01cf3651df960a470f37c8e37ea33d1f8.yml -openapi_spec_hash: 09ed9ea8e5027a48cacb6860cc063139 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6405db96ceaa7abf59d3737af41512a43f3e2e7ed038b726a9b9fca18bf43493.yml +openapi_spec_hash: 7b01c7ea60425c73047c6eb81c6408f8 config_hash: 3638b66b63ea825ab6a770e729104836 From 5e54984169d926b968227464cef5bfb3cc7d1081 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 18:42:51 +0000 Subject: [PATCH 122/187] =?UTF-8?q?fix(ci):=20release-doctor=20=E2=80=94?= =?UTF-8?q?=20report=20correct=20token=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/check-release-environment | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 bin/check-release-environment diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000000..3eb4ed5816 --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${GPG_SIGNING_KEY}" ]; then + errors+=("The GPG_SIGNING_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +if [ -z "${GPG_SIGNING_PASSWORD}" ]; then + errors+=("The GPG_SIGNING_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +lenErrors=${#errors[@]} + +if [[ lenErrors -gt 0 ]]; then + echo -e "Found the following errors in the release environment:\n" + + for error in "${errors[@]}"; do + echo -e "- $error\n" + done + + exit 1 +fi + +echo "The environment is ready to push releases!" From 2bfaee33b2cd6c25c4944df11da1d670eb69deb5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 14:54:36 +0000 Subject: [PATCH 123/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3200273e61..6088f4086d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6405db96ceaa7abf59d3737af41512a43f3e2e7ed038b726a9b9fca18bf43493.yml -openapi_spec_hash: 7b01c7ea60425c73047c6eb81c6408f8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-418855f534fdfe512ad1e453934d584f39eaf768596dd6a7598c59ae73ec780e.yml +openapi_spec_hash: 0afd338757e229fd3c9dcea6dbac3a61 config_hash: 3638b66b63ea825ab6a770e729104836 From ad42ee7343995f1e6f0bf9ee1fb3dbdca0395d3b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 15:27:20 +0000 Subject: [PATCH 124/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6088f4086d..f25cfce153 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-418855f534fdfe512ad1e453934d584f39eaf768596dd6a7598c59ae73ec780e.yml -openapi_spec_hash: 0afd338757e229fd3c9dcea6dbac3a61 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-33ed7cc297131e694d7e3ceb037444eac0995df93b78a637f89188173ff1ec1c.yml +openapi_spec_hash: 489a4310a7f30ea33ed0e01035e9a09d config_hash: 3638b66b63ea825ab6a770e729104836 From 1da4d7419372605767e24d2bed0a7504c1ac7200 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:52:41 +0000 Subject: [PATCH 125/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f25cfce153..f71596c4ac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-33ed7cc297131e694d7e3ceb037444eac0995df93b78a637f89188173ff1ec1c.yml -openapi_spec_hash: 489a4310a7f30ea33ed0e01035e9a09d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-943369a9e71cbb5e59c9a531ee6374d695cd5ec1f97b2082b03a8ccde4b3babf.yml +openapi_spec_hash: 72d90fb9a6b464d927d229b296b49c99 config_hash: 3638b66b63ea825ab6a770e729104836 From ddd2db86cf8d4f071173a10ac0e4f93753e7e910 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:55:02 +0000 Subject: [PATCH 126/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f71596c4ac..fbfd1f41ce 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-943369a9e71cbb5e59c9a531ee6374d695cd5ec1f97b2082b03a8ccde4b3babf.yml -openapi_spec_hash: 72d90fb9a6b464d927d229b296b49c99 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-f83e2d9e9a6eb973bb45a45b071c2f6fc7ed7f4fdb9d44178ee8dfd91f67c3f2.yml +openapi_spec_hash: cce9f8726591c6d5f3942ca74651b079 config_hash: 3638b66b63ea825ab6a770e729104836 From 8cd3301c5a862e00bc074e9a6b0d34ed05cf825b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:57:00 +0000 Subject: [PATCH 127/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index fbfd1f41ce..f9a6fb98ea 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-f83e2d9e9a6eb973bb45a45b071c2f6fc7ed7f4fdb9d44178ee8dfd91f67c3f2.yml -openapi_spec_hash: cce9f8726591c6d5f3942ca74651b079 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ed5977b427357609d4c885f8e49f20cd40709ee5201b8d7596965e78ab13408c.yml +openapi_spec_hash: 1881158343449820a2e5a0fd97726c29 config_hash: 3638b66b63ea825ab6a770e729104836 From d2cad01cc1f3274fb705abb849ed37813d2f6cf5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 17:14:30 +0000 Subject: [PATCH 128/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f9a6fb98ea..cd69d8d92c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ed5977b427357609d4c885f8e49f20cd40709ee5201b8d7596965e78ab13408c.yml -openapi_spec_hash: 1881158343449820a2e5a0fd97726c29 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fec12b67a9b920095500a586ad5fdc3d5085e89cb26da79d719b43fc263f4705.yml +openapi_spec_hash: 7f4c139ae43541e7c636a9282c003996 config_hash: 3638b66b63ea825ab6a770e729104836 From 5b945252a5452161d14cd5582c24ed03c6ddfbae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 17:25:03 +0000 Subject: [PATCH 129/187] feat(api): api update --- .stats.yml | 4 ++-- examples/resources/cloudflare_account_token/resource.tf | 3 +-- examples/resources/cloudflare_api_token/resource.tf | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index cd69d8d92c..936417e901 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fec12b67a9b920095500a586ad5fdc3d5085e89cb26da79d719b43fc263f4705.yml -openapi_spec_hash: 7f4c139ae43541e7c636a9282c003996 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3067c2bb6c9724d234be04ae30fd7d84fb04b2ad9fc9808a7e8a60837b300e7e.yml +openapi_spec_hash: 122a9851a2d05c751f47ff5ec875fbb4 config_hash: 3638b66b63ea825ab6a770e729104836 diff --git a/examples/resources/cloudflare_account_token/resource.tf b/examples/resources/cloudflare_account_token/resource.tf index 3b832bb766..894d97bb2e 100644 --- a/examples/resources/cloudflare_account_token/resource.tf +++ b/examples/resources/cloudflare_account_token/resource.tf @@ -17,8 +17,7 @@ resource "cloudflare_account_token" "example_account_token" { } }] resources = { - "com.cloudflare.api.account.zone.22b1de5f1c0e4b3ea97bb1e963b06a43" = "*" - "com.cloudflare.api.account.zone.eb78d65290b24279ba6f44721b3ea3c4" = "*" + foo = "string" } }] condition = { diff --git a/examples/resources/cloudflare_api_token/resource.tf b/examples/resources/cloudflare_api_token/resource.tf index 60b090078e..8886b0b8ca 100644 --- a/examples/resources/cloudflare_api_token/resource.tf +++ b/examples/resources/cloudflare_api_token/resource.tf @@ -16,8 +16,7 @@ resource "cloudflare_api_token" "example_api_token" { } }] resources = { - "com.cloudflare.api.account.zone.22b1de5f1c0e4b3ea97bb1e963b06a43" = "*" - "com.cloudflare.api.account.zone.eb78d65290b24279ba6f44721b3ea3c4" = "*" + foo = "string" } }] condition = { From e1cca1826aefd44e7429f949c22e4236c14cce1c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 18:46:27 +0000 Subject: [PATCH 130/187] fix(logpull_retention): Fix Terraform ID property --- .stats.yml | 2 +- .../cloudflare_logpull_retention/import.sh | 1 + internal/services/logpull_retention/model.go | 1 + .../services/logpull_retention/resource.go | 47 +++++++++++++++++++ internal/services/logpull_retention/schema.go | 7 ++- 5 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 examples/resources/cloudflare_logpull_retention/import.sh diff --git a/.stats.yml b/.stats.yml index 936417e901..ef7cf1a2de 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3067c2bb6c9724d234be04ae30fd7d84fb04b2ad9fc9808a7e8a60837b300e7e.yml openapi_spec_hash: 122a9851a2d05c751f47ff5ec875fbb4 -config_hash: 3638b66b63ea825ab6a770e729104836 +config_hash: 284c4178d08f75d8c8b29f275948a8fd diff --git a/examples/resources/cloudflare_logpull_retention/import.sh b/examples/resources/cloudflare_logpull_retention/import.sh new file mode 100644 index 0000000000..e3e1e65882 --- /dev/null +++ b/examples/resources/cloudflare_logpull_retention/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_logpull_retention.example '' diff --git a/internal/services/logpull_retention/model.go b/internal/services/logpull_retention/model.go index a3d7b837f7..4d26ca9574 100644 --- a/internal/services/logpull_retention/model.go +++ b/internal/services/logpull_retention/model.go @@ -12,6 +12,7 @@ type LogpullRetentionResultEnvelope struct { } type LogpullRetentionModel struct { + ID types.String `tfsdk:"id" json:"-,computed"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` Flag types.Bool `tfsdk:"flag" json:"flag,optional"` } diff --git a/internal/services/logpull_retention/resource.go b/internal/services/logpull_retention/resource.go index 64a91d775c..aa82c005d5 100644 --- a/internal/services/logpull_retention/resource.go +++ b/internal/services/logpull_retention/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/logs" "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*LogpullRetentionResource)(nil) var _ resource.ResourceWithModifyPlan = (*LogpullRetentionResource)(nil) +var _ resource.ResourceWithImportState = (*LogpullRetentionResource)(nil) func NewResource() resource.Resource { return &LogpullRetentionResource{} @@ -88,6 +91,7 @@ func (r *LogpullRetentionResource) Create(ctx context.Context, req resource.Crea return } data = &env.Result + data.ID = data.ZoneID resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -131,6 +135,7 @@ func (r *LogpullRetentionResource) Read(ctx context.Context, req resource.ReadRe return } data = &env.Result + data.ID = data.ZoneID resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -139,6 +144,48 @@ func (r *LogpullRetentionResource) Delete(ctx context.Context, req resource.Dele } +func (r *LogpullRetentionResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *LogpullRetentionModel = new(LogpullRetentionModel) + + path := "" + diags := importpath.ParseImportID( + req.ID, + "", + &path, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.ZoneID = types.StringValue(path) + + res := new(http.Response) + env := LogpullRetentionResultEnvelope{*data} + _, err := r.client.Logs.Control.Retention.Get( + ctx, + logs.ControlRetentionGetParams{ + ZoneID: cloudflare.F(path), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + data.ID = data.ZoneID + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *LogpullRetentionResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { if req.State.Raw.IsNull() { resp.Diagnostics.AddWarning( diff --git a/internal/services/logpull_retention/schema.go b/internal/services/logpull_retention/schema.go index 08ee07984a..44e2a97479 100644 --- a/internal/services/logpull_retention/schema.go +++ b/internal/services/logpull_retention/schema.go @@ -17,10 +17,15 @@ var _ resource.ResourceWithConfigValidators = (*LogpullRetentionResource)(nil) func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, + }, "zone_id": schema.StringAttribute{ Description: "Identifier.", Required: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, }, "flag": schema.BoolAttribute{ Description: "The log retention flag for Logpull API.", From bd93752d335e647ca9682d88e3717cc661798c48 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 19:02:46 +0000 Subject: [PATCH 131/187] chore(internal): codegen related update --- examples/resources/cloudflare_logpull_retention/import.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 examples/resources/cloudflare_logpull_retention/import.sh diff --git a/examples/resources/cloudflare_logpull_retention/import.sh b/examples/resources/cloudflare_logpull_retention/import.sh old mode 100644 new mode 100755 From dba168a6155fcf80a7fc1f94268cc42c6f718436 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 06:09:45 +0000 Subject: [PATCH 132/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ef7cf1a2de..8990325b48 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3067c2bb6c9724d234be04ae30fd7d84fb04b2ad9fc9808a7e8a60837b300e7e.yml -openapi_spec_hash: 122a9851a2d05c751f47ff5ec875fbb4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-357249a6950c7512598745513daaa0dbf653513c57dd9604f5e6d8b7e6ded2c4.yml +openapi_spec_hash: 3ab1a48771883dabf9cb61dbb58bbdb3 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 4bebdf7a18d42f1be1720ff524175908b8dd8969 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 07:07:40 +0000 Subject: [PATCH 133/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8990325b48..3f5769c1d8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-357249a6950c7512598745513daaa0dbf653513c57dd9604f5e6d8b7e6ded2c4.yml -openapi_spec_hash: 3ab1a48771883dabf9cb61dbb58bbdb3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-06c0722289c612a94a6c1e228ea4ada586b3942b04cb02b9a55d98adef5e9558.yml +openapi_spec_hash: f6f0cf5e8a41260e0d1ddf20a71a9c75 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 4de50f4b69ffb31c53b574a25b2c759b5347955e Mon Sep 17 00:00:00 2001 From: Eduardo Gomes Date: Mon, 23 Jun 2025 08:54:27 +0200 Subject: [PATCH 134/187] AUTH-7265 Fix zero_trust_access_applications --- ...hen_other_attribute_is_one_of_validator.go | 86 ++++ ..._other_attribute_to_be_one_of_validator.go | 110 +++++ .../zero_trust_access_application/model.go | 38 +- .../normalizations.go | 178 ++++++++ .../plan_modifiers.go | 137 ++++++ .../zero_trust_access_application/resource.go | 36 +- .../resource_test.go | 423 ++++++++++++------ .../zero_trust_access_application/schema.go | 252 +++++++++-- .../accessapplicationconfigwithadefinedidp.tf | 12 +- .../accessapplicationconfigwithinvalidsaas.tf | 7 + ...cessapplicationconfigwithlegacypolicies.tf | 42 ++ ...ssapplicationconfigwithreusablepolicies.tf | 53 +-- .../accessapplicationconfigwithsamlsaas.tf | 24 +- ...ationwithapplaunchercustomizationfields.tf | 37 +- .../normalizations.go | 18 + .../resource.go | 4 +- .../schema.go | 5 +- .../zero_trust_access_policy/model.go | 2 - .../zero_trust_access_policy/schema.go | 7 - scripts/run-ci-acceptance-tests | 1 + 20 files changed, 1196 insertions(+), 276 deletions(-) create mode 100644 internal/customvalidator/required_when_other_attribute_is_one_of_validator.go create mode 100644 internal/customvalidator/requires_other_attribute_to_be_one_of_validator.go create mode 100644 internal/services/zero_trust_access_application/normalizations.go create mode 100644 internal/services/zero_trust_access_application/plan_modifiers.go create mode 100644 internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithinvalidsaas.tf create mode 100644 internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithlegacypolicies.tf create mode 100644 internal/services/zero_trust_access_identity_provider/normalizations.go diff --git a/internal/customvalidator/required_when_other_attribute_is_one_of_validator.go b/internal/customvalidator/required_when_other_attribute_is_one_of_validator.go new file mode 100644 index 0000000000..4d1413001a --- /dev/null +++ b/internal/customvalidator/required_when_other_attribute_is_one_of_validator.go @@ -0,0 +1,86 @@ +package customvalidator + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + "strings" +) + +func RequiredWhenOtherStringIsOneOf(pathExpr path.Expression, wantStrValues ...string) requiredWhenOtherAttributeIsOneOfValidator { + var wantValues []attr.Value + for _, v := range wantStrValues { + wantValues = append(wantValues, types.StringValue(v)) + } + return requiredWhenOtherAttributeIsOneOfValidator{ + pathExpr, + wantValues, + } +} + +type requiredWhenOtherAttributeIsOneOfValidator struct { + pathExpr path.Expression + wantValues []attr.Value +} + +func (i requiredWhenOtherAttributeIsOneOfValidator) Description(ctx context.Context) string { + var wantValuesAsStrings []string + for _, v := range i.wantValues { + wantValuesAsStrings = append(wantValuesAsStrings, v.String()) + } + return fmt.Sprintf("has to be set if %q is one of: %s", i.pathExpr, strings.Join(wantValuesAsStrings, ", ")) +} + +func (i requiredWhenOtherAttributeIsOneOfValidator) MarkdownDescription(ctx context.Context) string { + return i.Description(ctx) +} + +func (i requiredWhenOtherAttributeIsOneOfValidator) validateAny(ctx context.Context, cfg *tfsdk.Config, attrPath path.Path, value attr.Value, resDiagnostics *diag.Diagnostics) { + if !value.IsNull() || value.IsUnknown() { + return + } + + matchedPaths, diags := cfg.PathMatches(ctx, i.pathExpr) + resDiagnostics.Append(diags...) + + for _, mp := range matchedPaths { + // If the user specifies the same attribute this validator is applied to, + // also as part of the input, skip it + if mp.Equal(attrPath) { + continue + } + + var mpVal attr.Value + resDiagnostics.Append(cfg.GetAttribute(ctx, mp, &mpVal)...) + + // Collect all errors + if diags.HasError() { + continue + } + + // Delay validation until all involved attribute have a known value + if mpVal.IsUnknown() { + return + } + + for _, wantValue := range i.wantValues { + if mpVal.Equal(wantValue) { + description := fmt.Sprintf("%q %s", attrPath, i.Description(ctx)) + resDiagnostics.Append(validatordiag.InvalidAttributeCombinationDiagnostic( + attrPath, + description, + )) + } + } + } +} + +func (i requiredWhenOtherAttributeIsOneOfValidator) ValidateObject(ctx context.Context, req validator.ObjectRequest, res *validator.ObjectResponse) { + i.validateAny(ctx, &req.Config, req.Path, req.ConfigValue, &res.Diagnostics) +} diff --git a/internal/customvalidator/requires_other_attribute_to_be_one_of_validator.go b/internal/customvalidator/requires_other_attribute_to_be_one_of_validator.go new file mode 100644 index 0000000000..bf9dbeae7d --- /dev/null +++ b/internal/customvalidator/requires_other_attribute_to_be_one_of_validator.go @@ -0,0 +1,110 @@ +package customvalidator + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + "strings" +) + +func RequiresOtherStringAttributeToBeOneOf(pathExpr path.Expression, wantStrValues ...string) requiresOtherAttributeToBeOneOfValidator { + var wantValues []attr.Value + for _, v := range wantStrValues { + wantValues = append(wantValues, types.StringValue(v)) + } + return requiresOtherAttributeToBeOneOfValidator{ + pathExpr, + wantValues, + } +} + +func RequiresOtherStringAttributeToNullOrBeOneOf(pathExpr path.Expression, wantStrValues ...string) requiresOtherAttributeToBeOneOfValidator { + v := RequiresOtherStringAttributeToBeOneOf(pathExpr, wantStrValues...) + v.wantValues = append(v.wantValues, types.StringNull()) + return v +} + +type requiresOtherAttributeToBeOneOfValidator struct { + pathExpr path.Expression + wantValues []attr.Value +} + +func (i requiresOtherAttributeToBeOneOfValidator) Description(ctx context.Context) string { + var wantValuesAsStrings []string + for _, v := range i.wantValues { + wantValuesAsStrings = append(wantValuesAsStrings, v.String()) + } + return fmt.Sprintf("can only be set if %q is one of: %s", i.pathExpr, strings.Join(wantValuesAsStrings, ", ")) +} + +func (i requiresOtherAttributeToBeOneOfValidator) MarkdownDescription(ctx context.Context) string { + return i.Description(ctx) +} + +func (i requiresOtherAttributeToBeOneOfValidator) validateAny(ctx context.Context, cfg *tfsdk.Config, attrPath path.Path, value attr.Value, resDiagnostics *diag.Diagnostics) { + if value.IsNull() || value.IsUnknown() { + return + } + + matchedPaths, diags := cfg.PathMatches(ctx, i.pathExpr) + resDiagnostics.Append(diags...) + + for _, mp := range matchedPaths { + // If the user specifies the same attribute this validator is applied to, + // also as part of the input, skip it + if mp.Equal(attrPath) { + continue + } + + var mpVal attr.Value + resDiagnostics.Append(cfg.GetAttribute(ctx, mp, &mpVal)...) + + // Collect all errors + if diags.HasError() { + continue + } + + // Delay validation until all involved attribute have a known value + if mpVal.IsUnknown() { + return + } + + foundMatch := false + for _, wantValue := range i.wantValues { + if mpVal.Equal(wantValue) { + foundMatch = true + break + } + } + + if !foundMatch { + description := fmt.Sprintf("%q %s", attrPath, i.Description(ctx)) + resDiagnostics.Append(validatordiag.InvalidAttributeCombinationDiagnostic( + attrPath, + description, + )) + } + } +} + +func (i requiresOtherAttributeToBeOneOfValidator) ValidateBool(ctx context.Context, req validator.BoolRequest, res *validator.BoolResponse) { + i.validateAny(ctx, &req.Config, req.Path, req.ConfigValue, &res.Diagnostics) +} + +func (i requiresOtherAttributeToBeOneOfValidator) ValidateString(ctx context.Context, req validator.StringRequest, res *validator.StringResponse) { + i.validateAny(ctx, &req.Config, req.Path, req.ConfigValue, &res.Diagnostics) +} + +func (i requiresOtherAttributeToBeOneOfValidator) ValidateObject(ctx context.Context, req validator.ObjectRequest, res *validator.ObjectResponse) { + i.validateAny(ctx, &req.Config, req.Path, req.ConfigValue, &res.Diagnostics) +} + +func (i requiresOtherAttributeToBeOneOfValidator) ValidateList(ctx context.Context, req validator.ListRequest, res *validator.ListResponse) { + i.validateAny(ctx, &req.Config, req.Path, req.ConfigValue, &res.Diagnostics) +} diff --git a/internal/services/zero_trust_access_application/model.go b/internal/services/zero_trust_access_application/model.go index d2099eb85b..0206f57f8a 100644 --- a/internal/services/zero_trust_access_application/model.go +++ b/internal/services/zero_trust_access_application/model.go @@ -24,10 +24,10 @@ type ZeroTrustAccessApplicationModel struct { CustomDenyMessage types.String `tfsdk:"custom_deny_message" json:"custom_deny_message,optional"` CustomDenyURL types.String `tfsdk:"custom_deny_url" json:"custom_deny_url,optional"` CustomNonIdentityDenyURL types.String `tfsdk:"custom_non_identity_deny_url" json:"custom_non_identity_deny_url,optional"` - Domain types.String `tfsdk:"domain" json:"domain,optional"` + Domain types.String `tfsdk:"domain" json:"domain,computed_optional"` HeaderBgColor types.String `tfsdk:"header_bg_color" json:"header_bg_color,optional"` LogoURL types.String `tfsdk:"logo_url" json:"logo_url,optional"` - Name types.String `tfsdk:"name" json:"name,optional"` + Name types.String `tfsdk:"name" json:"name,computed_optional"` OptionsPreflightBypass types.Bool `tfsdk:"options_preflight_bypass" json:"options_preflight_bypass,optional"` ReadServiceTokensFromHeader types.String `tfsdk:"read_service_tokens_from_header" json:"read_service_tokens_from_header,optional"` SameSiteCookieAttribute types.String `tfsdk:"same_site_cookie_attribute" json:"same_site_cookie_attribute,optional"` @@ -41,21 +41,19 @@ type ZeroTrustAccessApplicationModel struct { SCIMConfig *ZeroTrustAccessApplicationSCIMConfigModel `tfsdk:"scim_config" json:"scim_config,optional"` TargetCriteria *[]*ZeroTrustAccessApplicationTargetCriteriaModel `tfsdk:"target_criteria" json:"target_criteria,optional"` AppLauncherVisible types.Bool `tfsdk:"app_launcher_visible" json:"app_launcher_visible,computed_optional"` - AutoRedirectToIdentity types.Bool `tfsdk:"auto_redirect_to_identity" json:"auto_redirect_to_identity,computed_optional"` - EnableBindingCookie types.Bool `tfsdk:"enable_binding_cookie" json:"enable_binding_cookie,computed_optional"` + AutoRedirectToIdentity types.Bool `tfsdk:"auto_redirect_to_identity" json:"auto_redirect_to_identity,optional"` + EnableBindingCookie types.Bool `tfsdk:"enable_binding_cookie" json:"enable_binding_cookie,optional"` HTTPOnlyCookieAttribute types.Bool `tfsdk:"http_only_cookie_attribute" json:"http_only_cookie_attribute,computed_optional"` - PathCookieAttribute types.Bool `tfsdk:"path_cookie_attribute" json:"path_cookie_attribute,computed_optional"` + PathCookieAttribute types.Bool `tfsdk:"path_cookie_attribute" json:"path_cookie_attribute,optional"` SessionDuration types.String `tfsdk:"session_duration" json:"session_duration,computed_optional"` SkipAppLauncherLoginPage types.Bool `tfsdk:"skip_app_launcher_login_page" json:"skip_app_launcher_login_page,computed_optional"` SelfHostedDomains customfield.List[types.String] `tfsdk:"self_hosted_domains" json:"self_hosted_domains,computed_optional"` - Tags customfield.List[types.String] `tfsdk:"tags" json:"tags,computed_optional"` + Tags customfield.List[types.String] `tfsdk:"tags" json:"tags,optional"` Destinations customfield.NestedObjectList[ZeroTrustAccessApplicationDestinationsModel] `tfsdk:"destinations" json:"destinations,computed_optional"` - LandingPageDesign customfield.NestedObject[ZeroTrustAccessApplicationLandingPageDesignModel] `tfsdk:"landing_page_design" json:"landing_page_design,computed_optional"` - Policies customfield.NestedObjectList[ZeroTrustAccessApplicationPoliciesModel] `tfsdk:"policies" json:"policies,computed_optional"` - SaaSApp customfield.NestedObject[ZeroTrustAccessApplicationSaaSAppModel] `tfsdk:"saas_app" json:"saas_app,computed_optional"` + LandingPageDesign customfield.NestedObject[ZeroTrustAccessApplicationLandingPageDesignModel] `tfsdk:"landing_page_design" json:"landing_page_design,optional"` + Policies *[]ZeroTrustAccessApplicationPoliciesModel `tfsdk:"policies" json:"policies,optional"` + SaaSApp customfield.NestedObject[ZeroTrustAccessApplicationSaaSAppModel] `tfsdk:"saas_app" json:"saas_app,optional"` AUD types.String `tfsdk:"aud" json:"aud,computed"` - CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` - UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` } func (m ZeroTrustAccessApplicationModel) MarshalJSON() (data []byte, err error) { @@ -144,13 +142,13 @@ type ZeroTrustAccessApplicationLandingPageDesignModel struct { type ZeroTrustAccessApplicationPoliciesModel struct { ID types.String `tfsdk:"id" json:"id,optional"` - Precedence types.Int64 `tfsdk:"precedence" json:"precedence,optional"` + Precedence types.Int64 `tfsdk:"precedence" json:"precedence,computed_optional"` Decision types.String `tfsdk:"decision" json:"decision,optional"` - Include customfield.NestedObjectList[ZeroTrustAccessApplicationPoliciesIncludeModel] `tfsdk:"include" json:"include,computed_optional"` + Include customfield.NestedObjectList[ZeroTrustAccessApplicationPoliciesIncludeModel] `tfsdk:"include" json:"include,optional"` Name types.String `tfsdk:"name" json:"name,optional"` ConnectionRules *ZeroTrustAccessApplicationPoliciesConnectionRulesModel `tfsdk:"connection_rules" json:"connection_rules,optional"` - Exclude customfield.NestedObjectList[ZeroTrustAccessApplicationPoliciesExcludeModel] `tfsdk:"exclude" json:"exclude,computed_optional"` - Require customfield.NestedObjectList[ZeroTrustAccessApplicationPoliciesRequireModel] `tfsdk:"require" json:"require,computed_optional"` + Exclude customfield.NestedObjectList[ZeroTrustAccessApplicationPoliciesExcludeModel] `tfsdk:"exclude" json:"exclude,optional"` + Require customfield.NestedObjectList[ZeroTrustAccessApplicationPoliciesRequireModel] `tfsdk:"require" json:"require,optional"` } type ZeroTrustAccessApplicationPoliciesIncludeModel struct { @@ -529,18 +527,18 @@ type ZeroTrustAccessApplicationSaaSAppModel struct { CustomAttributes *[]*ZeroTrustAccessApplicationSaaSAppCustomAttributesModel `tfsdk:"custom_attributes" json:"custom_attributes,optional"` DefaultRelayState types.String `tfsdk:"default_relay_state" json:"default_relay_state,optional"` IdPEntityID types.String `tfsdk:"idp_entity_id" json:"idp_entity_id,computed_optional"` - NameIDFormat types.String `tfsdk:"name_id_format" json:"name_id_format,optional"` + NameIDFormat types.String `tfsdk:"name_id_format" json:"name_id_format,computed_optional"` NameIDTransformJsonata types.String `tfsdk:"name_id_transform_jsonata" json:"name_id_transform_jsonata,optional"` - PublicKey types.String `tfsdk:"public_key" json:"public_key,computed_optional"` + PublicKey types.String `tfsdk:"public_key" json:"public_key,computed"` SAMLAttributeTransformJsonata types.String `tfsdk:"saml_attribute_transform_jsonata" json:"saml_attribute_transform_jsonata,optional"` SPEntityID types.String `tfsdk:"sp_entity_id" json:"sp_entity_id,optional"` SSOEndpoint types.String `tfsdk:"sso_endpoint" json:"sso_endpoint,computed_optional"` UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` - AccessTokenLifetime types.String `tfsdk:"access_token_lifetime" json:"access_token_lifetime,optional"` + AccessTokenLifetime types.String `tfsdk:"access_token_lifetime" json:"access_token_lifetime,computed_optional"` AllowPKCEWithoutClientSecret types.Bool `tfsdk:"allow_pkce_without_client_secret" json:"allow_pkce_without_client_secret,optional"` AppLauncherURL types.String `tfsdk:"app_launcher_url" json:"app_launcher_url,optional"` - ClientID types.String `tfsdk:"client_id" json:"client_id,computed_optional"` - ClientSecret types.String `tfsdk:"client_secret" json:"client_secret,computed_optional"` + ClientID types.String `tfsdk:"client_id" json:"client_id,computed"` + ClientSecret types.String `tfsdk:"client_secret" json:"client_secret,computed"` CustomClaims *[]*ZeroTrustAccessApplicationSaaSAppCustomClaimsModel `tfsdk:"custom_claims" json:"custom_claims,optional"` GrantTypes *[]types.String `tfsdk:"grant_types" json:"grant_types,optional"` GroupFilterRegex types.String `tfsdk:"group_filter_regex" json:"group_filter_regex,optional"` diff --git a/internal/services/zero_trust_access_application/normalizations.go b/internal/services/zero_trust_access_application/normalizations.go new file mode 100644 index 0000000000..36cab24f7d --- /dev/null +++ b/internal/services/zero_trust_access_application/normalizations.go @@ -0,0 +1,178 @@ +package zero_trust_access_application + +import ( + "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "slices" +) + +func normalizeEmptyAndNullString(data *basetypes.StringValue, stateData basetypes.StringValue) { + if data.ValueString() != "" || stateData.ValueString() != "" { + return + } + *data = stateData +} + +func normalizeFalseAndNullBool(data *basetypes.BoolValue, stateData basetypes.BoolValue) { + if data.ValueBool() || stateData.ValueBool() { + return + } + *data = stateData +} + +func normalizeTrueAndNullBool(data *basetypes.BoolValue, stateData basetypes.BoolValue) { + if (!data.IsNull() && !data.ValueBool()) || (!stateData.IsNull() && !stateData.ValueBool()) { + return + } + if stateData.IsUnknown() { + return + } + *data = stateData +} + +type ListField interface { + Elements() []attr.Value +} + +func normalizeEmptyAndNullList[T ListField](data *T, stateData T) { + if len((*data).Elements()) != 0 || len(stateData.Elements()) != 0 { + return + } + *data = stateData +} + +func normalizeEmptyAndNullSlice[T any](data **[]T, stateData *[]T) { + if (*data != nil && len(**data) != 0) || (stateData != nil && len(*stateData) != 0) { + return + } + *data = stateData +} + +type IsNull interface { + IsNull() bool +} + +func persistNullFromState[T IsNull](data *T, stateData T) { + if stateData.IsNull() { + *data = stateData + } +} + +func normalizeReadZeroTrustApplicationSamlAppData(data *ZeroTrustAccessApplicationSaaSAppModel, stateData ZeroTrustAccessApplicationSaaSAppModel) { + normalizeEmptyAndNullString(&data.SPEntityID, stateData.SPEntityID) + normalizeEmptyAndNullString(&data.ConsumerServiceURL, stateData.ConsumerServiceURL) +} + +func normalizeReadZeroTrustApplicationOidcAppData(data *ZeroTrustAccessApplicationSaaSAppModel, stateData ZeroTrustAccessApplicationSaaSAppModel) { + // Prevent diffs on the default access_token_lifetime + if data.AccessTokenLifetime.ValueString() == "5m" && stateData.AccessTokenLifetime == types.StringNull() { + data.AccessTokenLifetime = stateData.AccessTokenLifetime + } + + // client_secret is only returned when the app is first created, assigning here from the state + // to prevent a diff when the app is updated + if !stateData.ClientSecret.IsUnknown() && !stateData.ClientSecret.IsNull() { + data.ClientSecret = stateData.ClientSecret + } + + normalizeFalseAndNullBool(&data.AllowPKCEWithoutClientSecret, stateData.AllowPKCEWithoutClientSecret) +} + +// Normalizing function to ensure consistency between the state and the meaning of the API response. +// Alters the API response before applying it to the state by laxing equalities between null & zero-value +// for some attributes, and nullifies fields that terraform should not be saving in the state. +func normalizeReadZeroTrustApplicationAPIData(ctx context.Context, data, stateData *ZeroTrustAccessApplicationModel) diag.Diagnostics { + diags := make(diag.Diagnostics, 0) + + // Empty `allowed_idps` is the same as a null value. The API might return an empty array, so we need to normalize it + // here to avoid a diff + normalizeEmptyAndNullSlice(&data.AllowedIdPs, stateData.AllowedIdPs) + // `policies` might not be in the configuration, so we need to normalize it here to avoid a diff + normalizeEmptyAndNullSlice(&data.Policies, stateData.Policies) + // `tags` might not be in the configuration, so we need to normalize it here to avoid a diff + normalizeEmptyAndNullList(&data.Tags, stateData.Tags) + + normalizeFalseAndNullBool(&data.EnableBindingCookie, stateData.EnableBindingCookie) + normalizeFalseAndNullBool(&data.OptionsPreflightBypass, stateData.OptionsPreflightBypass) + normalizeFalseAndNullBool(&data.AutoRedirectToIdentity, stateData.AutoRedirectToIdentity) + if slices.Contains(selfHostedAppTypes, data.Type.String()) { + normalizeTrueAndNullBool(&data.HTTPOnlyCookieAttribute, stateData.HTTPOnlyCookieAttribute) + } + + if !data.SaaSApp.IsNull() && !stateData.SaaSApp.IsNull() { + var dataSaasApp, stateDataSaasApp ZeroTrustAccessApplicationSaaSAppModel + diags.Append(data.SaaSApp.As(ctx, &dataSaasApp, basetypes.ObjectAsOptions{})...) + diags.Append(stateData.SaaSApp.As(ctx, &stateDataSaasApp, basetypes.ObjectAsOptions{})...) + if diags.HasError() { + return diags + } + + switch dataSaasApp.AuthType.ValueString() { + case "saml": + normalizeReadZeroTrustApplicationSamlAppData(&dataSaasApp, stateDataSaasApp) + case "oidc": + normalizeReadZeroTrustApplicationOidcAppData(&dataSaasApp, stateDataSaasApp) + } + + var saasDiags diag.Diagnostics + data.SaaSApp, saasDiags = customfield.NewObject[ZeroTrustAccessApplicationSaaSAppModel](ctx, &dataSaasApp) + diags.Append(saasDiags...) + if diags.HasError() { + return diags + } + } + + if data.Policies != nil && stateData.Policies != nil { + for i := range *data.Policies { + // Preserve null values from the Terraform state, even if the API response returns actual values. + // This is important because the API may populate these fields when it expands the attached reusable policy + // from its given ID. + // + // However, we intentionally avoid storing the full expanded policy inside the application resource's + // nested block, as its source of truth is the reusable policy resource itself. + // Only the policy ID should be persisted in state for reusable policies. + // For legacy policies, the ID should be ignored as they are not a standalone resource, but rather + // live as a nested object owned by the application. + persistNullFromState(&(*data.Policies)[i].ID, (*stateData.Policies)[i].ID) + persistNullFromState(&(*data.Policies)[i].Decision, (*stateData.Policies)[i].Decision) + persistNullFromState(&(*data.Policies)[i].Name, (*stateData.Policies)[i].Name) + persistNullFromState(&(*data.Policies)[i].Include, (*stateData.Policies)[i].Include) + persistNullFromState(&(*data.Policies)[i].Require, (*stateData.Policies)[i].Require) + persistNullFromState(&(*data.Policies)[i].Exclude, (*stateData.Policies)[i].Exclude) + } + } + + if data.SCIMConfig != nil && stateData.SCIMConfig != nil { + if data.SCIMConfig.Authentication != nil && stateData.SCIMConfig.Authentication != nil { + data.SCIMConfig.Authentication.Password = stateData.SCIMConfig.Authentication.Password + data.SCIMConfig.Authentication.Token = stateData.SCIMConfig.Authentication.Token + data.SCIMConfig.Authentication.ClientSecret = stateData.SCIMConfig.Authentication.ClientSecret + } + } + + return diags +} + +// Some fields are write-only sensitive and should not be stored in the state. +// Usually these secrets are injected in the config from a secret store. +func loadConfigSensitiveValuesForWriting(ctx context.Context, data *ZeroTrustAccessApplicationModel, cfg *tfsdk.Config) diag.Diagnostics { + var ( + diags = make(diag.Diagnostics, 0) + cfgData *ZeroTrustAccessApplicationModel + ) + diags.Append(cfg.Get(ctx, &cfgData)...) + + if data.SCIMConfig != nil && cfgData.SCIMConfig != nil { + if data.SCIMConfig.Authentication != nil && cfgData.SCIMConfig.Authentication != nil { + data.SCIMConfig.Authentication.Password = cfgData.SCIMConfig.Authentication.Password + data.SCIMConfig.Authentication.Token = cfgData.SCIMConfig.Authentication.Token + data.SCIMConfig.Authentication.ClientSecret = cfgData.SCIMConfig.Authentication.ClientSecret + } + } + return diags +} diff --git a/internal/services/zero_trust_access_application/plan_modifiers.go b/internal/services/zero_trust_access_application/plan_modifiers.go new file mode 100644 index 0000000000..3e0592931c --- /dev/null +++ b/internal/services/zero_trust_access_application/plan_modifiers.go @@ -0,0 +1,137 @@ +package zero_trust_access_application + +import ( + "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "regexp" + "slices" +) + +var ( + selfHostedAppTypes = []string{"self_hosted", "ssh", "vnc", "rdp"} + saasAppTypes = []string{"saas", "dash_sso"} + appLauncherVisibleAppTypes = []string{"self_hosted", "ssh", "vnc", "rdp", "saas", "bookmark", "infrastructure"} + targetCompatibleAppTypes = []string{"rdp", "infrastructure"} + durationRegex = regexp.MustCompile(`^(?:0|[-+]?(\d+(?:\.\d*)?|\.\d+)(?:ns|us|µs|ms|s|m|h)(?:(\d+(?:\.\d*)?|\.\d+)(?:ns|us|µs|ms|s|m|h))*)$`) +) + +// Sets a specific default value for a computed attribute specific to a set of app types, in case the attribute is unknown. +// If the app type is not in the list, it sets the second default value. +func setDefaultAccordingToAppTypes[T attr.Value](wantAppTypes []string, gotAppType string, planAttribute *T, default1, default2 T) { + if planAttribute == nil || !(*planAttribute).IsUnknown() { + return + } + if slices.Contains(wantAppTypes, gotAppType) { + *planAttribute = default1 + } else { + *planAttribute = default2 + } +} + +// Sets a specific default value for a computed attribute specific to a given app type, in case the attribute is unknown. +// If the app type does not match, it sets the second default value. +func setDefaultAccordingToAppType[T attr.Value](wantAppType string, gotAppType string, planAttribute *T, default1, default2 T) { + setDefaultAccordingToAppTypes([]string{wantAppType}, gotAppType, planAttribute, default1, default2) +} + +func modifyPlanForDomains(ctx context.Context, planApp, stateApp *ZeroTrustAccessApplicationModel) { + appType := planApp.Type.ValueString() + + setDefaultAccordingToAppTypes(selfHostedAppTypes, appType, &planApp.SelfHostedDomains, customfield.UnknownList[types.String](ctx), customfield.NullList[types.String](ctx)) + setDefaultAccordingToAppTypes(selfHostedAppTypes, appType, &planApp.Destinations, customfield.UnknownObjectList[ZeroTrustAccessApplicationDestinationsModel](ctx), customfield.NullObjectList[ZeroTrustAccessApplicationDestinationsModel](ctx)) + setDefaultAccordingToAppTypes(selfHostedAppTypes, appType, &planApp.HTTPOnlyCookieAttribute, types.BoolUnknown(), types.BoolNull()) + + // A self_hosted_app's 'domain', 'self_hosted_domains', and 'destinations' are all tied together in the API. + // changing one, causes the others to change. So we need to tell TF to set the other two to unknown if any of them + // changes from the previous state. + if stateApp == nil || + (!planApp.Domain.IsUnknown() && !planApp.Domain.Equal(stateApp.Domain)) || + (!planApp.SelfHostedDomains.IsUnknown() && !planApp.SelfHostedDomains.Equal(stateApp.SelfHostedDomains)) || + (!planApp.Destinations.IsUnknown() && !planApp.Destinations.Equal(stateApp.Destinations)) { + + if planApp.Domain.IsNull() { + planApp.Domain = types.StringUnknown() + } + if planApp.SelfHostedDomains.IsNull() { + planApp.SelfHostedDomains = customfield.UnknownList[types.String](ctx) + } + if planApp.Destinations.IsNull() { + planApp.Destinations = customfield.UnknownObjectList[ZeroTrustAccessApplicationDestinationsModel](ctx) + } + } else { + // If the domain, self_hosted_domains, and destinations have not changed, we can copy all of them from the state. + planApp.Domain = stateApp.Domain + planApp.SelfHostedDomains = stateApp.SelfHostedDomains + planApp.Destinations = stateApp.Destinations + } +} + +func modifySaasAppNestedObjectPlan(ctx context.Context, planApp *ZeroTrustAccessApplicationModel) diag.Diagnostics { + diags := diag.Diagnostics{} + if planApp.SaaSApp.IsNull() { + return diags + } + var planSaasApp ZeroTrustAccessApplicationSaaSAppModel + diags.Append(planApp.SaaSApp.As(ctx, &planSaasApp, basetypes.ObjectAsOptions{})...) + + oidcType, samlType, currentType := "oidc", "saml", planSaasApp.AuthType.ValueString() + + // These fields are non-existent for non-oidc saas_apps. So we can set them to null and avoid the recurring + // diffs due to unknown computed values. + setDefaultAccordingToAppType(oidcType, currentType, &planSaasApp.ClientID, types.StringUnknown(), types.StringNull()) + setDefaultAccordingToAppType(oidcType, currentType, &planSaasApp.ClientSecret, types.StringUnknown(), types.StringNull()) + setDefaultAccordingToAppType(oidcType, currentType, &planSaasApp.AllowPKCEWithoutClientSecret, types.BoolValue(false), types.BoolNull()) + setDefaultAccordingToAppType(oidcType, currentType, &planSaasApp.AccessTokenLifetime, types.StringValue("5m"), types.StringNull()) + + // These fields are non-existent for non-saml saas_apps. So we can set them to null and avoid the recurring + // diffs due to unknown computed values. + setDefaultAccordingToAppType(samlType, currentType, &planSaasApp.IdPEntityID, types.StringUnknown(), types.StringNull()) + setDefaultAccordingToAppType(samlType, currentType, &planSaasApp.NameIDFormat, types.StringUnknown(), types.StringNull()) + setDefaultAccordingToAppType(samlType, currentType, &planSaasApp.SSOEndpoint, types.StringUnknown(), types.StringNull()) + + planApp.SaaSApp, _ = customfield.NewObject[ZeroTrustAccessApplicationSaaSAppModel](ctx, &planSaasApp) + return diags +} + +func modifyNestedPoliciesPlan(_ context.Context, planApp *ZeroTrustAccessApplicationModel) { + lastKnownPrecedence := 0 + for i := range *planApp.Policies { + if (*planApp.Policies)[i].Precedence.IsUnknown() { + (*planApp.Policies)[i].Precedence = types.Int64Value(int64(lastKnownPrecedence + 1)) + } + lastKnownPrecedence = int((*planApp.Policies)[i].Precedence.ValueInt64()) + } +} + +func modifyPlan(ctx context.Context, req resource.ModifyPlanRequest, res *resource.ModifyPlanResponse) { + var planApp, stateApp *ZeroTrustAccessApplicationModel + res.Diagnostics.Append(req.Plan.Get(ctx, &planApp)...) + res.Diagnostics.Append(req.State.Get(ctx, &stateApp)...) + if res.Diagnostics.HasError() || planApp == nil { + return + } + + modifyPlanForDomains(ctx, planApp, stateApp) + + appType := planApp.Type.ValueString() + + // Add default values for some app type specific attributes + setDefaultAccordingToAppTypes(selfHostedAppTypes, appType, &planApp.HTTPOnlyCookieAttribute, types.BoolValue(true), types.BoolNull()) + setDefaultAccordingToAppTypes(appLauncherVisibleAppTypes, appType, &planApp.AppLauncherVisible, types.BoolValue(true), types.BoolNull()) + setDefaultAccordingToAppType("app_launcher", appType, &planApp.SkipAppLauncherLoginPage, types.BoolValue(false), types.BoolNull()) + + if appType == "saas" { + res.Diagnostics.Append(modifySaasAppNestedObjectPlan(ctx, planApp)...) + } + + if planApp.Policies != nil { + modifyNestedPoliciesPlan(ctx, planApp) + } + + res.Plan.Set(ctx, &planApp) +} diff --git a/internal/services/zero_trust_access_application/resource.go b/internal/services/zero_trust_access_application/resource.go index da74f2fb27..62dd826e5c 100644 --- a/internal/services/zero_trust_access_application/resource.go +++ b/internal/services/zero_trust_access_application/resource.go @@ -5,9 +5,6 @@ package zero_trust_access_application import ( "context" "fmt" - "io" - "net/http" - "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/cloudflare-go/v4/zero_trust" @@ -16,6 +13,8 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" + "io" + "net/http" ) // Ensure provider defined types fully satisfy framework interfaces. @@ -64,11 +63,17 @@ func (r *ZeroTrustAccessApplicationResource) Create(ctx context.Context, req res return } + resp.Diagnostics.Append(loadConfigSensitiveValuesForWriting(ctx, data, &req.Config)...) + if resp.Diagnostics.HasError() { + return + } + dataBytes, err := data.MarshalJSON() if err != nil { resp.Diagnostics.AddError("failed to serialize http request", err.Error()) return } + res := new(http.Response) env := ZeroTrustAccessApplicationResultEnvelope{*data} params := zero_trust.AccessApplicationNewParams{} @@ -118,6 +123,11 @@ func (r *ZeroTrustAccessApplicationResource) Update(ctx context.Context, req res return } + resp.Diagnostics.Append(loadConfigSensitiveValuesForWriting(ctx, data, &req.Config)...) + if resp.Diagnostics.HasError() { + return + } + dataBytes, err := data.MarshalJSONForUpdate(*state) if err != nil { resp.Diagnostics.AddError("failed to serialize http request", err.Error()) @@ -153,6 +163,14 @@ func (r *ZeroTrustAccessApplicationResource) Update(ctx context.Context, req res } data = &env.Result + var planData *ZeroTrustAccessApplicationModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...) + if resp.Diagnostics.HasError() { + return + } + + normalizeReadZeroTrustApplicationAPIData(ctx, data, planData) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -199,6 +217,14 @@ func (r *ZeroTrustAccessApplicationResource) Read(ctx context.Context, req resou } data = &env.Result + var stateData *ZeroTrustAccessApplicationModel + resp.Diagnostics.Append(req.State.Get(ctx, &stateData)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(normalizeReadZeroTrustApplicationAPIData(ctx, data, stateData)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -287,6 +313,6 @@ func (r *ZeroTrustAccessApplicationResource) ImportState(ctx context.Context, re resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func (r *ZeroTrustAccessApplicationResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { - +func (r *ZeroTrustAccessApplicationResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, res *resource.ModifyPlanResponse) { + modifyPlan(ctx, req, res) } diff --git a/internal/services/zero_trust_access_application/resource_test.go b/internal/services/zero_trust_access_application/resource_test.go index 775f5a4060..95673fe179 100644 --- a/internal/services/zero_trust_access_application/resource_test.go +++ b/internal/services/zero_trust_access_application/resource_test.go @@ -102,6 +102,11 @@ func TestAccCloudflareAccessApplication_BasicZone(t *testing.T) { resource.TestCheckResourceAttr(name, "auto_redirect_to_identity", "false"), ), }, + { + // Ensures no diff on second plan + Config: testAccCloudflareAccessApplicationConfigBasic(rnd, domain, cloudflare.ZoneIdentifier(zoneID)), + PlanOnly: true, + }, }, }) } @@ -131,6 +136,11 @@ func TestAccCloudflareAccessApplication_BasicAccount(t *testing.T) { resource.TestCheckResourceAttr(name, "auto_redirect_to_identity", "false"), ), }, + { + // Ensures no diff on second plan + Config: testAccCloudflareAccessApplicationConfigBasic(rnd, domain, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, }, }) } @@ -171,6 +181,11 @@ func TestAccCloudflareAccessApplication_WithSCIMConfigHttpBasic(t *testing.T) { resource.TestCheckResourceAttr(name, "scim_config.mappings.0.operations.delete", "true"), ), }, + { + // Ensures no diff on second plan + Config: testAccCloudflareAccessApplicationSCIMConfigValidHttpBasic(rnd, accountID, domain), + PlanOnly: true, + }, }, }) } @@ -211,6 +226,11 @@ func TestAccCloudflareAccessApplication_UpdateSCIMConfig(t *testing.T) { resource.TestCheckResourceAttr(name, "scim_config.mappings.0.operations.delete", "true"), ), }, + { + // Ensures no diff on second plan + Config: testAccCloudflareAccessApplicationSCIMConfigValidHttpBasic(rnd, accountID, domain), + PlanOnly: true, + }, { Config: testAccCloudflareAccessApplicationSCIMConfigValidOAuthBearerTokenNoMappings(rnd, accountID, domain), Check: resource.ComposeTestCheckFunc( @@ -228,6 +248,11 @@ func TestAccCloudflareAccessApplication_UpdateSCIMConfig(t *testing.T) { resource.TestCheckResourceAttr(name, "scim_config.mappings.#", "0"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationSCIMConfigValidOAuthBearerTokenNoMappings(rnd, accountID, domain), + PlanOnly: true, + }, }, }) } @@ -303,6 +328,11 @@ func TestAccCloudflareAccessApplication_WithSCIMConfigOAuthBearerToken(t *testin resource.TestCheckResourceAttr(name, "scim_config.mappings.0.operations.delete", "true"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationSCIMConfigValidOAuthBearerToken(rnd, accountID, domain), + PlanOnly: true, + }, }, }) } @@ -347,6 +377,11 @@ func TestAccCloudflareAccessApplication_WithSCIMConfigOAuth2(t *testing.T) { resource.TestCheckResourceAttr(name, "scim_config.mappings.0.operations.delete", "true"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationSCIMConfigValidOAuth2(rnd, accountID, domain), + PlanOnly: true, + }, }, }) } @@ -394,6 +429,11 @@ func TestAccCloudflareAccessApplication_WithCORS(t *testing.T) { resource.TestCheckResourceAttr(name, "auto_redirect_to_identity", "false"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithCORS(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -438,6 +478,11 @@ func TestAccCloudflareAccessApplication_WithSAMLSaas(t *testing.T) { resource.TestCheckResourceAttr(name, "saas_app.custom_attributes.1.required", "true"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithSAMLSaas(rnd, accountID), + PlanOnly: true, + }, }, }) } @@ -481,13 +526,18 @@ func TestAccCloudflareAccessApplication_WithSAMLSaas_Import(t *testing.T) { Config: testAccCloudflareAccessApplicationConfigWithSAMLSaas(rnd, accountID), Check: checkFn, }, - // { - // ImportState: true, - // ImportStateVerify: true, - // ResourceName: name, - // ImportStateIdPrefix: fmt.Sprintf("%s/", accountID), - // Check: checkFn, - // }, + { + ImportState: true, + ImportStateVerify: true, + ResourceName: name, + ImportStateIdPrefix: fmt.Sprintf("accounts/%s/", accountID), + Check: checkFn, + }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithSAMLSaas(rnd, accountID), + PlanOnly: true, + }, }, }) } @@ -536,6 +586,11 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas(t *testing.T) { resource.TestCheckResourceAttrSet(name, "saas_app.public_key"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithOIDCSaas(rnd, accountID), + PlanOnly: true, + }, }, }) } @@ -585,14 +640,19 @@ func TestAccCloudflareAccessApplication_WithOIDCSaas_Import(t *testing.T) { Config: testAccCloudflareAccessApplicationConfigWithOIDCSaas(rnd, accountID), Check: checkFn, }, - // { - // ImportState: true, - // ImportStateVerify: true, - // ImportStateVerifyIgnore: []string{"saas_app.client_secret"}, - // ResourceName: name, - // ImportStateIdPrefix: fmt.Sprintf("%s/", accountID), - // Check: checkFn, - // }, + { + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"saas_app.client_secret", "saas_app.allow_pkce_without_client_secret"}, + ResourceName: name, + ImportStateIdPrefix: fmt.Sprintf("accounts/%s/", accountID), + Check: checkFn, + }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithOIDCSaas(rnd, accountID), + PlanOnly: true, + }, }, }) } @@ -620,6 +680,11 @@ func TestAccCloudflareAccessApplication_WithAutoRedirectToIdentity(t *testing.T) resource.TestCheckResourceAttr(name, "allowed_idps.#", "1"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithAutoRedirectToIdentity(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -646,6 +711,11 @@ func TestAccCloudflareAccessApplication_WithEnableBindingCookie(t *testing.T) { resource.TestCheckResourceAttr(name, "enable_binding_cookie", "true"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithEnableBindingCookie(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -674,11 +744,16 @@ func TestAccCloudflareAccessApplication_WithCustomDenyFields(t *testing.T) { resource.TestCheckResourceAttr(name, "custom_non_identity_deny_url", "https://www.blocked.com"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithCustomDenyFields(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } -func TestAccCloudflareAccessApplication_WithADefinedIdps(t *testing.T) { +func TestAccCloudflareAccessApplication_WithADefinedIdp(t *testing.T) { rnd := utils.GenerateRandomResourceName() name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd) @@ -701,6 +776,11 @@ func TestAccCloudflareAccessApplication_WithADefinedIdps(t *testing.T) { resource.TestCheckResourceAttr(name, "allowed_idps.#", "1"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithADefinedIdp(rnd, zoneID, domain, accountID), + PlanOnly: true, + }, }, }) } @@ -723,6 +803,11 @@ func TestAccCloudflareAccessApplication_WithMultipleIdpsReordered(t *testing.T) { Config: testAccCloudflareAccessApplicationConfigWithMultipleIdps(rnd, zoneID, domain, accountID, idp2, idp1), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithMultipleIdps(rnd, zoneID, domain, accountID, idp2, idp1), + PlanOnly: true, + }, }, }) } @@ -749,6 +834,11 @@ func TestAccCloudflareAccessApplication_WithHttpOnlyCookieAttribute(t *testing.T resource.TestCheckResourceAttr(name, "http_only_cookie_attribute", "true"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithHTTPOnlyCookieAttribute(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -775,6 +865,11 @@ func TestAccCloudflareAccessApplication_WithHTTPOnlyCookieAttributeSetToFalse(t resource.TestCheckResourceAttr(name, "http_only_cookie_attribute", "false"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithHTTPOnlyCookieAttributeSetToFalse(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -801,6 +896,11 @@ func TestAccCloudflareAccessApplication_WithSameSiteCookieAttribute(t *testing.T resource.TestCheckResourceAttr(name, "same_site_cookie_attribute", "strict"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigSameSiteCookieAttribute(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -827,6 +927,11 @@ func TestAccCloudflareAccessApplication_WithLogoURL(t *testing.T) { resource.TestCheckResourceAttr(name, "logo_url", "https://www.cloudflare.com/img/logo-web-badges/cf-logo-on-white-bg.svg"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigLogoURL(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -853,6 +958,11 @@ func TestAccCloudflareAccessApplication_WithSkipInterstitial(t *testing.T) { resource.TestCheckResourceAttr(name, "skip_interstitial", "true"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigSkipInterstitial(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -879,6 +989,11 @@ func TestAccCloudflareAccessApplication_WithAppLauncherVisible(t *testing.T) { resource.TestCheckResourceAttr(name, "app_launcher_visible", "true"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithAppLauncherVisible(rnd, zoneID, domain), + PlanOnly: true, + }, }, }) } @@ -908,6 +1023,11 @@ func TestAccCloudflareAccessApplication_WithSelfHostedDomains(t *testing.T) { resource.TestCheckResourceAttr(name, "auto_redirect_to_identity", "false"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationWithSelfHostedDomains(rnd, domain, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, }, }) } @@ -935,6 +1055,41 @@ func TestAccCloudflareAccessApplication_WithDefinedTags(t *testing.T) { resource.TestCheckResourceAttr(name, "tags.#", "1"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithADefinedTag(rnd, zoneID, domain, accountID), + PlanOnly: true, + }, + }, + }) +} + +func TestAccCloudflareAccessApplication_WithLegacyPolicies(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := fmt.Sprintf("cloudflare_zero_trust_access_application.%s", rnd) + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.TestAccPreCheck(t) + acctest.TestAccPreCheck_AccountID(t) + }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + CheckDestroy: testAccCheckCloudflareAccessApplicationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareAccessApplicationConfigWithLegacyPolicies(rnd, domain, accountID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "domain", fmt.Sprintf("%s.%s", rnd, domain)), + resource.TestCheckResourceAttr(name, "type", "self_hosted"), + resource.TestCheckResourceAttr(name, "policies.#", "3"), + ), + }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithLegacyPolicies(rnd, domain, accountID), + PlanOnly: true, + }, }, }) } @@ -960,6 +1115,11 @@ func TestAccCloudflareAccessApplication_WithReusablePolicies(t *testing.T) { resource.TestCheckResourceAttr(name, "policies.#", "2"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessApplicationConfigWithReusablePolicies(rnd, domain, accountID), + PlanOnly: true, + }, }, }) } @@ -976,7 +1136,8 @@ func TestAccCloudflareAccessApplication_WithAppLauncherCustomization(t *testing. ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, CheckDestroy: testAccCheckCloudflareAccessApplicationDestroy, Steps: []resource.TestStep{ - {Config: testAccessApplicationWithAppLauncherCustomizationFields(rnd, accountID), + { + Config: testAccessApplicationWithAppLauncherCustomizationFields(rnd, accountID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), resource.TestCheckResourceAttr(name, "type", "app_launcher"), @@ -993,6 +1154,11 @@ func TestAccCloudflareAccessApplication_WithAppLauncherCustomization(t *testing. resource.TestCheckResourceAttr(name, "footer_links.0.url", "https://www.cloudflare.com"), ), }, + { + // Ensures no diff on last plan + Config: testAccessApplicationWithAppLauncherCustomizationFields(rnd, accountID), + PlanOnly: true, + }, }, }) } @@ -1068,7 +1234,8 @@ func testAccCloudflareAccessApplicationWithSelfHostedDomains(rnd string, domain func testAccCheckCloudflareAccessApplicationDestroy(s *terraform.State) error { client, clientErr := acctest.SharedV1Client() // TODO(terraform): replace with SharedV2Clent if clientErr != nil { - tflog.Error(context.TODO(), fmt.Sprintf("failed to create Cloudflare client: %s", clientErr)) + tflog.Error(context.TODO(), fmt.Sprintf("failed to create Cloudflare client for destroy check: %s", clientErr)) + return clientErr } for _, rs := range s.RootModule().Resources { @@ -1124,111 +1291,113 @@ func TestAccCloudflareAccessApplicationWithZoneID(t *testing.T) { resource.TestCheckResourceAttr(name, consts.ZoneIDSchemaKey, zoneID), ), }, + { + // Ensures no diff on last plan + Config: testAccessApplicationWithZoneIDUpdated(rnd, zone, zoneID), + PlanOnly: true, + }, }, }) } -// TODO: tighten up validation here and re-enable. -// -// func TestAccCloudflareAccessApplicationWithMissingCORSMethods(t *testing.T) { -// rnd := utils.GenerateRandomResourceName() -// zone := os.Getenv("CLOUDFLARE_DOMAIN") -// zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") - -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { -// acctest.TestAccPreCheck(t) -// acctest.TestAccPreCheck_AccountID(t) -// }, -// ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, -// Steps: []resource.TestStep{ -// { -// Config: testAccessApplicationWithMissingCORSMethods(rnd, zone, zoneID), -// ExpectError: regexp.MustCompile("must set allowed_methods or allow_all_methods"), -// }, -// }, -// }) -// } - -// func TestAccCloudflareAccessApplicationWithMissingCORSOrigins(t *testing.T) { -// rnd := utils.GenerateRandomResourceName() -// zone := os.Getenv("CLOUDFLARE_DOMAIN") -// zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") - -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { -// acctest.TestAccPreCheck(t) -// acctest.TestAccPreCheck_AccountID(t) -// }, -// ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, -// Steps: []resource.TestStep{ -// { -// Config: testAccessApplicationWithMissingCORSOrigins(rnd, zone, zoneID), -// ExpectError: regexp.MustCompile("must set allowed_origins or allow_all_origins"), -// }, -// }, -// }) -// } - -// func TestAccCloudflareAccessApplicationWithInvalidSessionDuration(t *testing.T) { -// rnd := utils.GenerateRandomResourceName() -// zone := os.Getenv("CLOUDFLARE_DOMAIN") -// zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") - -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { -// acctest.TestAccPreCheck(t) -// acctest.TestAccPreCheck_AccountID(t) -// }, -// ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, -// Steps: []resource.TestStep{ -// { -// Config: testAccessApplicationWithInvalidSessionDuration(rnd, zone, zoneID), -// ExpectError: regexp.MustCompile(regexp.QuoteMeta(`"session_duration" only supports "ns", "us" (or "µs"), "ms", "s", "m", or "h" as valid units`)), -// }, -// }, -// }) -// } - -// func TestAccCloudflareAccessApplicationMisconfiguredCORSCredentialsAllowingAllOrigins(t *testing.T) { -// rnd := utils.GenerateRandomResourceName() -// zone := os.Getenv("CLOUDFLARE_DOMAIN") -// zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") - -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { -// acctest.TestAccPreCheck(t) -// acctest.TestAccPreCheck_AccountID(t) -// }, -// ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, -// Steps: []resource.TestStep{ -// { -// Config: testAccessApplicationMisconfiguredCORSAllowAllOriginsWithCredentials(rnd, zone, zoneID), -// ExpectError: regexp.MustCompile(regexp.QuoteMeta(`CORS credentials are not permitted when all origins are allowed`)), -// }, -// }, -// }) -// } - -// func TestAccCloudflareAccessApplicationMisconfiguredCORSCredentialsAllowingWildcardOrigins(t *testing.T) { -// rnd := utils.GenerateRandomResourceName() -// zone := os.Getenv("CLOUDFLARE_DOMAIN") -// zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") - -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { -// acctest.TestAccPreCheck(t) -// acctest.TestAccPreCheck_AccountID(t) -// }, -// ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, -// Steps: []resource.TestStep{ -// { -// Config: testAccessApplicationMisconfiguredCORSAllowWildcardOriginWithCredentials(rnd, zone, zoneID), -// ExpectError: regexp.MustCompile(regexp.QuoteMeta(`CORS credentials are not permitted when all origins are allowed`)), -// }, -// }, -// }) -// } +func TestAccCloudflareAccessApplicationWithMissingCORSMethods(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + zone := os.Getenv("CLOUDFLARE_DOMAIN") + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.TestAccPreCheck(t) + acctest.TestAccPreCheck_AccountID(t) + }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccessApplicationWithMissingCORSMethods(rnd, zone, zoneID), + ExpectError: regexp.MustCompile(`No attribute specified when one \(and only one\) of\s+\[cors_headers\.allow_all_methods\.<\.allowed_methods\] is required`), + }, + }, + }) +} + +func TestAccCloudflareAccessApplicationWithMissingCORSOrigins(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + zone := os.Getenv("CLOUDFLARE_DOMAIN") + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.TestAccPreCheck(t) + acctest.TestAccPreCheck_AccountID(t) + }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccessApplicationWithMissingCORSOrigins(rnd, zone, zoneID), + ExpectError: regexp.MustCompile(`No attribute specified when one \(and only one\) of\s+\[cors_headers\.allow_all_origins\.<\.allowed_origins\] is required`), + }, + }, + }) +} + +func TestAccCloudflareAccessApplicationWithInvalidSessionDuration(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + zone := os.Getenv("CLOUDFLARE_DOMAIN") + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.TestAccPreCheck(t) + acctest.TestAccPreCheck_AccountID(t) + }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccessApplicationWithInvalidSessionDuration(rnd, zone, zoneID), + ExpectError: regexp.MustCompile(`"session_duration" only supports .*`), + }, + }, + }) +} + +func TestAccCloudflareAccessApplicationMisconfiguredCORSCredentialsAllowingAllOrigins(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + zone := os.Getenv("CLOUDFLARE_DOMAIN") + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.TestAccPreCheck(t) + acctest.TestAccPreCheck_AccountID(t) + }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccessApplicationMisconfiguredCORSAllowAllOriginsWithCredentials(rnd, zone, zoneID), + ExpectError: regexp.MustCompile(`Attribute "cors_headers.allow_all_origins" cannot be specified when\s+"cors_headers.allow_credentials" is specified`), + }, + }, + }) +} + +func TestAccCloudflareAccessApplicationWithInvalidSaas(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + accoundID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.TestAccPreCheck(t) + acctest.TestAccPreCheck_AccountID(t) + }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccessApplicationWithInvalidSaas(rnd, accoundID), + ExpectError: regexp.MustCompile("\"saas_app\" has to be set if \"type\" is one of: \"saas\", \"dash_sso\""), + }, + }, + }) +} func testAccessApplicationWithZoneID(resourceID, zone, zoneID string) string { return acctest.LoadTestCase("accessapplicationwithzoneid.tf", resourceID, zone, zoneID) @@ -1254,10 +1423,6 @@ func testAccessApplicationMisconfiguredCORSAllowAllOriginsWithCredentials(resour return acctest.LoadTestCase("accessapplicationmisconfiguredcorsallowalloriginswithcredentials.tf", resourceID, zone, zoneID) } -func testAccessApplicationMisconfiguredCORSAllowWildcardOriginWithCredentials(resourceID, zone, zoneID string) string { - return acctest.LoadTestCase("accessapplicationmisconfiguredcorsallowwildcardoriginwithcredentials.tf", resourceID, zone, zoneID) -} - func testAccCloudflareAccessApplicationConfigWithADefinedTag(rnd, zoneID, domain string, accountID string) string { return acctest.LoadTestCase("accessapplicationconfigwithadefinedtag.tf", rnd, zoneID, domain, accountID) } @@ -1282,10 +1447,6 @@ func testAccCloudflareAccessApplicationSCIMConfigOAuth2MissingRequired(rnd, acco return acctest.LoadTestCase("accessapplicationscimconfigoauth2missingrequired.tf", rnd, accountID, domain) } -func testAccCloudflareAccessApplicationSCIMConfigAuthenticationInvalid(rnd, accountID, domain string) string { - return acctest.LoadTestCase("accessapplicationscimconfigauthenticationinvalid.tf", rnd, accountID, domain) -} - func testAccCloudflareAccessApplicationSCIMConfigHttpBasicMissingRequired(rnd, accountID, domain string) string { return acctest.LoadTestCase("accessapplicationscimconfighttpbasicmissingrequired.tf", rnd, accountID, domain) } @@ -1294,6 +1455,14 @@ func testAccCloudflareAccessApplicationSCIMConfigInvalidMappingSchema(rnd, accou return acctest.LoadTestCase("accessapplicationscimconfiginvalidmappingschema.tf", rnd, accountID, domain) } +func testAccCloudflareAccessApplicationConfigWithLegacyPolicies(rnd, domain string, accountID string) string { + return acctest.LoadTestCase("accessapplicationconfigwithlegacypolicies.tf", rnd, domain, accountID) +} + func testAccCloudflareAccessApplicationConfigWithReusablePolicies(rnd, domain string, accountID string) string { return acctest.LoadTestCase("accessapplicationconfigwithreusablepolicies.tf", rnd, domain, accountID) } + +func testAccessApplicationWithInvalidSaas(resourceID, accountID string) string { + return acctest.LoadTestCase("accessapplicationconfigwithinvalidsaas.tf", resourceID, accountID) +} diff --git a/internal/services/zero_trust_access_application/schema.go b/internal/services/zero_trust_access_application/schema.go index a9fbd4cb81..622979df55 100644 --- a/internal/services/zero_trust_access_application/schema.go +++ b/internal/services/zero_trust_access_application/schema.go @@ -4,15 +4,18 @@ package zero_trust_access_application import ( "context" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customvalidator" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" @@ -47,14 +50,23 @@ func ResourceSchema(ctx context.Context) schema.Schema { "allow_iframe": schema.BoolAttribute{ Description: "Enables loading application content in an iFrame.", Optional: true, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "app_launcher_logo_url": schema.StringAttribute{ Description: "The image URL of the logo shown in the App Launcher header.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "app_launcher"), + }, }, "bg_color": schema.StringAttribute{ Description: "The background color of the App Launcher page.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "app_launcher"), + }, }, "custom_deny_message": schema.StringAttribute{ Description: "The custom error message shown to a user when they are denied access to the application.", @@ -71,38 +83,59 @@ func ResourceSchema(ctx context.Context) schema.Schema { "domain": schema.StringAttribute{ Description: "The primary hostname and path secured by Access. This domain will be displayed if the app is visible in the App Launcher.", Optional: true, + Computed: true, }, "header_bg_color": schema.StringAttribute{ Description: "The background color of the App Launcher header.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "app_launcher"), + }, }, "logo_url": schema.StringAttribute{ Description: "The image URL for the logo shown in the App Launcher dashboard.", Optional: true, }, "name": schema.StringAttribute{ - Description: "The name of the application.", - Optional: true, + Description: "The name of the application.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "options_preflight_bypass": schema.BoolAttribute{ Description: "Allows options preflight requests to bypass Access authentication and go directly to the origin. Cannot turn on if cors_headers is set.", Optional: true, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "read_service_tokens_from_header": schema.StringAttribute{ Description: "Allows matching Access Service Tokens passed HTTP in a single header with this name.\nThis works as an alternative to the (CF-Access-Client-Id, CF-Access-Client-Secret) pair of headers.\nThe header value will be interpreted as a json object similar to: \n {\n \"cf-access-client-id\": \"88bf3b6d86161464f6509f7219099e57.access.example.com\",\n \"cf-access-client-secret\": \"bdd31cbc4dec990953e39163fbbb194c93313ca9f0a6e420346af9d326b1d2a5\"\n }", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "same_site_cookie_attribute": schema.StringAttribute{ Description: "Sets the SameSite cookie setting, which provides increased security against CSRF attacks.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "service_auth_401_redirect": schema.BoolAttribute{ Description: "Returns a 401 status code when the request is blocked by a Service Auth policy.", Optional: true, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "skip_interstitial": schema.BoolAttribute{ Description: "Enables automatic authentication through cloudflared.", Optional: true, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "type": schema.StringAttribute{ Description: "The application type.\nAvailable values: \"self_hosted\", \"saas\", \"ssh\", \"vnc\", \"app_launcher\", \"warp\", \"biso\", \"bookmark\", \"dash_sso\", \"infrastructure\", \"rdp\".", @@ -123,7 +156,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { ), }, }, - "allowed_idps": schema.ListAttribute{ + "allowed_idps": schema.SetAttribute{ Description: "The identity providers your users can select when connecting to this application. Defaults to all IdPs configured in your account.", Optional: true, ElementType: types.StringType, @@ -135,33 +168,48 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "cors_headers": schema.SingleNestedAttribute{ Optional: true, + Validators: []validator.Object{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, Attributes: map[string]schema.Attribute{ "allow_all_headers": schema.BoolAttribute{ Description: "Allows all HTTP request headers.", Optional: true, + Validators: []validator.Bool{ + boolvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("allowed_headers")), + }, }, "allow_all_methods": schema.BoolAttribute{ Description: "Allows all HTTP request methods.", Optional: true, + Validators: []validator.Bool{ + boolvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("allowed_methods")), + }, }, "allow_all_origins": schema.BoolAttribute{ Description: "Allows all origins.", Optional: true, + Validators: []validator.Bool{ + boolvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("allowed_origins")), + }, }, "allow_credentials": schema.BoolAttribute{ Description: "When set to `true`, includes credentials (cookies, authorization headers, or TLS client certificates) with requests.", Optional: true, + Validators: []validator.Bool{ + boolvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("allow_all_origins")), + }, }, - "allowed_headers": schema.ListAttribute{ + "allowed_headers": schema.SetAttribute{ Description: "Allowed HTTP request headers.", Optional: true, ElementType: types.StringType, }, - "allowed_methods": schema.ListAttribute{ + "allowed_methods": schema.SetAttribute{ Description: "Allowed HTTP request methods.", Optional: true, - Validators: []validator.List{ - listvalidator.ValueStringsAre( + Validators: []validator.Set{ + setvalidator.ValueStringsAre( stringvalidator.OneOfCaseInsensitive( "GET", "POST", @@ -177,7 +225,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, ElementType: types.StringType, }, - "allowed_origins": schema.ListAttribute{ + "allowed_origins": schema.SetAttribute{ Description: "Allowed origins.", Optional: true, ElementType: types.StringType, @@ -194,6 +242,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { "footer_links": schema.ListNestedAttribute{ Description: "The links in the App Launcher footer.", Optional: true, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "app_launcher"), + }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "name": schema.StringAttribute{ @@ -226,6 +277,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "password": schema.StringAttribute{ Description: "Password used to authenticate with the remote SCIM service.", Optional: true, + Sensitive: true, }, "scheme": schema.StringAttribute{ Description: "The authentication scheme to use when making SCIM requests to this application.\nAvailable values: \"httpbasic\", \"oauthbearertoken\", \"oauth2\", \"access_service_token\".", @@ -333,6 +385,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "target_criteria": schema.ListNestedAttribute{ Optional: true, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), targetCompatibleAppTypes...), + }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "port": schema.Int64Attribute{ @@ -360,64 +415,85 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Displays the application in the App Launcher.", Computed: true, Optional: true, - Default: booldefault.StaticBool(true), + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), appLauncherVisibleAppTypes...), + }, }, "auto_redirect_to_identity": schema.BoolAttribute{ Description: "When set to `true`, users skip the identity provider selection step during login. You must specify only one identity provider in allowed_idps.", - Computed: true, Optional: true, - Default: booldefault.StaticBool(false), }, "enable_binding_cookie": schema.BoolAttribute{ Description: "Enables the binding cookie, which increases security against compromised authorization tokens and CSRF attacks.", - Computed: true, Optional: true, - Default: booldefault.StaticBool(false), + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "http_only_cookie_attribute": schema.BoolAttribute{ Description: "Enables the HttpOnly cookie attribute, which increases security against XSS attacks.", Computed: true, Optional: true, - Default: booldefault.StaticBool(true), + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "path_cookie_attribute": schema.BoolAttribute{ Description: "Enables cookie paths to scope an application's JWT to the application path. If disabled, the JWT will scope to the hostname by default", - Computed: true, Optional: true, - Default: booldefault.StaticBool(false), + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + }, }, "session_duration": schema.StringAttribute{ Description: "The amount of time that tokens issued for this application will be valid. Must be in the format `300ms` or `2h45m`. Valid time units are: ns, us (or µs), ms, s, m, h. Note: unsupported for infrastructure type applications.", Computed: true, Optional: true, Default: stringdefault.StaticString("24h"), + Validators: []validator.String{ + stringvalidator.RegexMatches(durationRegex, `"session_duration" only supports "ns", "us" (or "µs"), "ms", "s", "m", or "h" as valid units`), + }, }, "skip_app_launcher_login_page": schema.BoolAttribute{ Description: "Determines when to skip the App Launcher landing page.", - Computed: true, Optional: true, - Default: booldefault.StaticBool(false), + Computed: true, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "app_launcher"), + }, }, "self_hosted_domains": schema.ListAttribute{ Description: "List of public domains that Access will secure. This field is deprecated in favor of `destinations` and will be supported until **November 21, 2025.** If `destinations` are provided, then `self_hosted_domains` will be ignored.", - Computed: true, Optional: true, + Computed: true, DeprecationMessage: "This attribute is deprecated.", CustomType: customfield.NewListType[types.String](ctx), ElementType: types.StringType, + + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + listvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("destinations"), + }...), + }, }, "tags": schema.ListAttribute{ Description: "The tags you want assigned to an application. Tags are used to filter applications in the App Launcher dashboard.", - Computed: true, - Optional: true, CustomType: customfield.NewListType[types.String](ctx), + Optional: true, ElementType: types.StringType, }, "destinations": schema.ListNestedAttribute{ Description: "List of destinations secured by Access. This supersedes `self_hosted_domains` to allow for more flexibility in defining different types of domains. If `destinations` are provided, then `self_hosted_domains` will be ignored.", - Computed: true, Optional: true, + Computed: true, CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationDestinationsModel](ctx), + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), selfHostedAppTypes...), + listvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("self_hosted_domains"), + }...), + }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "type": schema.StringAttribute{ @@ -459,9 +535,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "landing_page_design": schema.SingleNestedAttribute{ Description: "The design of the App Launcher landing page shown to users when they log in.", - Computed: true, Optional: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationLandingPageDesignModel](ctx), + Validators: []validator.Object{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "app_launcher"), + }, Attributes: map[string]schema.Attribute{ "button_color": schema.StringAttribute{ Description: "The background color of the log in button on the landing page.", @@ -489,18 +567,20 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "policies": schema.ListNestedAttribute{ Description: "The policies that Access applies to the application, in ascending order of precedence. Items can reference existing policies or create new policies exclusive to the application.", - Computed: true, Optional: true, - CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ Description: "The UUID of the policy", Optional: true, + Validators: []validator.String{ + stringvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("include")), + }, }, "precedence": schema.Int64Attribute{ Description: "The order of execution for this policy. Must be unique for each policy within an app.", Optional: true, + Computed: true, }, "decision": schema.StringAttribute{ Description: "The action Access will take if a user matches this policy. Infrastructure application policies can only use the Allow action.\nAvailable values: \"allow\", \"deny\", \"non_identity\", \"bypass\".", @@ -512,13 +592,16 @@ func ResourceSchema(ctx context.Context) schema.Schema { "non_identity", "bypass", ), + stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("include")), }, }, "include": schema.ListNestedAttribute{ Description: "Rules evaluated with an OR logical operator. A user needs to meet only one of the Include rules.", - Computed: true, Optional: true, - CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesIncludeModel](ctx), + Validators: []validator.List{ + listvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("decision")), + }, + CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesIncludeModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ @@ -752,10 +835,16 @@ func ResourceSchema(ctx context.Context) schema.Schema { "name": schema.StringAttribute{ Description: "The name of the Access policy.", Optional: true, + Validators: []validator.String{ + stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("include")), + }, }, "connection_rules": schema.SingleNestedAttribute{ Description: "The rules that define how users may connect to the targets secured by your application.", Optional: true, + Validators: []validator.Object{ + objectvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("include")), + }, Attributes: map[string]schema.Attribute{ "ssh": schema.SingleNestedAttribute{ Description: "The SSH-specific rules that define how users may connect to the targets secured by your application.", @@ -776,9 +865,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "exclude": schema.ListNestedAttribute{ Description: "Rules evaluated with a NOT logical operator. To match the policy, a user cannot meet any of the Exclude rules.", - Computed: true, Optional: true, - CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesExcludeModel](ctx), + Validators: []validator.List{ + listvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("include")), + }, + CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesExcludeModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ @@ -1011,9 +1102,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "require": schema.ListNestedAttribute{ Description: "Rules evaluated with an AND logical operator. To match the policy, a user must meet all of the Require rules.", - Computed: true, Optional: true, - CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesRequireModel](ctx), + Validators: []validator.List{ + listvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("include")), + }, + CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesRequireModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ @@ -1248,14 +1341,18 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, "saas_app": schema.SingleNestedAttribute{ - Computed: true, Optional: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationSaaSAppModel](ctx), + Validators: []validator.Object{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), saasAppTypes...), + customvalidator.RequiredWhenOtherStringIsOneOf(path.MatchRoot("type"), saasAppTypes...), + }, Attributes: map[string]schema.Attribute{ "auth_type": schema.StringAttribute{ - Computed: true, Description: "Optional identifier indicating the authentication protocol used for the saas app. Required for OIDC. Default if unset is \"saml\"\nAvailable values: \"saml\", \"oidc\".", Optional: true, + Computed: true, + Default: stringdefault.StaticString("saml"), Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive("saml", "oidc"), }, @@ -1263,13 +1360,22 @@ func ResourceSchema(ctx context.Context) schema.Schema { "consumer_service_url": schema.StringAttribute{ Description: "The service provider's endpoint that is responsible for receiving and parsing a SAML assertion.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, }, "created_at": schema.StringAttribute{ Computed: true, CustomType: timetypes.RFC3339Type{}, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "custom_attributes": schema.ListNestedAttribute{ Optional: true, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "friendly_name": schema.StringAttribute{ @@ -1326,40 +1432,71 @@ func ResourceSchema(ctx context.Context) schema.Schema { "default_relay_state": schema.StringAttribute{ Description: "The URL that the user will be redirected to after a successful login for IDP initiated logins.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, }, "idp_entity_id": schema.StringAttribute{ Description: "The unique identifier for your SaaS application.", Computed: true, Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "name_id_format": schema.StringAttribute{ Description: "The format of the name identifier sent to the SaaS application.\nAvailable values: \"id\", \"email\".", Optional: true, + Computed: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive("id", "email"), + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, "name_id_transform_jsonata": schema.StringAttribute{ Description: "A [JSONata](https://jsonata.org/) expression that transforms an application's user identities into a NameID value for its SAML assertion. This expression should evaluate to a singular string. The output of this expression can override the `name_id_format` setting.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, }, "public_key": schema.StringAttribute{ Description: "The Access public certificate that will be used to verify your identity.", Computed: true, - Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "saml_attribute_transform_jsonata": schema.StringAttribute{ Description: "A [JSONata] (https://jsonata.org/) expression that transforms an application's user identities into attribute assertions in the SAML response. The expression can transform id, email, name, and groups values. It can also transform fields listed in the saml_attributes or oidc_fields of the identity provider used to authenticate. The output of this expression must be a JSON object.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, }, "sp_entity_id": schema.StringAttribute{ Description: "A globally unique name for an identity or service provider.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, }, "sso_endpoint": schema.StringAttribute{ Description: "The endpoint where your SaaS application will send login requests.", Computed: true, Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToNullOrBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "saml"), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "updated_at": schema.StringAttribute{ Computed: true, @@ -1368,10 +1505,17 @@ func ResourceSchema(ctx context.Context) schema.Schema { "access_token_lifetime": schema.StringAttribute{ Description: "The lifetime of the OIDC Access Token after creation. Valid units are m,h. Must be greater than or equal to 1m and less than or equal to 24h.", Optional: true, + Computed: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), + }, }, "allow_pkce_without_client_secret": schema.BoolAttribute{ Description: "If client secret should be required on the token endpoint when authorization_code_with_pkce grant is used.", Optional: true, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), + }, }, "app_launcher_url": schema.StringAttribute{ Description: "The URL where this applications tile redirects users", @@ -1380,16 +1524,23 @@ func ResourceSchema(ctx context.Context) schema.Schema { "client_id": schema.StringAttribute{ Description: "The application client id", Computed: true, - Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "client_secret": schema.StringAttribute{ Description: "The application client secret, only returned on POST request.", Computed: true, - Optional: true, Sensitive: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "custom_claims": schema.ListNestedAttribute{ Optional: true, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), + }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "name": schema.StringAttribute{ @@ -1433,6 +1584,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "The OIDC flows supported by this application", Optional: true, Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), listvalidator.ValueStringsAre( stringvalidator.OneOfCaseInsensitive( "authorization_code", @@ -1448,9 +1600,15 @@ func ResourceSchema(ctx context.Context) schema.Schema { "group_filter_regex": schema.StringAttribute{ Description: "A regex to filter Cloudflare groups returned in ID token and userinfo endpoint", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), + }, }, "hybrid_and_implicit_options": schema.SingleNestedAttribute{ Optional: true, + Validators: []validator.Object{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), + }, Attributes: map[string]schema.Attribute{ "return_access_token_from_authorization_endpoint": schema.BoolAttribute{ Description: "If an Access Token should be returned from the OIDC Authorization endpoint", @@ -1466,9 +1624,15 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "The permitted URL's for Cloudflare to return Authorization codes and Access/ID tokens", Optional: true, ElementType: types.StringType, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), + }, }, "refresh_token_options": schema.SingleNestedAttribute{ Optional: true, + Validators: []validator.Object{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), + }, Attributes: map[string]schema.Attribute{ "lifetime": schema.StringAttribute{ Description: "How long a refresh token will be valid for after creation. Valid units are m,h,d. Must be longer than 1m.", @@ -1480,6 +1644,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: `Define the user information shared with access, "offline_access" scope will be automatically enabled if refresh tokens are enabled`, Optional: true, Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("saas_app").AtName("auth_type"), "oidc"), listvalidator.ValueStringsAre( stringvalidator.OneOfCaseInsensitive( "openid", @@ -1496,14 +1661,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { "aud": schema.StringAttribute{ Description: "Audience tag.", Computed: true, - }, - "created_at": schema.StringAttribute{ - Computed: true, - CustomType: timetypes.RFC3339Type{}, - }, - "updated_at": schema.StringAttribute{ - Computed: true, - CustomType: timetypes.RFC3339Type{}, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, } diff --git a/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithadefinedidp.tf b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithadefinedidp.tf index 38e8348191..90d485adc8 100644 --- a/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithadefinedidp.tf +++ b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithadefinedidp.tf @@ -1,12 +1,10 @@ resource "cloudflare_zero_trust_access_identity_provider" "%[1]s" { account_id = "%[4]s" - name = "%[1]s" - type = "onetimepin" - config = { - client_id = "test" - client_secret = "test" - } + name = "%[1]s" + type = "onetimepin" + config = {} } + resource "cloudflare_zero_trust_access_application" "%[1]s" { zone_id = "%[2]s" name = "%[1]s" @@ -14,5 +12,5 @@ resource "cloudflare_zero_trust_access_application" "%[1]s" { type = "self_hosted" session_duration = "24h" auto_redirect_to_identity = true - allowed_idps = [cloudflare_zero_trust_access_identity_provider.%[1]s.id] + allowed_idps = [cloudflare_zero_trust_access_identity_provider.%[1]s.id] } diff --git a/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithinvalidsaas.tf b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithinvalidsaas.tf new file mode 100644 index 0000000000..a16f9677be --- /dev/null +++ b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithinvalidsaas.tf @@ -0,0 +1,7 @@ +resource "cloudflare_zero_trust_access_application" "%[1]s" { + account_id = "%[2]s" + name = "%[1]s" + type = "saas" + session_duration = "24h" + auto_redirect_to_identity = false +} diff --git a/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithlegacypolicies.tf b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithlegacypolicies.tf new file mode 100644 index 0000000000..e95760f837 --- /dev/null +++ b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithlegacypolicies.tf @@ -0,0 +1,42 @@ +resource "cloudflare_zero_trust_access_policy" "%[1]s_reusable_p1" { + account_id = "%[3]s" + name = "%[1]s" + decision = "non_identity" + include = [ + { + ip = { ip = "127.0.0.1/32" } + } + ] +} + +resource "cloudflare_zero_trust_access_application" "%[1]s" { + account_id = "%[3]s" + name = "%[1]s" + domain = "%[1]s.%[2]s" + type = "self_hosted" + policies = [ + { + name = "%[1]s.legacy_p1" + decision = "allow" + include = [ + { + email = { email = "a@example.com" } + } + ] + precedence = 2 + }, + { + id = cloudflare_zero_trust_access_policy.%[1]s_reusable_p1.id + precedence = 4 + }, + { + name = "%[1]s.legacy_p2" + decision = "non_identity" + include = [ + { + ip = { ip = "127.0.0.1/32" } + } + ] + } + ] +} diff --git a/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithreusablepolicies.tf b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithreusablepolicies.tf index ff022ad272..b41dbcb5d5 100644 --- a/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithreusablepolicies.tf +++ b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithreusablepolicies.tf @@ -1,42 +1,37 @@ resource "cloudflare_zero_trust_access_policy" "%[1]s_p1" { - account_id = "%[3]s" - name = "%[1]s" - decision = "allow" - include = [{ - email = { email = "a@example.com" } - }] + account_id = "%[3]s" + name = "%[1]s" + decision = "allow" + include = [ + { + email = { email = "a@example.com" } + } + ] } resource "cloudflare_zero_trust_access_policy" "%[1]s_p2" { - account_id = "%[3]s" - name = "%[1]s" - decision = "non_identity" - include = [{ - ip = { ip = "127.0.0.1/32" } - }] + account_id = "%[3]s" + name = "%[1]s" + decision = "non_identity" + include = [ + { + ip = { ip = "127.0.0.1/32" } + } + ] } resource "cloudflare_zero_trust_access_application" "%[1]s" { - account_id = "%[3]s" - name = "%[1]s" - domain = "%[1]s.%[2]s" - type = "self_hosted" - policies = [ - { - id = cloudflare_zero_trust_access_policy.%[1]s_p1.id - decision = cloudflare_zero_trust_access_policy.%[1]s_p1.decision - name = cloudflare_zero_trust_access_policy.%[1]s_p1.name - include = [{ - email = { email = cloudflare_zero_trust_access_policy.%[1]s_p1.include.0.email.email } - }] + account_id = "%[3]s" + name = "%[1]s" + domain = "%[1]s.%[2]s" + type = "self_hosted" + policies = [ + { + id = cloudflare_zero_trust_access_policy.%[1]s_p1.id + precedence = 4 }, { id = cloudflare_zero_trust_access_policy.%[1]s_p2.id - decision = cloudflare_zero_trust_access_policy.%[1]s_p2.decision - name = cloudflare_zero_trust_access_policy.%[1]s_p2.name - include = [{ - ip = { ip = cloudflare_zero_trust_access_policy.%[1]s_p2.include.0.ip.ip } - }] } ] } diff --git a/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithsamlsaas.tf b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithsamlsaas.tf index 29485a75d1..15378c9e85 100644 --- a/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithsamlsaas.tf +++ b/internal/services/zero_trust_access_application/testdata/accessapplicationconfigwithsamlsaas.tf @@ -4,23 +4,23 @@ resource "cloudflare_zero_trust_access_application" "%[1]s" { type = "saas" session_duration = "24h" saas_app = { - consumer_service_url = "https://saas-app.example/sso/saml/consume" - sp_entity_id = "saas-app.example" - name_id_format = "email" - default_relay_state = "https://saas-app.example" - name_id_transform_jsonata = "$substringBefore(email, '@') & '+sandbox@' & $substringAfter(email, '@')" + consumer_service_url = "https://saas-app.example/sso/saml/consume" + sp_entity_id = "saas-app.example" + name_id_format = "email" + default_relay_state = "https://saas-app.example" + name_id_transform_jsonata = "$substringBefore(email, '@') & '+sandbox@' & $substringAfter(email, '@')" saml_attribute_transform_jsonata = "$ ~>| groups | {'group_name': name} |" custom_attributes = [ { - name = "email" - name_format = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" - source = { name = "user_email" } + name = "email" + name_format = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" + source = { name = "user_email" } }, { - name = "rank" - required = true - friendly_name = "Rank" - source = { name = "rank" } + name = "rank" + required = true + friendly_name = "Rank" + source = { name = "rank" } } ] } diff --git a/internal/services/zero_trust_access_application/testdata/accessapplicationwithapplaunchercustomizationfields.tf b/internal/services/zero_trust_access_application/testdata/accessapplicationwithapplaunchercustomizationfields.tf index 81b0a4625a..be442cd995 100644 --- a/internal/services/zero_trust_access_application/testdata/accessapplicationwithapplaunchercustomizationfields.tf +++ b/internal/services/zero_trust_access_application/testdata/accessapplicationwithapplaunchercustomizationfields.tf @@ -1,22 +1,23 @@ resource "cloudflare_zero_trust_access_application" "%[1]s" { - account_id = "%[2]s" - type = "app_launcher" - session_duration = "24h" - app_launcher_visible = false - app_launcher_logo_url = "https://www.cloudflare.com/img/logo-web-badges/cf-logo-on-white-bg.svg" - bg_color = "#000000" - header_bg_color = "#000000" + account_id = "%[2]s" + type = "app_launcher" + session_duration = "24h" + app_launcher_logo_url = "https://www.cloudflare.com/img/logo-web-badges/cf-logo-on-white-bg.svg" + bg_color = "#000000" + header_bg_color = "#000000" - footer_links = [{ - name = "footer link" - url = "https://www.cloudflare.com" - }] + footer_links = [ + { + name = "footer link" + url = "https://www.cloudflare.com" + } + ] - landing_page_design = { - title = "title" - message = "message" - button_color = "#000000" - image_url = "https://www.cloudflare.com/img/logo-web-badges/cf-logo-on-white-bg.svg" - button_text_color = "#000000" - } + landing_page_design = { + title = "title" + message = "message" + button_color = "#000000" + image_url = "https://www.cloudflare.com/img/logo-web-badges/cf-logo-on-white-bg.svg" + button_text_color = "#000000" + } } diff --git a/internal/services/zero_trust_access_identity_provider/normalizations.go b/internal/services/zero_trust_access_identity_provider/normalizations.go new file mode 100644 index 0000000000..525968c023 --- /dev/null +++ b/internal/services/zero_trust_access_identity_provider/normalizations.go @@ -0,0 +1,18 @@ +package zero_trust_access_identity_provider + +import ( + "context" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +func normalizeReadZeroTrustIDPData(ctx context.Context, apiValue *ZeroTrustAccessIdentityProviderModel, state *tfsdk.State) diag.Diagnostics { + var stateValue ZeroTrustAccessIdentityProviderModel + d := state.Get(ctx, &stateValue) + if apiValue.Type.ValueString() == "azureAD" && + (apiValue.Config != nil && !apiValue.Config.ConditionalAccessEnabled.ValueBool()) && + (stateValue.Config != nil && !stateValue.Config.ConditionalAccessEnabled.ValueBool()) { + apiValue.Config.ConditionalAccessEnabled = stateValue.Config.ConditionalAccessEnabled + } + return d +} diff --git a/internal/services/zero_trust_access_identity_provider/resource.go b/internal/services/zero_trust_access_identity_provider/resource.go index 5c42bdb922..bdcdf6ba1a 100644 --- a/internal/services/zero_trust_access_identity_provider/resource.go +++ b/internal/services/zero_trust_access_identity_provider/resource.go @@ -213,6 +213,8 @@ func (r *ZeroTrustAccessIdentityProviderResource) Read(ctx context.Context, req } data = &env.Result + normalizeReadZeroTrustIDPData(ctx, data, &req.State) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("scim_config").AtName("secret"), secret)...) } @@ -302,6 +304,6 @@ func (r *ZeroTrustAccessIdentityProviderResource) ImportState(ctx context.Contex resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func (r *ZeroTrustAccessIdentityProviderResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { +func (r *ZeroTrustAccessIdentityProviderResource) ModifyPlan(context.Context, resource.ModifyPlanRequest, *resource.ModifyPlanResponse) { } diff --git a/internal/services/zero_trust_access_identity_provider/schema.go b/internal/services/zero_trust_access_identity_provider/schema.go index 1511b5e5a3..fec6b1ade8 100644 --- a/internal/services/zero_trust_access_identity_provider/schema.go +++ b/internal/services/zero_trust_access_identity_provider/schema.go @@ -44,8 +44,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, }, "type": schema.StringAttribute{ - Description: "The type of identity provider. To determine the value for a specific provider, refer to our [developer documentation](https://developers.cloudflare.com/cloudflare-one/identity/idp-integration/).\nAvailable values: \"onetimepin\", \"azureAD\", \"saml\", \"centrify\", \"facebook\", \"github\", \"google-apps\", \"google\", \"linkedin\", \"oidc\", \"okta\", \"onelogin\", \"pingone\", \"yandex\".", - Required: true, + Description: "The type of identity provider. To determine the value for a specific provider, refer to our [developer documentation](https://developers.cloudflare.com/cloudflare-one/identity/idp-integration/).\nAvailable values: \"onetimepin\", \"azureAD\", \"saml\", \"centrify\", \"facebook\", \"github\", \"google-apps\", \"google\", \"linkedin\", \"oidc\", \"okta\", \"onelogin\", \"pingone\", \"yandex\".", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive( "onetimepin", diff --git a/internal/services/zero_trust_access_policy/model.go b/internal/services/zero_trust_access_policy/model.go index 655357b089..9b65c946b6 100644 --- a/internal/services/zero_trust_access_policy/model.go +++ b/internal/services/zero_trust_access_policy/model.go @@ -27,9 +27,7 @@ type ZeroTrustAccessPolicyModel struct { Exclude customfield.NestedObjectList[ZeroTrustAccessPolicyExcludeModel] `tfsdk:"exclude" json:"exclude,computed_optional"` Include customfield.NestedObjectList[ZeroTrustAccessPolicyIncludeModel] `tfsdk:"include" json:"include,computed_optional"` Require customfield.NestedObjectList[ZeroTrustAccessPolicyRequireModel] `tfsdk:"require" json:"require,computed_optional"` - AppCount types.Int64 `tfsdk:"app_count" json:"app_count,computed"` CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` - Reusable types.Bool `tfsdk:"reusable" json:"reusable,computed"` UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` } diff --git a/internal/services/zero_trust_access_policy/schema.go b/internal/services/zero_trust_access_policy/schema.go index 09b77673c0..10ac9021de 100644 --- a/internal/services/zero_trust_access_policy/schema.go +++ b/internal/services/zero_trust_access_policy/schema.go @@ -800,17 +800,10 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, - "app_count": schema.Int64Attribute{ - Description: "Number of access applications currently using this policy.", - Computed: true, - }, "created_at": schema.StringAttribute{ Computed: true, CustomType: timetypes.RFC3339Type{}, }, - "reusable": schema.BoolAttribute{ - Computed: true, - }, "updated_at": schema.StringAttribute{ Computed: true, CustomType: timetypes.RFC3339Type{}, diff --git a/scripts/run-ci-acceptance-tests b/scripts/run-ci-acceptance-tests index ca1e41adc8..b90ce483c7 100755 --- a/scripts/run-ci-acceptance-tests +++ b/scripts/run-ci-acceptance-tests @@ -113,6 +113,7 @@ go test -run "^TestAcc" -count 1 \ ./internal/services/workers_route \ ./internal/services/workers_script \ ./internal/services/workers_script_subdomain \ + ./internal/services/zero_trust_access_application \ ./internal/services/zero_trust_access_infrastructure_target \ ./internal/services/zero_trust_access_key_configuration \ ./internal/services/zero_trust_access_mtls_hostname_settings \ From 5fa0dee8f9e8342523e3617500d3316150107b45 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 10:02:10 +0000 Subject: [PATCH 135/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3f5769c1d8..de433e06a4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-06c0722289c612a94a6c1e228ea4ada586b3942b04cb02b9a55d98adef5e9558.yml -openapi_spec_hash: f6f0cf5e8a41260e0d1ddf20a71a9c75 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-18e27d0e054a8b6d5fb94b14e2c26aa969ce8a99a0cb39eb84fed7c862df532e.yml +openapi_spec_hash: 2565070122de00041f70a5a52e5d1856 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 94197d3f00b61cc807fd7f98eb844034d78a1695 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 12:07:56 +0000 Subject: [PATCH 136/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index de433e06a4..6c6260f34e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-18e27d0e054a8b6d5fb94b14e2c26aa969ce8a99a0cb39eb84fed7c862df532e.yml -openapi_spec_hash: 2565070122de00041f70a5a52e5d1856 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ca3bcaa555572b3cd1f4370f69217537efb9e9cfa35d5430ed112057b4b8a1c5.yml +openapi_spec_hash: e6861902fdee4e44c8272b29e0ecfa0c config_hash: 284c4178d08f75d8c8b29f275948a8fd From 08ae49e3f90c807285a7a3786c1b2555f546b5e8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:37:33 +0000 Subject: [PATCH 137/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6c6260f34e..2ce9312395 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ca3bcaa555572b3cd1f4370f69217537efb9e9cfa35d5430ed112057b4b8a1c5.yml -openapi_spec_hash: e6861902fdee4e44c8272b29e0ecfa0c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3e1f0cf28b20bf72f09a9c0ff506a4f9c7e10f3f302fa27d1ac18de85ae99d88.yml +openapi_spec_hash: 6f715a68579915106a75426cd0b1668c config_hash: 284c4178d08f75d8c8b29f275948a8fd From 5c721afc99e6e28034b0f2b2b16a5761e281d5d6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:02:31 +0000 Subject: [PATCH 138/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2ce9312395..0fafaeb6ed 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3e1f0cf28b20bf72f09a9c0ff506a4f9c7e10f3f302fa27d1ac18de85ae99d88.yml -openapi_spec_hash: 6f715a68579915106a75426cd0b1668c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-909bf66edca8e60c9b79a637e887eafcd0ee0785a0f5dcb1156f75025474b681.yml +openapi_spec_hash: 982d254124046b4e74e16b3fff909898 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 2315a18f9ef4fe15df7d9b78c164f1338305223f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:39:26 +0000 Subject: [PATCH 139/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0fafaeb6ed..21162738b7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-909bf66edca8e60c9b79a637e887eafcd0ee0785a0f5dcb1156f75025474b681.yml -openapi_spec_hash: 982d254124046b4e74e16b3fff909898 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-42feba8865b4c8119bbfa35807f74e59de13be02ed81c9f887daab07a5689157.yml +openapi_spec_hash: d8c2c8e871477da1ced8b2f49c335942 config_hash: 284c4178d08f75d8c8b29f275948a8fd From fd7f9e4f3f324527caf6741d9e0c8870b8c3595e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:02:30 +0000 Subject: [PATCH 140/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 21162738b7..f2a5b02826 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-42feba8865b4c8119bbfa35807f74e59de13be02ed81c9f887daab07a5689157.yml -openapi_spec_hash: d8c2c8e871477da1ced8b2f49c335942 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-91d602be53cd2ea23d0f3d72cc4dc22506cd40ce64397e52929897260f1d5855.yml +openapi_spec_hash: a743c1e82045b35f9d3806284bd0d55b config_hash: 284c4178d08f75d8c8b29f275948a8fd From e368f6b988823b408a802e2ca97e656672cc1609 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:25:28 +0000 Subject: [PATCH 141/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f2a5b02826..2b0271f0e5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-91d602be53cd2ea23d0f3d72cc4dc22506cd40ce64397e52929897260f1d5855.yml -openapi_spec_hash: a743c1e82045b35f9d3806284bd0d55b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-5049bd1a864a468070ff3fe28f1d37086c6c8eb168a7ccab25e385ec83957626.yml +openapi_spec_hash: 775c5a2942feeedc08f5b31df965f6fb config_hash: 284c4178d08f75d8c8b29f275948a8fd From a7f2069921941ddf3cd6727767b0064b187b8da6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:27:00 +0000 Subject: [PATCH 142/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2b0271f0e5..4be3b6cadc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-5049bd1a864a468070ff3fe28f1d37086c6c8eb168a7ccab25e385ec83957626.yml -openapi_spec_hash: 775c5a2942feeedc08f5b31df965f6fb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fba48484f21ed01e9c21aa59976a96304de202726dff7f4e47887a8d8b429653.yml +openapi_spec_hash: 0be829777ee3470dc79b574e7fe39748 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 91178f888d7e3d130e403df86266c25b1425081d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:29:46 +0000 Subject: [PATCH 143/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4be3b6cadc..2b0271f0e5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fba48484f21ed01e9c21aa59976a96304de202726dff7f4e47887a8d8b429653.yml -openapi_spec_hash: 0be829777ee3470dc79b574e7fe39748 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-5049bd1a864a468070ff3fe28f1d37086c6c8eb168a7ccab25e385ec83957626.yml +openapi_spec_hash: 775c5a2942feeedc08f5b31df965f6fb config_hash: 284c4178d08f75d8c8b29f275948a8fd From 860d458b722b30345f3ffab695d334e0057f3439 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:16:28 +0000 Subject: [PATCH 144/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2b0271f0e5..4be3b6cadc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-5049bd1a864a468070ff3fe28f1d37086c6c8eb168a7ccab25e385ec83957626.yml -openapi_spec_hash: 775c5a2942feeedc08f5b31df965f6fb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fba48484f21ed01e9c21aa59976a96304de202726dff7f4e47887a8d8b429653.yml +openapi_spec_hash: 0be829777ee3470dc79b574e7fe39748 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 47292bf996bc37d302af9b9470992e6f2083502f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:28:34 +0000 Subject: [PATCH 145/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4be3b6cadc..96094337de 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fba48484f21ed01e9c21aa59976a96304de202726dff7f4e47887a8d8b429653.yml -openapi_spec_hash: 0be829777ee3470dc79b574e7fe39748 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ae6ffcbcc0856b0712d948732796e69c83954b184b053cd143d3ca2e4b1ce0da.yml +openapi_spec_hash: cce02f17f85e5baa523a036fe2a044cd config_hash: 284c4178d08f75d8c8b29f275948a8fd From 8072877b6af1fd0da9ff28c87767f3dbc3d06aa4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 17:21:16 +0000 Subject: [PATCH 146/187] feat(api): api update --- .stats.yml | 4 ++-- examples/resources/cloudflare_account_token/resource.tf | 4 +++- examples/resources/cloudflare_api_token/resource.tf | 4 +++- internal/services/account_token/data_source_model.go | 2 +- internal/services/account_token/data_source_schema.go | 6 ++++-- internal/services/account_token/list_data_source_model.go | 2 +- internal/services/account_token/list_data_source_schema.go | 6 ++++-- internal/services/account_token/model.go | 2 +- internal/services/account_token/schema.go | 4 +++- internal/services/api_token/data_source_model.go | 2 +- internal/services/api_token/data_source_schema.go | 6 ++++-- internal/services/api_token/list_data_source_model.go | 2 +- internal/services/api_token/list_data_source_schema.go | 6 ++++-- internal/services/api_token/model.go | 2 +- internal/services/api_token/schema.go | 4 +++- 15 files changed, 36 insertions(+), 20 deletions(-) diff --git a/.stats.yml b/.stats.yml index 96094337de..0b571dfa57 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ae6ffcbcc0856b0712d948732796e69c83954b184b053cd143d3ca2e4b1ce0da.yml -openapi_spec_hash: cce02f17f85e5baa523a036fe2a044cd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-79b67999c1748cd1df9ce78542f18e9b09c8c4cd3aafe5f194633754c74efda3.yml +openapi_spec_hash: a9a2aa58b9449dd64c6a291cbe9981cc config_hash: 284c4178d08f75d8c8b29f275948a8fd diff --git a/examples/resources/cloudflare_account_token/resource.tf b/examples/resources/cloudflare_account_token/resource.tf index 894d97bb2e..9bbfa14500 100644 --- a/examples/resources/cloudflare_account_token/resource.tf +++ b/examples/resources/cloudflare_account_token/resource.tf @@ -17,7 +17,9 @@ resource "cloudflare_account_token" "example_account_token" { } }] resources = { - foo = "string" + foo = { + foo = "string" + } } }] condition = { diff --git a/examples/resources/cloudflare_api_token/resource.tf b/examples/resources/cloudflare_api_token/resource.tf index 8886b0b8ca..ade55ca04a 100644 --- a/examples/resources/cloudflare_api_token/resource.tf +++ b/examples/resources/cloudflare_api_token/resource.tf @@ -16,7 +16,9 @@ resource "cloudflare_api_token" "example_api_token" { } }] resources = { - foo = "string" + foo = { + foo = "string" + } } }] condition = { diff --git a/internal/services/account_token/data_source_model.go b/internal/services/account_token/data_source_model.go index 7320f384a9..d478aeb59b 100644 --- a/internal/services/account_token/data_source_model.go +++ b/internal/services/account_token/data_source_model.go @@ -66,7 +66,7 @@ type AccountTokenPoliciesDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,computed"` PermissionGroups customfield.NestedObjectList[AccountTokenPoliciesPermissionGroupsDataSourceModel] `tfsdk:"permission_groups" json:"permission_groups,computed"` - Resources customfield.Map[types.String] `tfsdk:"resources" json:"resources,computed"` + Resources customfield.Map[customfield.Map[types.String]] `tfsdk:"resources" json:"resources,computed"` } type AccountTokenPoliciesPermissionGroupsDataSourceModel struct { diff --git a/internal/services/account_token/data_source_schema.go b/internal/services/account_token/data_source_schema.go index 0e0a2a9296..1699ea203d 100644 --- a/internal/services/account_token/data_source_schema.go +++ b/internal/services/account_token/data_source_schema.go @@ -148,8 +148,10 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Computed: true, - CustomType: customfield.NewMapType[types.String](ctx), - ElementType: types.StringType, + CustomType: customfield.NewMapType[customfield.Map[types.String]](ctx), + ElementType: types.MapType{ + ElemType: types.StringType, + }, }, }, }, diff --git a/internal/services/account_token/list_data_source_model.go b/internal/services/account_token/list_data_source_model.go index 17a9a8689a..1f87e623c4 100644 --- a/internal/services/account_token/list_data_source_model.go +++ b/internal/services/account_token/list_data_source_model.go @@ -62,7 +62,7 @@ type AccountTokensPoliciesDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,computed"` PermissionGroups customfield.NestedObjectList[AccountTokensPoliciesPermissionGroupsDataSourceModel] `tfsdk:"permission_groups" json:"permission_groups,computed"` - Resources customfield.Map[types.String] `tfsdk:"resources" json:"resources,computed"` + Resources customfield.Map[customfield.Map[types.String]] `tfsdk:"resources" json:"resources,computed"` } type AccountTokensPoliciesPermissionGroupsDataSourceModel struct { diff --git a/internal/services/account_token/list_data_source_schema.go b/internal/services/account_token/list_data_source_schema.go index 3408b951ec..c8da0caea3 100644 --- a/internal/services/account_token/list_data_source_schema.go +++ b/internal/services/account_token/list_data_source_schema.go @@ -152,8 +152,10 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Computed: true, - CustomType: customfield.NewMapType[types.String](ctx), - ElementType: types.StringType, + CustomType: customfield.NewMapType[customfield.Map[types.String]](ctx), + ElementType: types.MapType{ + ElemType: types.StringType, + }, }, }, }, diff --git a/internal/services/account_token/model.go b/internal/services/account_token/model.go index 7f18eb0c4b..ff7e4a913c 100644 --- a/internal/services/account_token/model.go +++ b/internal/services/account_token/model.go @@ -40,7 +40,7 @@ type AccountTokenPoliciesModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,required"` PermissionGroups *[]*AccountTokenPoliciesPermissionGroupsModel `tfsdk:"permission_groups" json:"permission_groups,required"` - Resources *map[string]types.String `tfsdk:"resources" json:"resources,required"` + Resources *map[string]*map[string]types.String `tfsdk:"resources" json:"resources,required"` } type AccountTokenPoliciesPermissionGroupsModel struct { diff --git a/internal/services/account_token/schema.go b/internal/services/account_token/schema.go index a765151b8b..a8e0991704 100644 --- a/internal/services/account_token/schema.go +++ b/internal/services/account_token/schema.go @@ -84,7 +84,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Required: true, - ElementType: types.StringType, + ElementType: types.MapType{ + ElemType: types.StringType, + }, }, }, }, diff --git a/internal/services/api_token/data_source_model.go b/internal/services/api_token/data_source_model.go index cc38fb5063..d466c854d1 100644 --- a/internal/services/api_token/data_source_model.go +++ b/internal/services/api_token/data_source_model.go @@ -55,7 +55,7 @@ type APITokenPoliciesDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,computed"` PermissionGroups customfield.NestedObjectList[APITokenPoliciesPermissionGroupsDataSourceModel] `tfsdk:"permission_groups" json:"permission_groups,computed"` - Resources customfield.Map[types.String] `tfsdk:"resources" json:"resources,computed"` + Resources customfield.Map[customfield.Map[types.String]] `tfsdk:"resources" json:"resources,computed"` } type APITokenPoliciesPermissionGroupsDataSourceModel struct { diff --git a/internal/services/api_token/data_source_schema.go b/internal/services/api_token/data_source_schema.go index 40f1c48e3f..7014c558d0 100644 --- a/internal/services/api_token/data_source_schema.go +++ b/internal/services/api_token/data_source_schema.go @@ -144,8 +144,10 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Computed: true, - CustomType: customfield.NewMapType[types.String](ctx), - ElementType: types.StringType, + CustomType: customfield.NewMapType[customfield.Map[types.String]](ctx), + ElementType: types.MapType{ + ElemType: types.StringType, + }, }, }, }, diff --git a/internal/services/api_token/list_data_source_model.go b/internal/services/api_token/list_data_source_model.go index 00732f4877..9ca6660400 100644 --- a/internal/services/api_token/list_data_source_model.go +++ b/internal/services/api_token/list_data_source_model.go @@ -59,7 +59,7 @@ type APITokensPoliciesDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,computed"` PermissionGroups customfield.NestedObjectList[APITokensPoliciesPermissionGroupsDataSourceModel] `tfsdk:"permission_groups" json:"permission_groups,computed"` - Resources customfield.Map[types.String] `tfsdk:"resources" json:"resources,computed"` + Resources customfield.Map[customfield.Map[types.String]] `tfsdk:"resources" json:"resources,computed"` } type APITokensPoliciesPermissionGroupsDataSourceModel struct { diff --git a/internal/services/api_token/list_data_source_schema.go b/internal/services/api_token/list_data_source_schema.go index b97fb4594e..57b2e6c672 100644 --- a/internal/services/api_token/list_data_source_schema.go +++ b/internal/services/api_token/list_data_source_schema.go @@ -148,8 +148,10 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Computed: true, - CustomType: customfield.NewMapType[types.String](ctx), - ElementType: types.StringType, + CustomType: customfield.NewMapType[customfield.Map[types.String]](ctx), + ElementType: types.MapType{ + ElemType: types.StringType, + }, }, }, }, diff --git a/internal/services/api_token/model.go b/internal/services/api_token/model.go index f96dd5437d..01caeee4e4 100644 --- a/internal/services/api_token/model.go +++ b/internal/services/api_token/model.go @@ -38,7 +38,7 @@ type APITokenPoliciesModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,required"` PermissionGroups *[]*APITokenPoliciesPermissionGroupsModel `tfsdk:"permission_groups" json:"permission_groups,required"` - Resources *map[string]types.String `tfsdk:"resources" json:"resources,required"` + Resources *map[string]*map[string]types.String `tfsdk:"resources" json:"resources,required"` } type APITokenPoliciesPermissionGroupsModel struct { diff --git a/internal/services/api_token/schema.go b/internal/services/api_token/schema.go index 8ae1089fa1..7a286b32cb 100644 --- a/internal/services/api_token/schema.go +++ b/internal/services/api_token/schema.go @@ -76,7 +76,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Required: true, - ElementType: types.StringType, + ElementType: types.MapType{ + ElemType: types.StringType, + }, }, }, }, From a5a3c581703739faedf2a5a922ec576e737985d9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 17:42:10 +0000 Subject: [PATCH 147/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0b571dfa57..d460faf10a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-79b67999c1748cd1df9ce78542f18e9b09c8c4cd3aafe5f194633754c74efda3.yml -openapi_spec_hash: a9a2aa58b9449dd64c6a291cbe9981cc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-e4a8036717db701e2c4150e4c79e945610651d92dd1025534829b24bb94c8b93.yml +openapi_spec_hash: 802d5904b4c6850754129234f78c81e5 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 01c2d35bbc4824fdcd314acdfc607f0e66f2561b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 19:04:34 +0000 Subject: [PATCH 148/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d460faf10a..5457fc3f35 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-e4a8036717db701e2c4150e4c79e945610651d92dd1025534829b24bb94c8b93.yml -openapi_spec_hash: 802d5904b4c6850754129234f78c81e5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7a9600a1ebc7905731c050ea7471c0034df7633cb2726aab226df3141e9f2037.yml +openapi_spec_hash: 1596f2cf8e092c9775505296958c41e4 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 235bdc7d9387c0278aaf431869516e6f38e0e770 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 19:22:23 +0000 Subject: [PATCH 149/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5457fc3f35..7e0cef02c8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7a9600a1ebc7905731c050ea7471c0034df7633cb2726aab226df3141e9f2037.yml -openapi_spec_hash: 1596f2cf8e092c9775505296958c41e4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6492b8554db528fc5246bec5d18b9743b92507f00f232ed69e10474262be4c8c.yml +openapi_spec_hash: 7c1ee096409f4b59e522bba00c911d07 config_hash: 284c4178d08f75d8c8b29f275948a8fd From bcbb93afd5cdb46c2182642902dd7d31425396ba Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 20:58:28 +0000 Subject: [PATCH 150/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7e0cef02c8..c0d7d1987c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-6492b8554db528fc5246bec5d18b9743b92507f00f232ed69e10474262be4c8c.yml -openapi_spec_hash: 7c1ee096409f4b59e522bba00c911d07 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-4c3d04b5ccf3eef80ced89900e30ba515959d50f395f8d65e610488d1084e9e5.yml +openapi_spec_hash: a3f24daa469d6247827c79c29a04c5fb config_hash: 284c4178d08f75d8c8b29f275948a8fd From 29cec1988c89d3e09e8a76718a531b6f789b6332 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 21:21:32 +0000 Subject: [PATCH 151/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c0d7d1987c..ed35957815 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-4c3d04b5ccf3eef80ced89900e30ba515959d50f395f8d65e610488d1084e9e5.yml -openapi_spec_hash: a3f24daa469d6247827c79c29a04c5fb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0f2bd193526171b33bdf83aed6c80e17bfec552bc98ed3e17ac18329a6e556f8.yml +openapi_spec_hash: ac1d578220e778b767b97cae294a6b51 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 51192a2ed86171989eb5e866b8d7f0c2fc5835e7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 22:04:44 +0000 Subject: [PATCH 152/187] feat(api): api update --- .stats.yml | 4 ++-- examples/resources/cloudflare_account_token/resource.tf | 4 +--- examples/resources/cloudflare_api_token/resource.tf | 4 +--- internal/services/account_token/data_source_model.go | 2 +- internal/services/account_token/data_source_schema.go | 6 ++---- internal/services/account_token/list_data_source_model.go | 2 +- internal/services/account_token/list_data_source_schema.go | 6 ++---- internal/services/account_token/model.go | 2 +- internal/services/account_token/schema.go | 4 +--- internal/services/api_token/data_source_model.go | 2 +- internal/services/api_token/data_source_schema.go | 6 ++---- internal/services/api_token/list_data_source_model.go | 2 +- internal/services/api_token/list_data_source_schema.go | 6 ++---- internal/services/api_token/model.go | 2 +- internal/services/api_token/schema.go | 4 +--- 15 files changed, 20 insertions(+), 36 deletions(-) diff --git a/.stats.yml b/.stats.yml index ed35957815..65a8b31b36 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0f2bd193526171b33bdf83aed6c80e17bfec552bc98ed3e17ac18329a6e556f8.yml -openapi_spec_hash: ac1d578220e778b767b97cae294a6b51 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fd1b420cb57dab0611a1e37130f60c8c53dcfe02529108fef301812d5dfd9bb6.yml +openapi_spec_hash: 326a08d1b5e9390af5d1fb976a15cbae config_hash: 284c4178d08f75d8c8b29f275948a8fd diff --git a/examples/resources/cloudflare_account_token/resource.tf b/examples/resources/cloudflare_account_token/resource.tf index 9bbfa14500..894d97bb2e 100644 --- a/examples/resources/cloudflare_account_token/resource.tf +++ b/examples/resources/cloudflare_account_token/resource.tf @@ -17,9 +17,7 @@ resource "cloudflare_account_token" "example_account_token" { } }] resources = { - foo = { - foo = "string" - } + foo = "string" } }] condition = { diff --git a/examples/resources/cloudflare_api_token/resource.tf b/examples/resources/cloudflare_api_token/resource.tf index ade55ca04a..8886b0b8ca 100644 --- a/examples/resources/cloudflare_api_token/resource.tf +++ b/examples/resources/cloudflare_api_token/resource.tf @@ -16,9 +16,7 @@ resource "cloudflare_api_token" "example_api_token" { } }] resources = { - foo = { - foo = "string" - } + foo = "string" } }] condition = { diff --git a/internal/services/account_token/data_source_model.go b/internal/services/account_token/data_source_model.go index d478aeb59b..7320f384a9 100644 --- a/internal/services/account_token/data_source_model.go +++ b/internal/services/account_token/data_source_model.go @@ -66,7 +66,7 @@ type AccountTokenPoliciesDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,computed"` PermissionGroups customfield.NestedObjectList[AccountTokenPoliciesPermissionGroupsDataSourceModel] `tfsdk:"permission_groups" json:"permission_groups,computed"` - Resources customfield.Map[customfield.Map[types.String]] `tfsdk:"resources" json:"resources,computed"` + Resources customfield.Map[types.String] `tfsdk:"resources" json:"resources,computed"` } type AccountTokenPoliciesPermissionGroupsDataSourceModel struct { diff --git a/internal/services/account_token/data_source_schema.go b/internal/services/account_token/data_source_schema.go index 1699ea203d..0e0a2a9296 100644 --- a/internal/services/account_token/data_source_schema.go +++ b/internal/services/account_token/data_source_schema.go @@ -148,10 +148,8 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Computed: true, - CustomType: customfield.NewMapType[customfield.Map[types.String]](ctx), - ElementType: types.MapType{ - ElemType: types.StringType, - }, + CustomType: customfield.NewMapType[types.String](ctx), + ElementType: types.StringType, }, }, }, diff --git a/internal/services/account_token/list_data_source_model.go b/internal/services/account_token/list_data_source_model.go index 1f87e623c4..17a9a8689a 100644 --- a/internal/services/account_token/list_data_source_model.go +++ b/internal/services/account_token/list_data_source_model.go @@ -62,7 +62,7 @@ type AccountTokensPoliciesDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,computed"` PermissionGroups customfield.NestedObjectList[AccountTokensPoliciesPermissionGroupsDataSourceModel] `tfsdk:"permission_groups" json:"permission_groups,computed"` - Resources customfield.Map[customfield.Map[types.String]] `tfsdk:"resources" json:"resources,computed"` + Resources customfield.Map[types.String] `tfsdk:"resources" json:"resources,computed"` } type AccountTokensPoliciesPermissionGroupsDataSourceModel struct { diff --git a/internal/services/account_token/list_data_source_schema.go b/internal/services/account_token/list_data_source_schema.go index c8da0caea3..3408b951ec 100644 --- a/internal/services/account_token/list_data_source_schema.go +++ b/internal/services/account_token/list_data_source_schema.go @@ -152,10 +152,8 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Computed: true, - CustomType: customfield.NewMapType[customfield.Map[types.String]](ctx), - ElementType: types.MapType{ - ElemType: types.StringType, - }, + CustomType: customfield.NewMapType[types.String](ctx), + ElementType: types.StringType, }, }, }, diff --git a/internal/services/account_token/model.go b/internal/services/account_token/model.go index ff7e4a913c..7f18eb0c4b 100644 --- a/internal/services/account_token/model.go +++ b/internal/services/account_token/model.go @@ -40,7 +40,7 @@ type AccountTokenPoliciesModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,required"` PermissionGroups *[]*AccountTokenPoliciesPermissionGroupsModel `tfsdk:"permission_groups" json:"permission_groups,required"` - Resources *map[string]*map[string]types.String `tfsdk:"resources" json:"resources,required"` + Resources *map[string]types.String `tfsdk:"resources" json:"resources,required"` } type AccountTokenPoliciesPermissionGroupsModel struct { diff --git a/internal/services/account_token/schema.go b/internal/services/account_token/schema.go index a8e0991704..a765151b8b 100644 --- a/internal/services/account_token/schema.go +++ b/internal/services/account_token/schema.go @@ -84,9 +84,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Required: true, - ElementType: types.MapType{ - ElemType: types.StringType, - }, + ElementType: types.StringType, }, }, }, diff --git a/internal/services/api_token/data_source_model.go b/internal/services/api_token/data_source_model.go index d466c854d1..cc38fb5063 100644 --- a/internal/services/api_token/data_source_model.go +++ b/internal/services/api_token/data_source_model.go @@ -55,7 +55,7 @@ type APITokenPoliciesDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,computed"` PermissionGroups customfield.NestedObjectList[APITokenPoliciesPermissionGroupsDataSourceModel] `tfsdk:"permission_groups" json:"permission_groups,computed"` - Resources customfield.Map[customfield.Map[types.String]] `tfsdk:"resources" json:"resources,computed"` + Resources customfield.Map[types.String] `tfsdk:"resources" json:"resources,computed"` } type APITokenPoliciesPermissionGroupsDataSourceModel struct { diff --git a/internal/services/api_token/data_source_schema.go b/internal/services/api_token/data_source_schema.go index 7014c558d0..40f1c48e3f 100644 --- a/internal/services/api_token/data_source_schema.go +++ b/internal/services/api_token/data_source_schema.go @@ -144,10 +144,8 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Computed: true, - CustomType: customfield.NewMapType[customfield.Map[types.String]](ctx), - ElementType: types.MapType{ - ElemType: types.StringType, - }, + CustomType: customfield.NewMapType[types.String](ctx), + ElementType: types.StringType, }, }, }, diff --git a/internal/services/api_token/list_data_source_model.go b/internal/services/api_token/list_data_source_model.go index 9ca6660400..00732f4877 100644 --- a/internal/services/api_token/list_data_source_model.go +++ b/internal/services/api_token/list_data_source_model.go @@ -59,7 +59,7 @@ type APITokensPoliciesDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,computed"` PermissionGroups customfield.NestedObjectList[APITokensPoliciesPermissionGroupsDataSourceModel] `tfsdk:"permission_groups" json:"permission_groups,computed"` - Resources customfield.Map[customfield.Map[types.String]] `tfsdk:"resources" json:"resources,computed"` + Resources customfield.Map[types.String] `tfsdk:"resources" json:"resources,computed"` } type APITokensPoliciesPermissionGroupsDataSourceModel struct { diff --git a/internal/services/api_token/list_data_source_schema.go b/internal/services/api_token/list_data_source_schema.go index 57b2e6c672..b97fb4594e 100644 --- a/internal/services/api_token/list_data_source_schema.go +++ b/internal/services/api_token/list_data_source_schema.go @@ -148,10 +148,8 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Computed: true, - CustomType: customfield.NewMapType[customfield.Map[types.String]](ctx), - ElementType: types.MapType{ - ElemType: types.StringType, - }, + CustomType: customfield.NewMapType[types.String](ctx), + ElementType: types.StringType, }, }, }, diff --git a/internal/services/api_token/model.go b/internal/services/api_token/model.go index 01caeee4e4..f96dd5437d 100644 --- a/internal/services/api_token/model.go +++ b/internal/services/api_token/model.go @@ -38,7 +38,7 @@ type APITokenPoliciesModel struct { ID types.String `tfsdk:"id" json:"id,computed"` Effect types.String `tfsdk:"effect" json:"effect,required"` PermissionGroups *[]*APITokenPoliciesPermissionGroupsModel `tfsdk:"permission_groups" json:"permission_groups,required"` - Resources *map[string]*map[string]types.String `tfsdk:"resources" json:"resources,required"` + Resources *map[string]types.String `tfsdk:"resources" json:"resources,required"` } type APITokenPoliciesPermissionGroupsModel struct { diff --git a/internal/services/api_token/schema.go b/internal/services/api_token/schema.go index 7a286b32cb..8ae1089fa1 100644 --- a/internal/services/api_token/schema.go +++ b/internal/services/api_token/schema.go @@ -76,9 +76,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "resources": schema.MapAttribute{ Description: "A list of resource names that the policy applies to.", Required: true, - ElementType: types.MapType{ - ElemType: types.StringType, - }, + ElementType: types.StringType, }, }, }, From 0acad4a3b4506ac47269ba154a912a841abc9888 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 22:08:01 +0000 Subject: [PATCH 153/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 65a8b31b36..ae7258e052 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fd1b420cb57dab0611a1e37130f60c8c53dcfe02529108fef301812d5dfd9bb6.yml -openapi_spec_hash: 326a08d1b5e9390af5d1fb976a15cbae +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d533d4e934a66ddbb480577a08bf932947c053f8a5060c4e5a3fae34f405fdc8.yml +openapi_spec_hash: 039b35d08c3bba51af3c4ec5832850a0 config_hash: 284c4178d08f75d8c8b29f275948a8fd From bdb65b06b3699e7eb584805e57a22607b6c383a6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 22:43:44 +0000 Subject: [PATCH 154/187] chore(ci): only run for pushes and fork pull requests --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90882aa1e0..effb11b0a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ on: jobs: lint: runs-on: ${{ github.repository == 'stainless-sdks/cloudflare-terraform' && 'depot-ubuntu-24.04' || 'lx64' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -31,6 +32,7 @@ jobs: test: runs-on: ${{ github.repository == 'stainless-sdks/cloudflare-terraform' && 'depot-ubuntu-24.04' || 'lx64' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 From 50ea13afff51f6115d609fe30717c583cdf931d1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 22:55:12 +0000 Subject: [PATCH 155/187] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index ae7258e052..8f5a2e75a0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d533d4e934a66ddbb480577a08bf932947c053f8a5060c4e5a3fae34f405fdc8.yml -openapi_spec_hash: 039b35d08c3bba51af3c4ec5832850a0 +openapi_spec_hash: e7921ba2e6f51641f1bd5ea80ed8de04 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 9a8e94dcb9df9ed5dff99ea233135e95045ca0f0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 22:59:02 +0000 Subject: [PATCH 156/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8f5a2e75a0..80deeaf33e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d533d4e934a66ddbb480577a08bf932947c053f8a5060c4e5a3fae34f405fdc8.yml -openapi_spec_hash: e7921ba2e6f51641f1bd5ea80ed8de04 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-07850c05f5faee9033ffe4970b3e0a2368458141d05da9b761a534f8195e6e6d.yml +openapi_spec_hash: 69b3076f1524a788b18a81893fee1ee3 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 454d8c4ba33ca1448eaa800383ef40cccb04b1e1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 03:26:31 +0000 Subject: [PATCH 157/187] feat(api): api update --- .stats.yml | 4 +-- .../logpush_dataset_job/data_source_model.go | 6 ++--- .../logpush_dataset_job/data_source_schema.go | 24 ++++++++--------- .../services/logpush_job/data_source_model.go | 6 ++--- .../logpush_job/data_source_schema.go | 24 ++++++++--------- .../logpush_job/list_data_source_model.go | 6 ++--- .../logpush_job/list_data_source_schema.go | 24 ++++++++--------- internal/services/logpush_job/model.go | 6 ++--- internal/services/logpush_job/schema.go | 27 +++++++++---------- 9 files changed, 62 insertions(+), 65 deletions(-) diff --git a/.stats.yml b/.stats.yml index 80deeaf33e..c098e9b98a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-07850c05f5faee9033ffe4970b3e0a2368458141d05da9b761a534f8195e6e6d.yml -openapi_spec_hash: 69b3076f1524a788b18a81893fee1ee3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-97074b550d93648f2a49d85826e270e6d8701c8f7995d398092d47b38a5617d5.yml +openapi_spec_hash: e8767543491a9b3109cd30388421100b config_hash: 284c4178d08f75d8c8b29f275948a8fd diff --git a/internal/services/logpush_dataset_job/data_source_model.go b/internal/services/logpush_dataset_job/data_source_model.go index fab17e6add..78229e634f 100644 --- a/internal/services/logpush_dataset_job/data_source_model.go +++ b/internal/services/logpush_dataset_job/data_source_model.go @@ -31,9 +31,9 @@ type LogpushDatasetJobDataSourceModel struct { LastComplete timetypes.RFC3339 `tfsdk:"last_complete" json:"last_complete,computed" format:"date-time"` LastError timetypes.RFC3339 `tfsdk:"last_error" json:"last_error,computed" format:"date-time"` LogpullOptions types.String `tfsdk:"logpull_options" json:"logpull_options,computed"` - MaxUploadBytes types.Int64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,computed"` - MaxUploadIntervalSeconds types.Int64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed"` - MaxUploadRecords types.Int64 `tfsdk:"max_upload_records" json:"max_upload_records,computed"` + MaxUploadBytes types.Float64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,computed"` + MaxUploadIntervalSeconds types.Float64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed"` + MaxUploadRecords types.Float64 `tfsdk:"max_upload_records" json:"max_upload_records,computed"` Name types.String `tfsdk:"name" json:"name,computed"` OutputOptions customfield.NestedObject[LogpushDatasetJobOutputOptionsDataSourceModel] `tfsdk:"output_options" json:"output_options,computed"` } diff --git a/internal/services/logpush_dataset_job/data_source_schema.go b/internal/services/logpush_dataset_job/data_source_schema.go index 358b0db6f1..2a85d30bc5 100644 --- a/internal/services/logpush_dataset_job/data_source_schema.go +++ b/internal/services/logpush_dataset_job/data_source_schema.go @@ -145,25 +145,25 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Computed: true, DeprecationMessage: "This attribute is deprecated.", }, - "max_upload_bytes": schema.Int64Attribute{ - Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size. This parameter is not available for jobs with `edge` as its kind.", + "max_upload_bytes": schema.Float64Attribute{ + Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(5000000, 1000000000), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, - "max_upload_interval_seconds": schema.Int64Attribute{ - Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this. This parameter is only used for jobs with `edge` as its kind.", + "max_upload_interval_seconds": schema.Float64Attribute{ + Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(30, 300), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, - "max_upload_records": schema.Int64Attribute{ - Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this. This parameter is not available for jobs with `edge` as its kind.", + "max_upload_records": schema.Float64Attribute{ + Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(1000, 1000000), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, "name": schema.StringAttribute{ diff --git a/internal/services/logpush_job/data_source_model.go b/internal/services/logpush_job/data_source_model.go index 2c9db3e04e..dab09c2f24 100644 --- a/internal/services/logpush_job/data_source_model.go +++ b/internal/services/logpush_job/data_source_model.go @@ -31,9 +31,9 @@ type LogpushJobDataSourceModel struct { LastComplete timetypes.RFC3339 `tfsdk:"last_complete" json:"last_complete,computed" format:"date-time"` LastError timetypes.RFC3339 `tfsdk:"last_error" json:"last_error,computed" format:"date-time"` LogpullOptions types.String `tfsdk:"logpull_options" json:"logpull_options,computed"` - MaxUploadBytes types.Int64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,computed"` - MaxUploadIntervalSeconds types.Int64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed"` - MaxUploadRecords types.Int64 `tfsdk:"max_upload_records" json:"max_upload_records,computed"` + MaxUploadBytes types.Float64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,computed"` + MaxUploadIntervalSeconds types.Float64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed"` + MaxUploadRecords types.Float64 `tfsdk:"max_upload_records" json:"max_upload_records,computed"` Name types.String `tfsdk:"name" json:"name,computed"` OutputOptions customfield.NestedObject[LogpushJobOutputOptionsDataSourceModel] `tfsdk:"output_options" json:"output_options,computed"` } diff --git a/internal/services/logpush_job/data_source_schema.go b/internal/services/logpush_job/data_source_schema.go index d2635a3a3e..4d6fde50cb 100644 --- a/internal/services/logpush_job/data_source_schema.go +++ b/internal/services/logpush_job/data_source_schema.go @@ -119,25 +119,25 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Computed: true, DeprecationMessage: "This attribute is deprecated.", }, - "max_upload_bytes": schema.Int64Attribute{ - Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size. This parameter is not available for jobs with `edge` as its kind.", + "max_upload_bytes": schema.Float64Attribute{ + Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(5000000, 1000000000), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, - "max_upload_interval_seconds": schema.Int64Attribute{ - Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this. This parameter is only used for jobs with `edge` as its kind.", + "max_upload_interval_seconds": schema.Float64Attribute{ + Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(30, 300), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, - "max_upload_records": schema.Int64Attribute{ - Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this. This parameter is not available for jobs with `edge` as its kind.", + "max_upload_records": schema.Float64Attribute{ + Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(1000, 1000000), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, "name": schema.StringAttribute{ diff --git a/internal/services/logpush_job/list_data_source_model.go b/internal/services/logpush_job/list_data_source_model.go index 481f67b0c7..ad071eb5b7 100644 --- a/internal/services/logpush_job/list_data_source_model.go +++ b/internal/services/logpush_job/list_data_source_model.go @@ -47,9 +47,9 @@ type LogpushJobsResultDataSourceModel struct { LastComplete timetypes.RFC3339 `tfsdk:"last_complete" json:"last_complete,computed" format:"date-time"` LastError timetypes.RFC3339 `tfsdk:"last_error" json:"last_error,computed" format:"date-time"` LogpullOptions types.String `tfsdk:"logpull_options" json:"logpull_options,computed"` - MaxUploadBytes types.Int64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,computed"` - MaxUploadIntervalSeconds types.Int64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed"` - MaxUploadRecords types.Int64 `tfsdk:"max_upload_records" json:"max_upload_records,computed"` + MaxUploadBytes types.Float64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,computed"` + MaxUploadIntervalSeconds types.Float64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed"` + MaxUploadRecords types.Float64 `tfsdk:"max_upload_records" json:"max_upload_records,computed"` Name types.String `tfsdk:"name" json:"name,computed"` OutputOptions customfield.NestedObject[LogpushJobsOutputOptionsDataSourceModel] `tfsdk:"output_options" json:"output_options,computed"` } diff --git a/internal/services/logpush_job/list_data_source_schema.go b/internal/services/logpush_job/list_data_source_schema.go index e55fa7f557..88d068e7d0 100644 --- a/internal/services/logpush_job/list_data_source_schema.go +++ b/internal/services/logpush_job/list_data_source_schema.go @@ -125,25 +125,25 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Computed: true, DeprecationMessage: "This attribute is deprecated.", }, - "max_upload_bytes": schema.Int64Attribute{ - Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size. This parameter is not available for jobs with `edge` as its kind.", + "max_upload_bytes": schema.Float64Attribute{ + Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(5000000, 1000000000), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, - "max_upload_interval_seconds": schema.Int64Attribute{ - Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this. This parameter is only used for jobs with `edge` as its kind.", + "max_upload_interval_seconds": schema.Float64Attribute{ + Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(30, 300), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, - "max_upload_records": schema.Int64Attribute{ - Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this. This parameter is not available for jobs with `edge` as its kind.", + "max_upload_records": schema.Float64Attribute{ + Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this.\nAvailable values: 0.", Computed: true, - Validators: []validator.Int64{ - int64validator.Between(1000, 1000000), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, "name": schema.StringAttribute{ diff --git a/internal/services/logpush_job/model.go b/internal/services/logpush_job/model.go index f65ccb95d5..9990cd678e 100644 --- a/internal/services/logpush_job/model.go +++ b/internal/services/logpush_job/model.go @@ -22,13 +22,13 @@ type LogpushJobModel struct { Enabled types.Bool `tfsdk:"enabled" json:"enabled,optional"` Filter types.String `tfsdk:"filter" json:"filter,optional,no_refresh"` LogpullOptions types.String `tfsdk:"logpull_options" json:"logpull_options,optional"` - MaxUploadBytes types.Int64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,optional"` + MaxUploadBytes types.Float64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,optional"` Name types.String `tfsdk:"name" json:"name,optional"` OwnershipChallenge types.String `tfsdk:"ownership_challenge" json:"ownership_challenge,optional,no_refresh"` Frequency types.String `tfsdk:"frequency" json:"frequency,computed_optional"` Kind types.String `tfsdk:"kind" json:"kind,computed_optional"` - MaxUploadIntervalSeconds types.Int64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed_optional"` - MaxUploadRecords types.Int64 `tfsdk:"max_upload_records" json:"max_upload_records,computed_optional"` + MaxUploadIntervalSeconds types.Float64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed_optional"` + MaxUploadRecords types.Float64 `tfsdk:"max_upload_records" json:"max_upload_records,computed_optional"` OutputOptions customfield.NestedObject[LogpushJobOutputOptionsModel] `tfsdk:"output_options" json:"output_options,computed_optional"` ErrorMessage types.String `tfsdk:"error_message" json:"error_message,computed"` LastComplete timetypes.RFC3339 `tfsdk:"last_complete" json:"last_complete,computed" format:"date-time"` diff --git a/internal/services/logpush_job/schema.go b/internal/services/logpush_job/schema.go index caaf007d0c..f97d5509d6 100644 --- a/internal/services/logpush_job/schema.go +++ b/internal/services/logpush_job/schema.go @@ -14,7 +14,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/float64default" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" @@ -98,11 +97,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { Optional: true, DeprecationMessage: "This attribute is deprecated.", }, - "max_upload_bytes": schema.Int64Attribute{ - Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size. This parameter is not available for jobs with `edge` as its kind.", + "max_upload_bytes": schema.Float64Attribute{ + Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size.\nAvailable values: 0.", Optional: true, - Validators: []validator.Int64{ - int64validator.Between(5000000, 1000000000), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, }, "name": schema.StringAttribute{ @@ -133,23 +132,21 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, Default: stringdefault.StaticString(""), }, - "max_upload_interval_seconds": schema.Int64Attribute{ - Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this. This parameter is only used for jobs with `edge` as its kind.", + "max_upload_interval_seconds": schema.Float64Attribute{ + Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this.\nAvailable values: 0.", Computed: true, Optional: true, - Validators: []validator.Int64{ - int64validator.Between(30, 300), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, - Default: int64default.StaticInt64(30), }, - "max_upload_records": schema.Int64Attribute{ - Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this. This parameter is not available for jobs with `edge` as its kind.", + "max_upload_records": schema.Float64Attribute{ + Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this.\nAvailable values: 0.", Computed: true, Optional: true, - Validators: []validator.Int64{ - int64validator.Between(1000, 1000000), + Validators: []validator.Float64{ + float64validator.OneOf(0), }, - Default: int64default.StaticInt64(100000), }, "output_options": schema.SingleNestedAttribute{ Description: "The structured replacement for `logpull_options`. When including this field, the `logpull_option` field will be ignored.", From be9b31d3edb706c55dbb82421fbece9ac9d55ded Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 03:53:03 +0000 Subject: [PATCH 158/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c098e9b98a..21f590531a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-97074b550d93648f2a49d85826e270e6d8701c8f7995d398092d47b38a5617d5.yml -openapi_spec_hash: e8767543491a9b3109cd30388421100b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d1f9bc5d4ff983922303cbeb07f95ce8a1349e7cb85c3c35d54ede88ef7b4457.yml +openapi_spec_hash: 8e71c2e7d6377b510152299736720a11 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 504ba25b53a478366fa2f495449ab9ba8bbeb655 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 06:16:04 +0000 Subject: [PATCH 159/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 21f590531a..a9e6576911 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d1f9bc5d4ff983922303cbeb07f95ce8a1349e7cb85c3c35d54ede88ef7b4457.yml -openapi_spec_hash: 8e71c2e7d6377b510152299736720a11 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c7d7bd26c4996e7e7241be895166c5f64e8db7d483091c6e3d75c9ad6e11dcbf.yml +openapi_spec_hash: 9592d49009e10003a86a2d24069b6afc config_hash: 284c4178d08f75d8c8b29f275948a8fd From 75c19365c808431b5548692a2ed61b300a2d2d39 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 29 Jun 2025 06:14:14 +0000 Subject: [PATCH 160/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a9e6576911..0ea1050911 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c7d7bd26c4996e7e7241be895166c5f64e8db7d483091c6e3d75c9ad6e11dcbf.yml -openapi_spec_hash: 9592d49009e10003a86a2d24069b6afc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d8e71359b16a5ccc22c0dce5c16d1ff798500cc8858af25335d85e9d6c0d64b0.yml +openapi_spec_hash: 1bcf0ff8d24d6e63399a9e0c1a331336 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 2a649e2e551b61d8055b785fc80c92d2eab98fea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 06:14:21 +0000 Subject: [PATCH 161/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0ea1050911..cf6586dcf7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-d8e71359b16a5ccc22c0dce5c16d1ff798500cc8858af25335d85e9d6c0d64b0.yml -openapi_spec_hash: 1bcf0ff8d24d6e63399a9e0c1a331336 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-56825afb1a7a893f4928c3184b8db1345893562278db43d1ab77ebeff740082e.yml +openapi_spec_hash: 2b5b0dcc1d4a02ae0cee79e6065bbef1 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 3221cd1669cac02b561c4033fce46462fe6b88fb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 11:36:12 +0000 Subject: [PATCH 162/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index cf6586dcf7..dcb3152b21 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-56825afb1a7a893f4928c3184b8db1345893562278db43d1ab77ebeff740082e.yml -openapi_spec_hash: 2b5b0dcc1d4a02ae0cee79e6065bbef1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9e7c566c3ce59d925331b04a5c4802747f67167d4645637414a17b2db0f89a5a.yml +openapi_spec_hash: 43e4ef78fd8c5d5a4695688659db7fbd config_hash: 284c4178d08f75d8c8b29f275948a8fd From e5e9aec42e1085f08f048aa66d7171a369eeacb7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 12:08:20 +0000 Subject: [PATCH 163/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index dcb3152b21..26887e5ac2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9e7c566c3ce59d925331b04a5c4802747f67167d4645637414a17b2db0f89a5a.yml -openapi_spec_hash: 43e4ef78fd8c5d5a4695688659db7fbd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-85dad60f1b2821be03c3c8a58b223fceae36de496cee13a358f7603d685d31c0.yml +openapi_spec_hash: b57f7fe72b7083fa0c7ed0ec30569810 config_hash: 284c4178d08f75d8c8b29f275948a8fd From cc795011a00e33c5b77abd0c79da2eec0de596de Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 12:37:08 +0000 Subject: [PATCH 164/187] feat(api): api update --- .stats.yml | 4 +- .../data-source.tf | 4 +- .../import.sh | 1 + .../resource.tf | 2 + .../services/rate_limit/data_source_schema.go | 2 +- .../rate_limit/list_data_source_schema.go | 2 +- internal/services/rate_limit/schema.go | 2 +- .../user_agent_blocking_rule/data_source.go | 30 +++++++++ .../data_source_model.go | 40 ++++++++++- .../data_source_schema.go | 67 ++++++++++++++++++- .../list_data_source_model.go | 20 +++--- .../list_data_source_schema.go | 6 +- .../user_agent_blocking_rule/model.go | 8 ++- .../user_agent_blocking_rule/resource.go | 54 ++++++++++++++- .../user_agent_blocking_rule/schema.go | 18 +++-- internal/services/zone_lockdown/schema.go | 2 +- 16 files changed, 226 insertions(+), 36 deletions(-) create mode 100644 examples/resources/cloudflare_user_agent_blocking_rule/import.sh diff --git a/.stats.yml b/.stats.yml index 26887e5ac2..fbaed1d32c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-85dad60f1b2821be03c3c8a58b223fceae36de496cee13a358f7603d685d31c0.yml -openapi_spec_hash: b57f7fe72b7083fa0c7ed0ec30569810 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-00c303ed3ff51e75fd30ab890a69ebbfde9bcb7c3a64397b081abfdd30c7b212.yml +openapi_spec_hash: 6886ec9a0f6960b8da8ef7309236eefb config_hash: 284c4178d08f75d8c8b29f275948a8fd diff --git a/examples/data-sources/cloudflare_user_agent_blocking_rules/data-source.tf b/examples/data-sources/cloudflare_user_agent_blocking_rules/data-source.tf index bc748a5e59..3dbee13a7b 100644 --- a/examples/data-sources/cloudflare_user_agent_blocking_rules/data-source.tf +++ b/examples/data-sources/cloudflare_user_agent_blocking_rules/data-source.tf @@ -1,6 +1,6 @@ data "cloudflare_user_agent_blocking_rules" "example_user_agent_blocking_rules" { zone_id = "023e105f4ecef8ad9ca31a8372d0c353" description = "abusive" - description_search = "abusive" - ua_search = "Safari" + paused = false + user_agent = "Safari" } diff --git a/examples/resources/cloudflare_user_agent_blocking_rule/import.sh b/examples/resources/cloudflare_user_agent_blocking_rule/import.sh new file mode 100644 index 0000000000..af5b863405 --- /dev/null +++ b/examples/resources/cloudflare_user_agent_blocking_rule/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_user_agent_blocking_rule.example '/' diff --git a/examples/resources/cloudflare_user_agent_blocking_rule/resource.tf b/examples/resources/cloudflare_user_agent_blocking_rule/resource.tf index 186b6bc4b7..a692ceb9a7 100644 --- a/examples/resources/cloudflare_user_agent_blocking_rule/resource.tf +++ b/examples/resources/cloudflare_user_agent_blocking_rule/resource.tf @@ -5,4 +5,6 @@ resource "cloudflare_user_agent_blocking_rule" "example_user_agent_blocking_rule value = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" } mode = "challenge" + description = "Prevent multiple login failures to mitigate brute force attacks" + paused = false } diff --git a/internal/services/rate_limit/data_source_schema.go b/internal/services/rate_limit/data_source_schema.go index 7a03cc0f3c..1a44cf701c 100644 --- a/internal/services/rate_limit/data_source_schema.go +++ b/internal/services/rate_limit/data_source_schema.go @@ -34,7 +34,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Required: true, }, "description": schema.StringAttribute{ - Description: "An informative summary of the rate limit. This value is sanitized and any tags will be removed.", + Description: "An informative summary of the rule. This value is sanitized and any tags will be removed.", Computed: true, }, "disabled": schema.BoolAttribute{ diff --git a/internal/services/rate_limit/list_data_source_schema.go b/internal/services/rate_limit/list_data_source_schema.go index 1548890971..0d6cdb12a6 100644 --- a/internal/services/rate_limit/list_data_source_schema.go +++ b/internal/services/rate_limit/list_data_source_schema.go @@ -106,7 +106,7 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, "description": schema.StringAttribute{ - Description: "An informative summary of the rate limit. This value is sanitized and any tags will be removed.", + Description: "An informative summary of the rule. This value is sanitized and any tags will be removed.", Computed: true, }, "disabled": schema.BoolAttribute{ diff --git a/internal/services/rate_limit/schema.go b/internal/services/rate_limit/schema.go index faa3a417a9..70afb07e79 100644 --- a/internal/services/rate_limit/schema.go +++ b/internal/services/rate_limit/schema.go @@ -157,7 +157,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, "description": schema.StringAttribute{ - Description: "An informative summary of the rate limit. This value is sanitized and any tags will be removed.", + Description: "An informative summary of the rule. This value is sanitized and any tags will be removed.", Computed: true, }, "disabled": schema.BoolAttribute{ diff --git a/internal/services/user_agent_blocking_rule/data_source.go b/internal/services/user_agent_blocking_rule/data_source.go index 79c45b7402..944a5034fd 100644 --- a/internal/services/user_agent_blocking_rule/data_source.go +++ b/internal/services/user_agent_blocking_rule/data_source.go @@ -57,6 +57,36 @@ func (d *UserAgentBlockingRuleDataSource) Read(ctx context.Context, req datasour return } + if data.Filter != nil { + params, diags := data.toListParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + env := UserAgentBlockingRulesResultListDataSourceEnvelope{} + page, err := d.client.Firewall.UARules.List(ctx, params) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + bytes := []byte(page.JSON.RawJSON()) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to unmarshal http request", err.Error()) + return + } + + if count := len(env.Result.Elements()); count != 1 { + resp.Diagnostics.AddError("failed to find exactly one result", fmt.Sprint(count)+" found") + return + } + ts, diags := env.Result.AsStructSliceT(ctx) + resp.Diagnostics.Append(diags...) + data.UARuleID = ts[0].ID + } + params, diags := data.toReadParams(ctx) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/internal/services/user_agent_blocking_rule/data_source_model.go b/internal/services/user_agent_blocking_rule/data_source_model.go index e7b35ed62d..7d24cf71af 100644 --- a/internal/services/user_agent_blocking_rule/data_source_model.go +++ b/internal/services/user_agent_blocking_rule/data_source_model.go @@ -7,6 +7,7 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/firewall" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,8 +17,14 @@ type UserAgentBlockingRuleResultDataSourceEnvelope struct { } type UserAgentBlockingRuleDataSourceModel struct { - UARuleID types.String `tfsdk:"ua_rule_id" path:"ua_rule_id,required"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + ID types.String `tfsdk:"id" path:"ua_rule_id,computed"` + UARuleID types.String `tfsdk:"ua_rule_id" path:"ua_rule_id,optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Description types.String `tfsdk:"description" json:"description,computed"` + Mode types.String `tfsdk:"mode" json:"mode,computed"` + Paused types.Bool `tfsdk:"paused" json:"paused,computed"` + Configuration customfield.NestedObject[UserAgentBlockingRuleConfigurationDataSourceModel] `tfsdk:"configuration" json:"configuration,computed"` + Filter *UserAgentBlockingRuleFindOneByDataSourceModel `tfsdk:"filter"` } func (m *UserAgentBlockingRuleDataSourceModel) toReadParams(_ context.Context) (params firewall.UARuleGetParams, diags diag.Diagnostics) { @@ -27,3 +34,32 @@ func (m *UserAgentBlockingRuleDataSourceModel) toReadParams(_ context.Context) ( return } + +func (m *UserAgentBlockingRuleDataSourceModel) toListParams(_ context.Context) (params firewall.UARuleListParams, diags diag.Diagnostics) { + params = firewall.UARuleListParams{ + ZoneID: cloudflare.F(m.ZoneID.ValueString()), + } + + if !m.Filter.Description.IsNull() { + params.Description = cloudflare.F(m.Filter.Description.ValueString()) + } + if !m.Filter.Paused.IsNull() { + params.Paused = cloudflare.F(m.Filter.Paused.ValueBool()) + } + if !m.Filter.UserAgent.IsNull() { + params.UserAgent = cloudflare.F(m.Filter.UserAgent.ValueString()) + } + + return +} + +type UserAgentBlockingRuleConfigurationDataSourceModel struct { + Target types.String `tfsdk:"target" json:"target,computed"` + Value types.String `tfsdk:"value" json:"value,computed"` +} + +type UserAgentBlockingRuleFindOneByDataSourceModel struct { + Description types.String `tfsdk:"description" query:"description,optional"` + Paused types.Bool `tfsdk:"paused" query:"paused,optional"` + UserAgent types.String `tfsdk:"user_agent" query:"user_agent,optional"` +} diff --git a/internal/services/user_agent_blocking_rule/data_source_schema.go b/internal/services/user_agent_blocking_rule/data_source_schema.go index a045f7088c..6693ab9ecd 100644 --- a/internal/services/user_agent_blocking_rule/data_source_schema.go +++ b/internal/services/user_agent_blocking_rule/data_source_schema.go @@ -5,8 +5,13 @@ package user_agent_blocking_rule import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) var _ datasource.DataSourceWithConfigValidators = (*UserAgentBlockingRuleDataSource)(nil) @@ -14,14 +19,70 @@ var _ datasource.DataSourceWithConfigValidators = (*UserAgentBlockingRuleDataSou func DataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique identifier of the User Agent Blocking rule.", + Computed: true, + }, "ua_rule_id": schema.StringAttribute{ Description: "The unique identifier of the User Agent Blocking rule.", - Required: true, + Optional: true, }, "zone_id": schema.StringAttribute{ Description: "Defines an identifier.", Required: true, }, + "description": schema.StringAttribute{ + Description: "An informative summary of the rule.", + Computed: true, + }, + "mode": schema.StringAttribute{ + Description: "The action to apply to a matched request.\nAvailable values: \"block\", \"challenge\", \"js_challenge\", \"managed_challenge\".", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "block", + "challenge", + "js_challenge", + "managed_challenge", + ), + }, + }, + "paused": schema.BoolAttribute{ + Description: "When true, indicates that the rule is currently paused.", + Computed: true, + }, + "configuration": schema.SingleNestedAttribute{ + Description: "The configuration object for the current rule.", + Computed: true, + CustomType: customfield.NewNestedObjectType[UserAgentBlockingRuleConfigurationDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "target": schema.StringAttribute{ + Description: "The configuration target for this rule. You must set the target to `ua` for User Agent Blocking rules.", + Computed: true, + }, + "value": schema.StringAttribute{ + Description: "The exact user agent string to match. This value will be compared to the received `User-Agent` HTTP header value.", + Computed: true, + }, + }, + }, + "filter": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "description": schema.StringAttribute{ + Description: "A string to search for in the description of existing rules.", + Optional: true, + }, + "paused": schema.BoolAttribute{ + Description: "When true, indicates that the rule is currently paused.", + Optional: true, + }, + "user_agent": schema.StringAttribute{ + Description: "A string to search for in the user agent values of existing rules.", + Optional: true, + }, + }, + }, }, } } @@ -31,5 +92,7 @@ func (d *UserAgentBlockingRuleDataSource) Schema(ctx context.Context, req dataso } func (d *UserAgentBlockingRuleDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { - return []datasource.ConfigValidator{} + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf(path.MatchRoot("ua_rule_id"), path.MatchRoot("filter")), + } } diff --git a/internal/services/user_agent_blocking_rule/list_data_source_model.go b/internal/services/user_agent_blocking_rule/list_data_source_model.go index f859070d69..da4b6cae41 100644 --- a/internal/services/user_agent_blocking_rule/list_data_source_model.go +++ b/internal/services/user_agent_blocking_rule/list_data_source_model.go @@ -17,12 +17,12 @@ type UserAgentBlockingRulesResultListDataSourceEnvelope struct { } type UserAgentBlockingRulesDataSourceModel struct { - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - Description types.String `tfsdk:"description" query:"description,optional"` - DescriptionSearch types.String `tfsdk:"description_search" query:"description_search,optional"` - UASearch types.String `tfsdk:"ua_search" query:"ua_search,optional"` - MaxItems types.Int64 `tfsdk:"max_items"` - Result customfield.NestedObjectList[UserAgentBlockingRulesResultDataSourceModel] `tfsdk:"result"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Description types.String `tfsdk:"description" query:"description,optional"` + Paused types.Bool `tfsdk:"paused" query:"paused,optional"` + UserAgent types.String `tfsdk:"user_agent" query:"user_agent,optional"` + MaxItems types.Int64 `tfsdk:"max_items"` + Result customfield.NestedObjectList[UserAgentBlockingRulesResultDataSourceModel] `tfsdk:"result"` } func (m *UserAgentBlockingRulesDataSourceModel) toListParams(_ context.Context) (params firewall.UARuleListParams, diags diag.Diagnostics) { @@ -33,11 +33,11 @@ func (m *UserAgentBlockingRulesDataSourceModel) toListParams(_ context.Context) if !m.Description.IsNull() { params.Description = cloudflare.F(m.Description.ValueString()) } - if !m.DescriptionSearch.IsNull() { - params.DescriptionSearch = cloudflare.F(m.DescriptionSearch.ValueString()) + if !m.Paused.IsNull() { + params.Paused = cloudflare.F(m.Paused.ValueBool()) } - if !m.UASearch.IsNull() { - params.UASearch = cloudflare.F(m.UASearch.ValueString()) + if !m.UserAgent.IsNull() { + params.UserAgent = cloudflare.F(m.UserAgent.ValueString()) } return diff --git a/internal/services/user_agent_blocking_rule/list_data_source_schema.go b/internal/services/user_agent_blocking_rule/list_data_source_schema.go index fbbb6b9705..f87e2df07f 100644 --- a/internal/services/user_agent_blocking_rule/list_data_source_schema.go +++ b/internal/services/user_agent_blocking_rule/list_data_source_schema.go @@ -26,11 +26,11 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Description: "A string to search for in the description of existing rules.", Optional: true, }, - "description_search": schema.StringAttribute{ - Description: "A string to search for in the description of existing rules.", + "paused": schema.BoolAttribute{ + Description: "When true, indicates that the rule is currently paused.", Optional: true, }, - "ua_search": schema.StringAttribute{ + "user_agent": schema.StringAttribute{ Description: "A string to search for in the user agent values of existing rules.", Optional: true, }, diff --git a/internal/services/user_agent_blocking_rule/model.go b/internal/services/user_agent_blocking_rule/model.go index 9b6eb6b86a..3658285a71 100644 --- a/internal/services/user_agent_blocking_rule/model.go +++ b/internal/services/user_agent_blocking_rule/model.go @@ -12,10 +12,12 @@ type UserAgentBlockingRuleResultEnvelope struct { } type UserAgentBlockingRuleModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - UARuleID types.String `tfsdk:"ua_rule_id" path:"ua_rule_id,optional"` - Mode types.String `tfsdk:"mode" json:"mode,required,no_refresh"` - Configuration *UserAgentBlockingRuleConfigurationModel `tfsdk:"configuration" json:"configuration,required,no_refresh"` + Mode types.String `tfsdk:"mode" json:"mode,required"` + Configuration *UserAgentBlockingRuleConfigurationModel `tfsdk:"configuration" json:"configuration,required"` + Description types.String `tfsdk:"description" json:"description,optional"` + Paused types.Bool `tfsdk:"paused" json:"paused,optional"` } func (m UserAgentBlockingRuleModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/user_agent_blocking_rule/resource.go b/internal/services/user_agent_blocking_rule/resource.go index ff013ef572..0f7c4e4343 100644 --- a/internal/services/user_agent_blocking_rule/resource.go +++ b/internal/services/user_agent_blocking_rule/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/firewall" "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*UserAgentBlockingRuleResource)(nil) var _ resource.ResourceWithModifyPlan = (*UserAgentBlockingRuleResource)(nil) +var _ resource.ResourceWithImportState = (*UserAgentBlockingRuleResource)(nil) func NewResource() resource.Resource { return &UserAgentBlockingRuleResource{} @@ -118,7 +121,7 @@ func (r *UserAgentBlockingRuleResource) Update(ctx context.Context, req resource env := UserAgentBlockingRuleResultEnvelope{*data} _, err = r.client.Firewall.UARules.Update( ctx, - data.UARuleID.ValueString(), + data.ID.ValueString(), firewall.UARuleUpdateParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -154,7 +157,7 @@ func (r *UserAgentBlockingRuleResource) Read(ctx context.Context, req resource.R env := UserAgentBlockingRuleResultEnvelope{*data} _, err := r.client.Firewall.UARules.Get( ctx, - data.UARuleID.ValueString(), + data.ID.ValueString(), firewall.UARuleGetParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -192,7 +195,7 @@ func (r *UserAgentBlockingRuleResource) Delete(ctx context.Context, req resource _, err := r.client.Firewall.UARules.Delete( ctx, - data.UARuleID.ValueString(), + data.ID.ValueString(), firewall.UARuleDeleteParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -206,6 +209,51 @@ func (r *UserAgentBlockingRuleResource) Delete(ctx context.Context, req resource resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } +func (r *UserAgentBlockingRuleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *UserAgentBlockingRuleModel = new(UserAgentBlockingRuleModel) + + path_zone_id := "" + path_ua_rule_id := "" + diags := importpath.ParseImportID( + req.ID, + "/", + &path_zone_id, + &path_ua_rule_id, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.ZoneID = types.StringValue(path_zone_id) + data.ID = types.StringValue(path_ua_rule_id) + + res := new(http.Response) + env := UserAgentBlockingRuleResultEnvelope{*data} + _, err := r.client.Firewall.UARules.Get( + ctx, + path_ua_rule_id, + firewall.UARuleGetParams{ + ZoneID: cloudflare.F(path_zone_id), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *UserAgentBlockingRuleResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { } diff --git a/internal/services/user_agent_blocking_rule/schema.go b/internal/services/user_agent_blocking_rule/schema.go index 1e147f6783..6d8de34c54 100644 --- a/internal/services/user_agent_blocking_rule/schema.go +++ b/internal/services/user_agent_blocking_rule/schema.go @@ -18,16 +18,16 @@ var _ resource.ResourceWithConfigValidators = (*UserAgentBlockingRuleResource)(n func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique identifier of the User Agent Blocking rule.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, "zone_id": schema.StringAttribute{ Description: "Defines an identifier.", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "ua_rule_id": schema.StringAttribute{ - Description: "The unique identifier of the User Agent Blocking rule.", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "mode": schema.StringAttribute{ Description: "The action to apply to a matched request.\nAvailable values: \"block\", \"challenge\", \"whitelist\", \"js_challenge\", \"managed_challenge\".", Required: true, @@ -57,6 +57,14 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "description": schema.StringAttribute{ + Description: "An informative summary of the rule. This value is sanitized and any tags will be removed.", + Optional: true, + }, + "paused": schema.BoolAttribute{ + Description: "When true, indicates that the rule is currently paused.", + Optional: true, + }, }, } } diff --git a/internal/services/zone_lockdown/schema.go b/internal/services/zone_lockdown/schema.go index 92640e74e1..33b6d008b4 100644 --- a/internal/services/zone_lockdown/schema.go +++ b/internal/services/zone_lockdown/schema.go @@ -33,7 +33,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, "description": schema.StringAttribute{ - Description: "An informative summary of the rate limit. This value is sanitized and any tags will be removed.", + Description: "An informative summary of the rule. This value is sanitized and any tags will be removed.", Optional: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, From b14c81b6020fe611ee5edee4df1baed96d9db108 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 12:38:55 +0000 Subject: [PATCH 165/187] feat(api): api update --- examples/resources/cloudflare_user_agent_blocking_rule/import.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 examples/resources/cloudflare_user_agent_blocking_rule/import.sh diff --git a/examples/resources/cloudflare_user_agent_blocking_rule/import.sh b/examples/resources/cloudflare_user_agent_blocking_rule/import.sh old mode 100644 new mode 100755 From c00b14379adc13dca2ea4cbdb836da0dbeebeb58 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 14:56:42 +0000 Subject: [PATCH 166/187] feat(api): api update --- .stats.yml | 4 ++-- .../bot_management/data_source_schema.go | 8 ++++++-- internal/services/bot_management/model.go | 20 +++++++++---------- internal/services/bot_management/schema.go | 18 +++++++++++++++-- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/.stats.yml b/.stats.yml index fbaed1d32c..06bb9eb0d3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-00c303ed3ff51e75fd30ab890a69ebbfde9bcb7c3a64397b081abfdd30c7b212.yml -openapi_spec_hash: 6886ec9a0f6960b8da8ef7309236eefb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fe53c8e1ba9040b0f7a669ede08f5e9c2a888661408036e7ea14b76ad713de49.yml +openapi_spec_hash: 5652d9793419b03cb9bba3883f6c2a92 config_hash: 284c4178d08f75d8c8b29f275948a8fd diff --git a/internal/services/bot_management/data_source_schema.go b/internal/services/bot_management/data_source_schema.go index 5276be083d..ecfc08233d 100644 --- a/internal/services/bot_management/data_source_schema.go +++ b/internal/services/bot_management/data_source_schema.go @@ -22,10 +22,14 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Required: true, }, "ai_bots_protection": schema.StringAttribute{ - Description: "Enable rule to block AI Scrapers and Crawlers.\nAvailable values: \"block\", \"disabled\".", + Description: "Enable rule to block AI Scrapers and Crawlers.\nAvailable values: \"block\", \"disabled\", \"only_on_ad_pages\".", Computed: true, Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive("block", "disabled"), + stringvalidator.OneOfCaseInsensitive( + "block", + "disabled", + "only_on_ad_pages", + ), }, }, "auto_update_model": schema.BoolAttribute{ diff --git a/internal/services/bot_management/model.go b/internal/services/bot_management/model.go index 54cf1717e9..7c8e91795e 100644 --- a/internal/services/bot_management/model.go +++ b/internal/services/bot_management/model.go @@ -15,16 +15,16 @@ type BotManagementResultEnvelope struct { type BotManagementModel struct { ID types.String `tfsdk:"id" json:"-,computed"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - AIBotsProtection types.String `tfsdk:"ai_bots_protection" json:"ai_bots_protection,optional"` - AutoUpdateModel types.Bool `tfsdk:"auto_update_model" json:"auto_update_model,optional"` - CrawlerProtection types.String `tfsdk:"crawler_protection" json:"crawler_protection,optional"` - EnableJS types.Bool `tfsdk:"enable_js" json:"enable_js,optional"` - FightMode types.Bool `tfsdk:"fight_mode" json:"fight_mode,optional"` - OptimizeWordpress types.Bool `tfsdk:"optimize_wordpress" json:"optimize_wordpress,optional"` - SBFMDefinitelyAutomated types.String `tfsdk:"sbfm_definitely_automated" json:"sbfm_definitely_automated,optional"` - SBFMLikelyAutomated types.String `tfsdk:"sbfm_likely_automated" json:"sbfm_likely_automated,optional"` - SBFMStaticResourceProtection types.Bool `tfsdk:"sbfm_static_resource_protection" json:"sbfm_static_resource_protection,optional"` - SBFMVerifiedBots types.String `tfsdk:"sbfm_verified_bots" json:"sbfm_verified_bots,optional"` + AIBotsProtection types.String `tfsdk:"ai_bots_protection" json:"ai_bots_protection,computed_optional"` + AutoUpdateModel types.Bool `tfsdk:"auto_update_model" json:"auto_update_model,computed_optional"` + CrawlerProtection types.String `tfsdk:"crawler_protection" json:"crawler_protection,computed_optional"` + EnableJS types.Bool `tfsdk:"enable_js" json:"enable_js,computed_optional"` + FightMode types.Bool `tfsdk:"fight_mode" json:"fight_mode,computed_optional"` + OptimizeWordpress types.Bool `tfsdk:"optimize_wordpress" json:"optimize_wordpress,computed_optional"` + SBFMDefinitelyAutomated types.String `tfsdk:"sbfm_definitely_automated" json:"sbfm_definitely_automated,computed_optional"` + SBFMLikelyAutomated types.String `tfsdk:"sbfm_likely_automated" json:"sbfm_likely_automated,computed_optional"` + SBFMStaticResourceProtection types.Bool `tfsdk:"sbfm_static_resource_protection" json:"sbfm_static_resource_protection,computed_optional"` + SBFMVerifiedBots types.String `tfsdk:"sbfm_verified_bots" json:"sbfm_verified_bots,computed_optional"` SuppressSessionScore types.Bool `tfsdk:"suppress_session_score" json:"suppress_session_score,computed_optional"` UsingLatestModel types.Bool `tfsdk:"using_latest_model" json:"using_latest_model,computed"` StaleZoneConfiguration customfield.NestedObject[BotManagementStaleZoneConfigurationModel] `tfsdk:"stale_zone_configuration" json:"stale_zone_configuration,computed"` diff --git a/internal/services/bot_management/schema.go b/internal/services/bot_management/schema.go index 095b324ce4..a8d3b16a6a 100644 --- a/internal/services/bot_management/schema.go +++ b/internal/services/bot_management/schema.go @@ -31,18 +31,25 @@ func ResourceSchema(ctx context.Context) schema.Schema { PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, }, "ai_bots_protection": schema.StringAttribute{ - Description: "Enable rule to block AI Scrapers and Crawlers.\nAvailable values: \"block\", \"disabled\".", + Description: "Enable rule to block AI Scrapers and Crawlers.\nAvailable values: \"block\", \"disabled\", \"only_on_ad_pages\".", + Computed: true, Optional: true, Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive("block", "disabled"), + stringvalidator.OneOfCaseInsensitive( + "block", + "disabled", + "only_on_ad_pages", + ), }, }, "auto_update_model": schema.BoolAttribute{ Description: "Automatically update to the newest bot detection models created by Cloudflare as they are released. [Learn more.](https://developers.cloudflare.com/bots/reference/machine-learning-models#model-versions-and-release-notes)", + Computed: true, Optional: true, }, "crawler_protection": schema.StringAttribute{ Description: "Enable rule to punish AI Scrapers and Crawlers via a link maze.\nAvailable values: \"enabled\", \"disabled\".", + Computed: true, Optional: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive("enabled", "disabled"), @@ -50,18 +57,22 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "enable_js": schema.BoolAttribute{ Description: "Use lightweight, invisible JavaScript detections to improve Bot Management. [Learn more about JavaScript Detections](https://developers.cloudflare.com/bots/reference/javascript-detections/).", + Computed: true, Optional: true, }, "fight_mode": schema.BoolAttribute{ Description: "Whether to enable Bot Fight Mode.", + Computed: true, Optional: true, }, "optimize_wordpress": schema.BoolAttribute{ Description: "Whether to optimize Super Bot Fight Mode protections for Wordpress.", + Computed: true, Optional: true, }, "sbfm_definitely_automated": schema.StringAttribute{ Description: "Super Bot Fight Mode (SBFM) action to take on definitely automated requests.\nAvailable values: \"allow\", \"block\", \"managed_challenge\".", + Computed: true, Optional: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive( @@ -73,6 +84,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "sbfm_likely_automated": schema.StringAttribute{ Description: "Super Bot Fight Mode (SBFM) action to take on likely automated requests.\nAvailable values: \"allow\", \"block\", \"managed_challenge\".", + Computed: true, Optional: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive( @@ -84,10 +96,12 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "sbfm_static_resource_protection": schema.BoolAttribute{ Description: "Super Bot Fight Mode (SBFM) to enable static resource protection.\nEnable if static resources on your application need bot protection.\nNote: Static resource protection can also result in legitimate traffic being blocked.", + Computed: true, Optional: true, }, "sbfm_verified_bots": schema.StringAttribute{ Description: "Super Bot Fight Mode (SBFM) action to take on verified bots requests.\nAvailable values: \"allow\", \"block\".", + Computed: true, Optional: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive("allow", "block"), From 7942b8af422fdb0d782eaf5a976ffc406b58f2f7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:46:41 +0000 Subject: [PATCH 167/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 06bb9eb0d3..29997a37be 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fe53c8e1ba9040b0f7a669ede08f5e9c2a888661408036e7ea14b76ad713de49.yml -openapi_spec_hash: 5652d9793419b03cb9bba3883f6c2a92 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3d3cbf5ec66167f9d4a0256b0157b7aa22a9e19c6df38dc69fe5ba9d545b8f7f.yml +openapi_spec_hash: 440056f075a5e6290e1d275b399dfdb8 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 16bed601794838563c231ca69cab0930b2403d82 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:07:41 +0000 Subject: [PATCH 168/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 29997a37be..eb9e1b7277 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-3d3cbf5ec66167f9d4a0256b0157b7aa22a9e19c6df38dc69fe5ba9d545b8f7f.yml -openapi_spec_hash: 440056f075a5e6290e1d275b399dfdb8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-2d8531090b44f32249e0eed01bb829c6e720593a78a2d02a551fab20cdd8ee20.yml +openapi_spec_hash: 6a479f8eb296f4049aaff05a951ee2eb config_hash: 284c4178d08f75d8c8b29f275948a8fd From 2f0c06d7de13f6abc42a648a70e06f0794e4e72b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:32:08 +0000 Subject: [PATCH 169/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index eb9e1b7277..3f7e003864 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-2d8531090b44f32249e0eed01bb829c6e720593a78a2d02a551fab20cdd8ee20.yml -openapi_spec_hash: 6a479f8eb296f4049aaff05a951ee2eb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0a7660a9125cd0eb5273d15f53de60d7ce676054089c6a0c297d086bb7eacd35.yml +openapi_spec_hash: f0c71ff66c24814cbca35d23b2e7f644 config_hash: 284c4178d08f75d8c8b29f275948a8fd From c03e8a1d614c52f25daf46b9f212e37745c533de Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 16:41:57 +0000 Subject: [PATCH 170/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3f7e003864..9c14e339d4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0a7660a9125cd0eb5273d15f53de60d7ce676054089c6a0c297d086bb7eacd35.yml -openapi_spec_hash: f0c71ff66c24814cbca35d23b2e7f644 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7b0e31b73481fdd677267f9a351a6e34b90594566f61eb273887fdfcf04c1830.yml +openapi_spec_hash: 423a55384fc788ed54721636851ee81d config_hash: 284c4178d08f75d8c8b29f275948a8fd From 12e42ea639ab7c83f152f9aec3f79a0be1a832e9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 17:27:49 +0000 Subject: [PATCH 171/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9c14e339d4..8252911943 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-7b0e31b73481fdd677267f9a351a6e34b90594566f61eb273887fdfcf04c1830.yml -openapi_spec_hash: 423a55384fc788ed54721636851ee81d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-583c4de47352785441e316de8134bcb10cb0b359b1f85de236d18bae8e185bd7.yml +openapi_spec_hash: f628190422f169e155747747116cc414 config_hash: 284c4178d08f75d8c8b29f275948a8fd From c49b29f2aca59c62b84432bfa296ca54aa94c68f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 17:39:19 +0000 Subject: [PATCH 172/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8252911943..914fbc2f2f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-583c4de47352785441e316de8134bcb10cb0b359b1f85de236d18bae8e185bd7.yml -openapi_spec_hash: f628190422f169e155747747116cc414 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0655902c1ad875fb19db63fc4f8c6704fae4967ca6b91ae482125884c174ed24.yml +openapi_spec_hash: bd789cc3f543fa2869a732b53f9398c0 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 1f9299770f86ad28746ff297c971d29352424229 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 20:10:13 +0000 Subject: [PATCH 173/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 914fbc2f2f..d1fcb81e0e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0655902c1ad875fb19db63fc4f8c6704fae4967ca6b91ae482125884c174ed24.yml -openapi_spec_hash: bd789cc3f543fa2869a732b53f9398c0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-abb65a4a263d4d85eb2903b7afcc3d8a376bdf85143d1ab9f05e0988db6ced90.yml +openapi_spec_hash: 5a134fafe63a192ef9c2f41f4b7ebed9 config_hash: 284c4178d08f75d8c8b29f275948a8fd From cdecaa8d6f0f6169cd8b4821ed8e8e31a86147ae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 20:58:45 +0000 Subject: [PATCH 174/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d1fcb81e0e..be3b6c8e22 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1752 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-abb65a4a263d4d85eb2903b7afcc3d8a376bdf85143d1ab9f05e0988db6ced90.yml -openapi_spec_hash: 5a134fafe63a192ef9c2f41f4b7ebed9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-33820eebc9530ec8e1c285a315f055d92e1f1b02db794934b6947616075562fd.yml +openapi_spec_hash: dd485200592659d406659d8d731779f5 config_hash: 284c4178d08f75d8c8b29f275948a8fd From 1b85a0dd554467df4cef3d7bf3ab923a0c33bc74 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 21:26:19 +0000 Subject: [PATCH 175/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index be3b6c8e22..1f73a6564a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 1752 +configured_endpoints: 1759 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-33820eebc9530ec8e1c285a315f055d92e1f1b02db794934b6947616075562fd.yml openapi_spec_hash: dd485200592659d406659d8d731779f5 -config_hash: 284c4178d08f75d8c8b29f275948a8fd +config_hash: 920bb1b417565d337cbdb7c39e77be5b From 2f3d879522083f412295447b85c9477cd3529c28 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 06:35:17 +0000 Subject: [PATCH 176/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1f73a6564a..6fa7b96a9d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1759 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-33820eebc9530ec8e1c285a315f055d92e1f1b02db794934b6947616075562fd.yml -openapi_spec_hash: dd485200592659d406659d8d731779f5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c74d75f6406242d4a1d91f9e6008f6a4b7d2a570447b6c4d17a52074c1e03e4c.yml +openapi_spec_hash: a48c7884808af06b2064c9c5b287979c config_hash: 920bb1b417565d337cbdb7c39e77be5b From b79a3ee035a0044667f37483ae743cddf30a4d83 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 08:57:46 +0000 Subject: [PATCH 177/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6fa7b96a9d..39f629f8e8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1759 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c74d75f6406242d4a1d91f9e6008f6a4b7d2a570447b6c4d17a52074c1e03e4c.yml -openapi_spec_hash: a48c7884808af06b2064c9c5b287979c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b911d4653c4d46d20e78d8bd5c2a97558f93520ef9896d2aae9c6ba90563d74c.yml +openapi_spec_hash: d78d3216f3e8a78a36757e260531d1d5 config_hash: 920bb1b417565d337cbdb7c39e77be5b From dab3b0010419ee34f05d81ec054193b80aea4d38 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 09:19:02 +0000 Subject: [PATCH 178/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 39f629f8e8..2db0b8c1cb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1759 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-b911d4653c4d46d20e78d8bd5c2a97558f93520ef9896d2aae9c6ba90563d74c.yml -openapi_spec_hash: d78d3216f3e8a78a36757e260531d1d5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bb4f00f35d216fc086f41a566a2008bf2d7665f18c9977f0c305df8aa50610f9.yml +openapi_spec_hash: 07db6ce298038f2c1688b7b2ee9f4c43 config_hash: 920bb1b417565d337cbdb7c39e77be5b From 51d27b1a0a1e4d3858ccf9b3dbc3976f9b3cf75b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 10:43:16 +0000 Subject: [PATCH 179/187] feat(api): api update --- .stats.yml | 4 ++-- examples/resources/cloudflare_image/resource.tf | 8 ++------ internal/services/image/model.go | 4 ++-- internal/services/image/schema.go | 16 ++++++++-------- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2db0b8c1cb..1c1b14cecd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1759 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bb4f00f35d216fc086f41a566a2008bf2d7665f18c9977f0c305df8aa50610f9.yml -openapi_spec_hash: 07db6ce298038f2c1688b7b2ee9f4c43 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9da40dd6e26c12cb5cc2621882e3a721c33102947241937aecf8b1cf1bfd1906.yml +openapi_spec_hash: 8e673d154552fd22c1291dc39644d664 config_hash: 920bb1b417565d337cbdb7c39e77be5b diff --git a/examples/resources/cloudflare_image/resource.tf b/examples/resources/cloudflare_image/resource.tf index 1c0a30ed7a..8486556b5e 100644 --- a/examples/resources/cloudflare_image/resource.tf +++ b/examples/resources/cloudflare_image/resource.tf @@ -1,11 +1,7 @@ resource "cloudflare_image" "example_image" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" - id = { - - } - file = { - - } + id = "id" + file = null metadata = { } diff --git a/internal/services/image/model.go b/internal/services/image/model.go index 2ca24fadf8..f07927e69e 100644 --- a/internal/services/image/model.go +++ b/internal/services/image/model.go @@ -18,10 +18,10 @@ type ImageResultEnvelope struct { } type ImageModel struct { - ID jsontypes.Normalized `tfsdk:"id" json:"id,required"` + ID types.String `tfsdk:"id" json:"id,required"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + File types.String `tfsdk:"file" json:"file,optional,no_refresh"` URL types.String `tfsdk:"url" json:"url,optional,no_refresh"` - File jsontypes.Normalized `tfsdk:"file" json:"file,optional,no_refresh"` Metadata jsontypes.Normalized `tfsdk:"metadata" json:"metadata,optional,no_refresh"` RequireSignedURLs types.Bool `tfsdk:"require_signed_urls" json:"requireSignedURLs,computed_optional"` Filename types.String `tfsdk:"filename" json:"filename,computed"` diff --git a/internal/services/image/schema.go b/internal/services/image/schema.go index a44c4a0587..c474520b14 100644 --- a/internal/services/image/schema.go +++ b/internal/services/image/schema.go @@ -22,25 +22,25 @@ func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Description: "An optional custom unique identifier for your image.", - Required: true, - CustomType: jsontypes.NormalizedType{}, + Description: "An optional custom unique identifier for your image.", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, }, "account_id": schema.StringAttribute{ Description: "Account identifier tag.", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, + "file": schema.StringAttribute{ + Description: "An image binary data. Only needed when type is uploading a file.", + Optional: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, "url": schema.StringAttribute{ Description: "A URL to fetch an image from origin. Only needed when type is uploading from a URL.", Optional: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "file": schema.StringAttribute{ - Description: "An image binary data. Only needed when type is uploading a file.", - Optional: true, - CustomType: jsontypes.NormalizedType{}, - }, "metadata": schema.StringAttribute{ Description: "User modifiable key-value store. Can use used for keeping references to another system of record for managing images.", Optional: true, From 761f333e071f300682a62e59f4caf8ac2bd70b1e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 10:45:57 +0000 Subject: [PATCH 180/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1c1b14cecd..511dac5557 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1759 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-9da40dd6e26c12cb5cc2621882e3a721c33102947241937aecf8b1cf1bfd1906.yml -openapi_spec_hash: 8e673d154552fd22c1291dc39644d664 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c3c5cb5abba2fdace82af1aa067daef34549bd71bc77c1a87094ad437585d728.yml +openapi_spec_hash: 0a2ad51009bc14a0c79c2b0d16512ff4 config_hash: 920bb1b417565d337cbdb7c39e77be5b From 48dab2a7da6952ddd1f8b617dc15f4ae4d81c081 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 11:27:47 +0000 Subject: [PATCH 181/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 511dac5557..a4a83a89e7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1759 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-c3c5cb5abba2fdace82af1aa067daef34549bd71bc77c1a87094ad437585d728.yml -openapi_spec_hash: 0a2ad51009bc14a0c79c2b0d16512ff4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-f8f9d2fc74cc4e5d448a399616ade4c32e3a1c06021a1c56c310a05ec1acc78e.yml +openapi_spec_hash: f9312bdf6d65d3010c60742469b6abe3 config_hash: 920bb1b417565d337cbdb7c39e77be5b From dec78592c61eb80318ebc4f7d32db24ac1943d39 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 12:00:55 +0000 Subject: [PATCH 182/187] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a4a83a89e7..e991ae6841 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1759 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-f8f9d2fc74cc4e5d448a399616ade4c32e3a1c06021a1c56c310a05ec1acc78e.yml -openapi_spec_hash: f9312bdf6d65d3010c60742469b6abe3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-2960e6379741ec36e2d9ce4951603341a209d327c23b8dd612059d5d54d6a462.yml +openapi_spec_hash: 20d3ceeadc6efd9590f482c695bf82ab config_hash: 920bb1b417565d337cbdb7c39e77be5b From b2b67b709c1e426bc74696dfeb09d86e94d31cfd Mon Sep 17 00:00:00 2001 From: Eduardo Gomes Date: Fri, 27 Jun 2025 11:25:13 +0200 Subject: [PATCH 183/187] AUTH-7323 Fix zero_trust_access_identity_provider resource --- .../model.go | 2 +- .../normalizations.go | 85 +++++++++++++++-- .../resource.go | 19 ++-- .../resource_test.go | 93 +++++++++++++++---- .../schema.go | 72 ++++++++++++++ .../testdata/accessidentityproviderazuread.tf | 7 +- .../testdata/accessidentityprovidersaml.tf | 11 ++- scripts/run-ci-acceptance-tests | 1 + 8 files changed, 243 insertions(+), 47 deletions(-) diff --git a/internal/services/zero_trust_access_identity_provider/model.go b/internal/services/zero_trust_access_identity_provider/model.go index d6e3f85c5c..a327308c2b 100644 --- a/internal/services/zero_trust_access_identity_provider/model.go +++ b/internal/services/zero_trust_access_identity_provider/model.go @@ -56,7 +56,7 @@ type ZeroTrustAccessIdentityProviderConfigModel struct { HeaderAttributes *[]*ZeroTrustAccessIdentityProviderConfigHeaderAttributesModel `tfsdk:"header_attributes" json:"header_attributes,optional"` IdPPublicCERTs *[]types.String `tfsdk:"idp_public_certs" json:"idp_public_certs,optional"` IssuerURL types.String `tfsdk:"issuer_url" json:"issuer_url,optional"` - SignRequest types.Bool `tfsdk:"sign_request" json:"sign_request,computed_optional"` + SignRequest types.Bool `tfsdk:"sign_request" json:"sign_request,optional"` SSOTargetURL types.String `tfsdk:"sso_target_url" json:"sso_target_url,optional"` RedirectURL types.String `tfsdk:"redirect_url" json:"redirect_url,computed"` } diff --git a/internal/services/zero_trust_access_identity_provider/normalizations.go b/internal/services/zero_trust_access_identity_provider/normalizations.go index 525968c023..fc45a6217c 100644 --- a/internal/services/zero_trust_access_identity_provider/normalizations.go +++ b/internal/services/zero_trust_access_identity_provider/normalizations.go @@ -2,17 +2,90 @@ package zero_trust_access_identity_provider import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) -func normalizeReadZeroTrustIDPData(ctx context.Context, apiValue *ZeroTrustAccessIdentityProviderModel, state *tfsdk.State) diag.Diagnostics { - var stateValue ZeroTrustAccessIdentityProviderModel +func normalizeFalseAndNullBool(data *basetypes.BoolValue, stateData basetypes.BoolValue) { + if data.ValueBool() || stateData.ValueBool() { + return + } + *data = stateData +} + +func normalizeReadZeroTrustIDPScimConfigData(ctx context.Context, dataValue, stateValue *customfield.NestedObject[ZeroTrustAccessIdentityProviderSCIMConfigModel]) diag.Diagnostics { + var ( + diags = make(diag.Diagnostics, 0) + dataScimConfig, stateScimConfig ZeroTrustAccessIdentityProviderSCIMConfigModel + ) + + diags.Append(dataValue.As(ctx, &dataScimConfig, basetypes.ObjectAsOptions{})...) + diags.Append(stateValue.As(ctx, &stateScimConfig, basetypes.ObjectAsOptions{})...) + if diags.HasError() { + return diags + } + + if !stateScimConfig.Secret.IsUnknown() && !stateScimConfig.Secret.IsNull() { + // Scim secret is only generated and returned in the create request, and null on reads. + // so we need to load it from the state + dataScimConfig.Secret = stateScimConfig.Secret + } + + *dataValue, diags = customfield.NewObject[ZeroTrustAccessIdentityProviderSCIMConfigModel](ctx, &dataScimConfig) + return diags +} + +func normalizeReadZeroTrustIDPConfigData(ctx context.Context, dataValue *ZeroTrustAccessIdentityProviderModel, stateValue ZeroTrustAccessIdentityProviderModel) diag.Diagnostics { + diag := make(diag.Diagnostics, 0) + if dataValue.Config == nil || stateValue.Config == nil { + return diag + } + + normalizeFalseAndNullBool(&dataValue.Config.SignRequest, stateValue.Config.SignRequest) + normalizeFalseAndNullBool(&dataValue.Config.ConditionalAccessEnabled, stateValue.Config.ConditionalAccessEnabled) + normalizeFalseAndNullBool(&dataValue.Config.SupportGroups, stateValue.Config.SupportGroups) + + return diag +} + +func normalizeReadZeroTrustIDPData(ctx context.Context, dataValue *ZeroTrustAccessIdentityProviderModel, state *tfsdk.State) diag.Diagnostics { + var ( + diags = make(diag.Diagnostics, 0) + stateValue ZeroTrustAccessIdentityProviderModel + ) d := state.Get(ctx, &stateValue) - if apiValue.Type.ValueString() == "azureAD" && - (apiValue.Config != nil && !apiValue.Config.ConditionalAccessEnabled.ValueBool()) && - (stateValue.Config != nil && !stateValue.Config.ConditionalAccessEnabled.ValueBool()) { - apiValue.Config.ConditionalAccessEnabled = stateValue.Config.ConditionalAccessEnabled + + diags.Append(normalizeReadZeroTrustIDPConfigData(ctx, dataValue, stateValue)...) + if diags.HasError() { + return diags + } + + // scim_config.secret is only returned when the app is first created, assigning here from the state + // to prevent a diff when the app is updated + if !dataValue.SCIMConfig.IsNull() && (!stateValue.SCIMConfig.IsNull() && !stateValue.SCIMConfig.IsUnknown()) { + diags.Append(normalizeReadZeroTrustIDPScimConfigData(ctx, &dataValue.SCIMConfig, &stateValue.SCIMConfig)...) + if diags.HasError() { + return diags + } } + return d } + +// Some fields are write-only sensitive and should not be stored in the state. +// Usually these secrets are injected in the config from a secret store. +func loadConfigSensitiveValuesForWriting(ctx context.Context, data *ZeroTrustAccessIdentityProviderModel, cfg *tfsdk.Config) diag.Diagnostics { + var ( + diags = make(diag.Diagnostics, 0) + cfgData *ZeroTrustAccessIdentityProviderModel + ) + diags.Append(cfg.Get(ctx, &cfgData)...) + + if data.Config != nil && cfgData.Config != nil { + data.Config.ClientSecret = cfgData.Config.ClientSecret + } + + return diags +} diff --git a/internal/services/zero_trust_access_identity_provider/resource.go b/internal/services/zero_trust_access_identity_provider/resource.go index bdcdf6ba1a..081b5c2cc4 100644 --- a/internal/services/zero_trust_access_identity_provider/resource.go +++ b/internal/services/zero_trust_access_identity_provider/resource.go @@ -59,16 +59,16 @@ func (r *ZeroTrustAccessIdentityProviderResource) Configure(ctx context.Context, func (r *ZeroTrustAccessIdentityProviderResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data *ZeroTrustAccessIdentityProviderModel - secret := types.StringNull() - req.Config.GetAttribute(ctx, path.Root("config").AtName("client_secret"), &secret) - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } - data.Config.ClientSecret = secret + resp.Diagnostics.Append(loadConfigSensitiveValuesForWriting(ctx, data, &req.Config)...) + if resp.Diagnostics.HasError() { + return + } dataBytes, err := data.MarshalJSON() if err != nil { @@ -103,15 +103,12 @@ func (r *ZeroTrustAccessIdentityProviderResource) Create(ctx context.Context, re return } data = &env.Result - data.Config.ClientSecret = types.StringNull() resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } func (r *ZeroTrustAccessIdentityProviderResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var data *ZeroTrustAccessIdentityProviderModel - secret := types.StringNull() - req.State.GetAttribute(ctx, path.Root("scim_config").AtName("secret"), &secret) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) @@ -162,10 +159,9 @@ func (r *ZeroTrustAccessIdentityProviderResource) Update(ctx context.Context, re } data = &env.Result + normalizeReadZeroTrustIDPData(ctx, data, &req.State) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - if !secret.IsNull() { - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("scim_config").AtName("secret"), secret)...) - } } func (r *ZeroTrustAccessIdentityProviderResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { @@ -304,6 +300,5 @@ func (r *ZeroTrustAccessIdentityProviderResource) ImportState(ctx context.Contex resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func (r *ZeroTrustAccessIdentityProviderResource) ModifyPlan(context.Context, resource.ModifyPlanRequest, *resource.ModifyPlanResponse) { - +func (r *ZeroTrustAccessIdentityProviderResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, res *resource.ModifyPlanResponse) { } diff --git a/internal/services/zero_trust_access_identity_provider/resource_test.go b/internal/services/zero_trust_access_identity_provider/resource_test.go index cbf4bf5e8f..57604b0718 100644 --- a/internal/services/zero_trust_access_identity_provider/resource_test.go +++ b/internal/services/zero_trust_access_identity_provider/resource_test.go @@ -87,6 +87,11 @@ func TestAccCloudflareAccessIdentityProvider_OneTimePin(t *testing.T) { }), ), }, + { + // Ensures no diff on last plan + Config: testAccCheckCloudflareAccessIdentityProviderOneTimePin(rnd, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, }, }) @@ -110,6 +115,11 @@ func TestAccCloudflareAccessIdentityProvider_OneTimePin(t *testing.T) { }), ), }, + { + // Ensures no diff on last plan + Config: testAccCheckCloudflareAccessIdentityProviderOneTimePin(rnd, cloudflare.ZoneIdentifier(zoneID)), + PlanOnly: true, + }, }, }) } @@ -133,9 +143,14 @@ func TestAccCloudflareAccessIdentityProvider_OAuth(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", rnd), resource.TestCheckResourceAttr(resourceName, "type", "github"), resource.TestCheckResourceAttr(resourceName, "config.client_id", "test"), - resource.TestCheckResourceAttrSet(resourceName, "config.client_secret"), + resource.TestCheckNoResourceAttr(resourceName, "config.client_secret"), ), }, + { + // Ensures no diff on last plan + Config: testAccCheckCloudflareAccessIdentityProviderOAuth(accountID, rnd), + PlanOnly: true, + }, }, }) } @@ -159,9 +174,14 @@ func TestAccCloudflareAccessIdentityProvider_OAuthWithUpdate(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", rnd), resource.TestCheckResourceAttr(resourceName, "type", "github"), resource.TestCheckResourceAttr(resourceName, "config.client_id", "test"), - resource.TestCheckResourceAttrSet(resourceName, "config.client_secret"), + resource.TestCheckNoResourceAttr(resourceName, "config.client_secret"), ), }, + { + // Ensures no diff on second plan + Config: testAccCheckCloudflareAccessIdentityProviderOAuth(accountID, rnd), + PlanOnly: true, + }, { Config: testAccCheckCloudflareAccessIdentityProviderOAuthUpdatedName(accountID, rnd), Check: resource.ComposeTestCheckFunc( @@ -169,9 +189,14 @@ func TestAccCloudflareAccessIdentityProvider_OAuthWithUpdate(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", rnd+"-updated"), resource.TestCheckResourceAttr(resourceName, "type", "github"), resource.TestCheckResourceAttr(resourceName, "config.client_id", "test"), - resource.TestCheckResourceAttrSet(resourceName, "config.client_secret"), + resource.TestCheckNoResourceAttr(resourceName, "config.client_secret"), ), }, + { + // Ensures no diff on last plan + Config: testAccCheckCloudflareAccessIdentityProviderOAuthUpdatedName(accountID, rnd), + PlanOnly: true, + }, }, }) } @@ -196,13 +221,17 @@ func TestAccCloudflareAccessIdentityProvider_SAML(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "type", "saml"), resource.TestCheckResourceAttr(resourceName, "config.issuer_url", "jumpcloud"), resource.TestCheckResourceAttr(resourceName, "config.sso_target_url", "https://sso.myexample.jumpcloud.com/saml2/cloudflareaccess"), - resource.TestCheckResourceAttr(resourceName, "config.sign_request", "false"), resource.TestCheckResourceAttr(resourceName, "config.attributes.#", "2"), resource.TestCheckResourceAttr(resourceName, "config.attributes.0", "email"), resource.TestCheckResourceAttr(resourceName, "config.attributes.1", "username"), resource.TestCheckResourceAttr(resourceName, "config.idp_public_certs.#", "1"), ), }, + { + // Ensures no diff on last plan + Config: testAccCheckCloudflareAccessIdentityProviderSAML(accountID, rnd), + PlanOnly: true, + }, }, }) } @@ -229,13 +258,16 @@ func TestAccCloudflareAccessIdentityProvider_AzureAD(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "type", "azureAD"), resource.TestCheckResourceAttr(resourceName, "config.client_id", "test"), resource.TestCheckResourceAttr(resourceName, "config.directory_id", "directory"), - resource.TestCheckResourceAttr(resourceName, "config.condtional_access_enabled", "true"), resource.TestCheckResourceAttr(resourceName, "scim_config.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "scim_config.user_deprovision", "true"), resource.TestCheckResourceAttr(resourceName, "scim_config.seat_deprovision", "true"), - resource.TestCheckResourceAttr(resourceName, "scim_config.group_member_deprovision", "true"), ), }, + { + // Ensures no diff on last plan + Config: testAccCheckCloudflareAccessIdentityProviderAzureAD(accountID, rnd), + PlanOnly: true, + }, }, }) } @@ -251,7 +283,7 @@ func TestAccCloudflareAccessIdentityProvider_OAuth_Import(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", rnd), resource.TestCheckResourceAttr(resourceName, "type", "github"), resource.TestCheckResourceAttr(resourceName, "config.client_id", "test"), - resource.TestCheckResourceAttrSet(resourceName, "config.client_secret"), + resource.TestCheckNoResourceAttr(resourceName, "config.client_secret"), ) resource.Test(t, resource.TestCase{ @@ -265,13 +297,18 @@ func TestAccCloudflareAccessIdentityProvider_OAuth_Import(t *testing.T) { Config: testAccCheckCloudflareAccessIdentityProviderOAuth(accountID, rnd), Check: checkFn, }, - // { - // ImportState: true, - // ImportStateVerify: true, - // ResourceName: resourceName, - // ImportStateIdPrefix: fmt.Sprintf("%s/", accountID), - // Check: checkFn, - // }, + { + // Ensures no diff on second plan + Config: testAccCheckCloudflareAccessIdentityProviderOAuth(accountID, rnd), + PlanOnly: true, + }, + { + ImportState: true, + ImportStateVerify: true, + ResourceName: resourceName, + ImportStateIdPrefix: fmt.Sprintf("accounts/%s/", accountID), + Check: checkFn, + }, }, }) } @@ -303,10 +340,20 @@ func TestAccCloudflareAccessIdentityProvider_SCIM_Config_Secret(t *testing.T) { Config: testAccCheckCloudflareAccessIdentityProviderAzureAD(accountID, rnd), Check: checkFn, }, + { + // Ensures no diff on second plan + Config: testAccCheckCloudflareAccessIdentityProviderAzureAD(accountID, rnd), + PlanOnly: true, + }, { Config: testAccCheckCloudflareAccessIdentityProviderAzureADUpdated(accountID, rnd), Check: checkFn, }, + { + // Ensures no diff on last plan + Config: testAccCheckCloudflareAccessIdentityProviderAzureADUpdated(accountID, rnd), + PlanOnly: true, + }, }, }) } @@ -322,11 +369,6 @@ func TestAccCloudflareAccessIdentityProvider_SCIM_Secret_Enabled_After_Resource_ if value == "" { return errors.New("secret is empty") } - - // if strings.Contains(value, "*") { - // return errors.New("secret was redacted") - // } - return nil }), ) @@ -344,14 +386,27 @@ func TestAccCloudflareAccessIdentityProvider_SCIM_Secret_Enabled_After_Resource_ resource.TestCheckNoResourceAttr(resourceName, "scim_config.secret"), ), }, + { + Config: testAccCheckCloudflareAccessIdentityProviderAzureADNoSCIM(accountID, rnd), + PlanOnly: true, + }, { Config: testAccCheckCloudflareAccessIdentityProviderAzureAD(accountID, rnd), Check: checkFn, }, + { + Config: testAccCheckCloudflareAccessIdentityProviderAzureAD(accountID, rnd), + PlanOnly: true, + }, { Config: testAccCheckCloudflareAccessIdentityProviderAzureADUpdated(accountID, rnd), Check: checkFn, }, + { + // Ensures no diff on last plan + Config: testAccCheckCloudflareAccessIdentityProviderAzureADUpdated(accountID, rnd), + PlanOnly: true, + }, }, }) } diff --git a/internal/services/zero_trust_access_identity_provider/schema.go b/internal/services/zero_trust_access_identity_provider/schema.go index fec6b1ade8..83e262c21b 100644 --- a/internal/services/zero_trust_access_identity_provider/schema.go +++ b/internal/services/zero_trust_access_identity_provider/schema.go @@ -4,6 +4,8 @@ package zero_trust_access_identity_provider import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" @@ -88,10 +90,16 @@ func ResourceSchema(ctx context.Context) schema.Schema { "conditional_access_enabled": schema.BoolAttribute{ Description: "Should Cloudflare try to load authentication contexts from your account", Optional: true, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "azureAD"), + }, }, "directory_id": schema.StringAttribute{ Description: "Your Azure directory uuid", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "azureAD"), + }, }, "email_claim_name": schema.StringAttribute{ Description: "The claim name for email in the id_token response.", @@ -106,31 +114,50 @@ func ResourceSchema(ctx context.Context) schema.Schema { "select_account", "none", ), + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "azureAD"), }, }, "support_groups": schema.BoolAttribute{ Description: "Should Cloudflare try to load groups from your account", Optional: true, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "azureAD"), + }, }, "centrify_account": schema.StringAttribute{ Description: "Your centrify account url", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "centrify"), + }, }, "centrify_app_id": schema.StringAttribute{ Description: "Your centrify app id", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "centrify"), + }, }, "apps_domain": schema.StringAttribute{ Description: "Your companies TLD", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "google-apps"), + }, }, "auth_url": schema.StringAttribute{ Description: "The authorization_endpoint URL of your IdP", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "oidc"), + }, }, "certs_url": schema.StringAttribute{ Description: "The jwks_uri endpoint of your IdP to allow the IdP keys to sign the tokens", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "oidc"), + }, }, "pkce_enabled": schema.BoolAttribute{ Description: "Enable Proof Key for Code Exchange (PKCE)", @@ -140,39 +167,66 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "OAuth scopes", Optional: true, ElementType: types.StringType, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "oidc"), + }, }, "token_url": schema.StringAttribute{ Description: "The token_endpoint URL of your IdP", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "oidc"), + }, }, "authorization_server_id": schema.StringAttribute{ Description: "Your okta authorization server id", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "okta"), + }, }, "okta_account": schema.StringAttribute{ Description: "Your okta account url", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "okta"), + }, }, "onelogin_account": schema.StringAttribute{ Description: "Your OneLogin account url", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "onelogin"), + }, }, "ping_env_id": schema.StringAttribute{ Description: "Your PingOne environment identifier", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "pingone"), + }, }, "attributes": schema.ListAttribute{ Description: "A list of SAML attribute names that will be added to your signed JWT token and can be used in SAML policy rules.", Optional: true, ElementType: types.StringType, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "saml"), + }, }, "email_attribute_name": schema.StringAttribute{ Description: "The attribute name for email in the SAML response.", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "saml"), + }, }, "header_attributes": schema.ListNestedAttribute{ Description: "Add a list of attribute names that will be returned in the response header from the Access callback.", Optional: true, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "saml"), + }, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "attribute_name": schema.StringAttribute{ @@ -190,23 +244,38 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "X509 certificate to verify the signature in the SAML authentication response", Optional: true, ElementType: types.StringType, + Validators: []validator.List{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "saml"), + }, }, "issuer_url": schema.StringAttribute{ Description: "IdP Entity ID or Issuer URL", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "saml"), + }, }, "sign_request": schema.BoolAttribute{ Description: "Sign the SAML authentication request with Access credentials. To verify the signature, use the public key from the Access certs endpoints.", Optional: true, PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()}, + Validators: []validator.Bool{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "saml"), + }, }, "sso_target_url": schema.StringAttribute{ Description: "URL to send the SAML authentication requests to", Optional: true, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "saml"), + }, }, "redirect_url": schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + Validators: []validator.String{ + customvalidator.RequiresOtherStringAttributeToBeOneOf(path.MatchRoot("type"), "saml"), + }, }, }, }, @@ -252,6 +321,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "A read-only token generated when the SCIM integration is enabled for the first time. It is redacted on subsequent requests. If you lose this you will need to refresh it at /access/identity_providers/:idpID/refresh_scim_secret.", Computed: true, Sensitive: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "user_deprovision": schema.BoolAttribute{ Description: "A flag to enable revoking a user's session in Access and Gateway when they have been deprovisioned in the Identity Provider.", diff --git a/internal/services/zero_trust_access_identity_provider/testdata/accessidentityproviderazuread.tf b/internal/services/zero_trust_access_identity_provider/testdata/accessidentityproviderazuread.tf index 14cc96add3..69214fafaf 100644 --- a/internal/services/zero_trust_access_identity_provider/testdata/accessidentityproviderazuread.tf +++ b/internal/services/zero_trust_access_identity_provider/testdata/accessidentityproviderazuread.tf @@ -9,9 +9,8 @@ resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" { support_groups = true } scim_config = { - enabled = true - group_member_deprovision = true - seat_deprovision = true - user_deprovision = true + enabled = true + seat_deprovision = true + user_deprovision = true } } diff --git a/internal/services/zero_trust_access_identity_provider/testdata/accessidentityprovidersaml.tf b/internal/services/zero_trust_access_identity_provider/testdata/accessidentityprovidersaml.tf index 5ff44525ac..f92dbbaeb3 100644 --- a/internal/services/zero_trust_access_identity_provider/testdata/accessidentityprovidersaml.tf +++ b/internal/services/zero_trust_access_identity_provider/testdata/accessidentityprovidersaml.tf @@ -4,10 +4,11 @@ resource "cloudflare_zero_trust_access_identity_provider" "%[2]s" { name = "%[2]s" type = "saml" config = { - issuer_url = "jumpcloud" + issuer_url = "jumpcloud" sso_target_url = "https://sso.myexample.jumpcloud.com/saml2/cloudflareaccess" - attributes = [ "email", "username" ] - sign_request = false - idp_public_certs = ["MIIDpDCCAoygAwIBAgIGAV2ka+55MA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEG\nA1UEC…..GF/Q2/MHadws97cZg\nuTnQyuOqPuHbnN83d/2l1NSYKCbHt24o"] -} + attributes = ["email", "username"] + idp_public_certs = [ + "MIIDpDCCAoygAwIBAgIGAV2ka+55MA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEG\nA1UEC…..GF/Q2/MHadws97cZg\nuTnQyuOqPuHbnN83d/2l1NSYKCbHt24o" + ] + } } diff --git a/scripts/run-ci-acceptance-tests b/scripts/run-ci-acceptance-tests index b90ce483c7..bf8d6d22cc 100755 --- a/scripts/run-ci-acceptance-tests +++ b/scripts/run-ci-acceptance-tests @@ -114,6 +114,7 @@ go test -run "^TestAcc" -count 1 \ ./internal/services/workers_script \ ./internal/services/workers_script_subdomain \ ./internal/services/zero_trust_access_application \ + ./internal/services/zero_trust_access_identity_provider \ ./internal/services/zero_trust_access_infrastructure_target \ ./internal/services/zero_trust_access_key_configuration \ ./internal/services/zero_trust_access_mtls_hostname_settings \ From d3c25aad0156ba337116f7cccbcbd0261099fb87 Mon Sep 17 00:00:00 2001 From: Eduardo Gomes Date: Fri, 27 Jun 2025 17:22:41 +0200 Subject: [PATCH 184/187] AUTH-7350 Fix zero-trust-access policies and groups --- .../object_size_at_most_validator.go | 53 +++++ .../zero_trust_access_application/schema.go | 9 + .../services/zero_trust_access_group/model.go | 3 - .../zero_trust_access_group/normalizations.go | 30 +++ .../zero_trust_access_group/resource.go | 16 ++ .../zero_trust_access_group/resource_test.go | 194 +++++++++++++----- .../zero_trust_access_group/schema.go | 20 +- .../testdata/accessgroupconfigbasic.tf | 83 ++++---- .../testdata/accessgroupconfigexclude.tf | 22 +- .../testdata/accessgroupconfigfullconfig.tf | 20 +- .../testdata/accessgroupconfigrequire.tf | 22 +- .../zero_trust_access_policy/model.go | 30 ++- .../normalizations.go | 30 +++ .../zero_trust_access_policy/resource.go | 15 ++ .../zero_trust_access_policy/resource_test.go | 73 +++++++ .../zero_trust_access_policy/schema.go | 28 +-- scripts/run-ci-acceptance-tests | 2 + 17 files changed, 497 insertions(+), 153 deletions(-) create mode 100644 internal/customvalidator/object_size_at_most_validator.go create mode 100644 internal/services/zero_trust_access_group/normalizations.go create mode 100644 internal/services/zero_trust_access_policy/normalizations.go diff --git a/internal/customvalidator/object_size_at_most_validator.go b/internal/customvalidator/object_size_at_most_validator.go new file mode 100644 index 0000000000..23eef366f5 --- /dev/null +++ b/internal/customvalidator/object_size_at_most_validator.go @@ -0,0 +1,53 @@ +package customvalidator + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +type objectSizeAtMostValidator struct { + max int +} + +func (v objectSizeAtMostValidator) Description(_ context.Context) string { + return fmt.Sprintf("must contain at most %d elements", v.max) +} + +func (v objectSizeAtMostValidator) MarkdownDescription(ctx context.Context) string { + return v.Description(ctx) +} + +func (v objectSizeAtMostValidator) ValidateObject(ctx context.Context, req validator.ObjectRequest, resp *validator.ObjectResponse) { + if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() { + return + } + + nonNullCount := 0 + for _, attr := range req.ConfigValue.Attributes() { + if !attr.IsNull() && !attr.IsUnknown() { + nonNullCount++ + } + } + if nonNullCount > v.max { + resp.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( + req.Path, + v.Description(ctx), + fmt.Sprintf("%d", nonNullCount), + )) + } +} + +// ObjectSizeAtMost returns an AttributeValidator which ensures that any configured +// attribute or function parameter value: +// +// - Is an object. +// - Contains at most max elements. +// +// Null (unconfigured) and unknown (known after apply) values are skipped. +func ObjectSizeAtMost(maxVal int) objectSizeAtMostValidator { + return objectSizeAtMostValidator{ + max: maxVal, + } +} diff --git a/internal/services/zero_trust_access_application/schema.go b/internal/services/zero_trust_access_application/schema.go index 622979df55..c0bad05762 100644 --- a/internal/services/zero_trust_access_application/schema.go +++ b/internal/services/zero_trust_access_application/schema.go @@ -603,6 +603,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesIncludeModel](ctx), NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, @@ -871,6 +874,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesExcludeModel](ctx), NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, @@ -1108,6 +1114,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationPoliciesRequireModel](ctx), NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, diff --git a/internal/services/zero_trust_access_group/model.go b/internal/services/zero_trust_access_group/model.go index a5cf659a5e..85db544664 100644 --- a/internal/services/zero_trust_access_group/model.go +++ b/internal/services/zero_trust_access_group/model.go @@ -4,7 +4,6 @@ package zero_trust_access_group import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" - "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -21,8 +20,6 @@ type ZeroTrustAccessGroupModel struct { IsDefault types.Bool `tfsdk:"is_default" json:"is_default,optional,no_refresh"` Exclude *[]*ZeroTrustAccessGroupExcludeModel `tfsdk:"exclude" json:"exclude,optional"` Require *[]*ZeroTrustAccessGroupRequireModel `tfsdk:"require" json:"require,optional"` - CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` - UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` } func (m ZeroTrustAccessGroupModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/zero_trust_access_group/normalizations.go b/internal/services/zero_trust_access_group/normalizations.go new file mode 100644 index 0000000000..b15db1c1d0 --- /dev/null +++ b/internal/services/zero_trust_access_group/normalizations.go @@ -0,0 +1,30 @@ +package zero_trust_access_group + +import ( + "context" + "github.com/hashicorp/terraform-plugin-framework/diag" +) + +type IsNull interface { + IsNull() bool +} + +func normalizeEmptyAndNullSlice[T any](data **[]T, stateData *[]T) { + if (*data != nil && len(**data) != 0) || (stateData != nil && len(*stateData) != 0) { + return + } + *data = stateData +} + +// Normalizing function to ensure consistency between the state/plan and the meaning of the API response. +// Alters the API response before applying it to the state by laxing equalities between null & zero-value +// for some attributes, and nullifies fields that terraform should not be saving in the state. +func normalizeReadZeroTrustAccessGroupAPIData(ctx context.Context, data, sourceData *ZeroTrustAccessGroupModel) diag.Diagnostics { + diags := make(diag.Diagnostics, 0) + + normalizeEmptyAndNullSlice(&data.Include, sourceData.Include) + normalizeEmptyAndNullSlice(&data.Require, sourceData.Require) + normalizeEmptyAndNullSlice(&data.Exclude, sourceData.Exclude) + + return diags +} diff --git a/internal/services/zero_trust_access_group/resource.go b/internal/services/zero_trust_access_group/resource.go index 38437608d8..d9ea814c8b 100644 --- a/internal/services/zero_trust_access_group/resource.go +++ b/internal/services/zero_trust_access_group/resource.go @@ -153,6 +153,14 @@ func (r *ZeroTrustAccessGroupResource) Update(ctx context.Context, req resource. } data = &env.Result + var planData *ZeroTrustAccessGroupModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(normalizeReadZeroTrustAccessGroupAPIData(ctx, data, planData)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -199,6 +207,14 @@ func (r *ZeroTrustAccessGroupResource) Read(ctx context.Context, req resource.Re } data = &env.Result + var stateData *ZeroTrustAccessGroupModel + resp.Diagnostics.Append(req.State.Get(ctx, &stateData)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(normalizeReadZeroTrustAccessGroupAPIData(ctx, data, stateData)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } diff --git a/internal/services/zero_trust_access_group/resource_test.go b/internal/services/zero_trust_access_group/resource_test.go index 2654211ed1..17b594b893 100644 --- a/internal/services/zero_trust_access_group/resource_test.go +++ b/internal/services/zero_trust_access_group/resource_test.go @@ -95,30 +95,60 @@ func TestAccCloudflareAccessGroup_ConfigBasicAccount(t *testing.T) { testAccCheckCloudflareAccessGroupExists(name, cloudflare.AccountIdentifier(accountID), &accessGroup), resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), resource.TestCheckResourceAttr(name, "name", rnd), - resource.TestCheckResourceAttr(name, "include.0.email.email", email), - resource.TestCheckResourceAttr(name, "include.0.email_domain.domain", "example.com"), - resource.TestCheckResourceAttrSet(name, "include.0.any_valid_service_token.%"), - resource.TestCheckResourceAttr(name, "include.0.ip.ip", "192.0.2.1/32"), - resource.TestCheckResourceAttr(name, "include.1.ip.ip", "192.0.2.2/32"), - resource.TestCheckResourceAttr(name, "include.0.ip_list.id", "e3a0f205-c525-4e48-a293-ba5d1f00e638"), - resource.TestCheckResourceAttr(name, "include.1.ip_list.id", "5d54cd30-ce52-46e4-9a46-a47887e1a167"), + resource.TestCheckResourceAttr(name, "include.0.any_valid_service_token.%", "0"), + resource.TestCheckResourceAttr(name, "include.1.email.email", email), + resource.TestCheckResourceAttr(name, "include.2.email_domain.domain", "example.com"), + resource.TestCheckResourceAttr(name, "include.3.ip.ip", "192.0.2.1/32"), + resource.TestCheckResourceAttr(name, "include.4.ip_list.id", "e3a0f205-c525-4e48-a293-ba5d1f00e638"), + resource.TestCheckResourceAttr(name, "include.5.saml.attribute_name", "Name1"), + resource.TestCheckResourceAttr(name, "include.5.saml.attribute_value", "Value1"), + resource.TestCheckResourceAttr(name, "include.5.saml.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.6.azure_ad.id", "group1"), + resource.TestCheckResourceAttr(name, "include.6.azure_ad.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.7.ip.ip", "192.0.2.2/32"), + resource.TestCheckResourceAttr(name, "include.8.ip_list.id", "5d54cd30-ce52-46e4-9a46-a47887e1a167"), + resource.TestCheckResourceAttr(name, "include.9.saml.attribute_name", "Name2"), + resource.TestCheckResourceAttr(name, "include.9.saml.attribute_value", "Value2"), + resource.TestCheckResourceAttr(name, "include.9.saml.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.10.azure_ad.id", "group2"), + resource.TestCheckResourceAttr(name, "include.10.azure_ad.identity_provider_id", "5678"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigBasic(rnd, email, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, { Config: testAccCloudflareAccessGroupConfigBasic(rnd, email, cloudflare.AccountIdentifier(accountID)), Check: resource.ComposeTestCheckFunc( testAccCheckCloudflareAccessGroupExists(name, cloudflare.AccountIdentifier(accountID), &accessGroup), resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), resource.TestCheckResourceAttr(name, "name", rnd), - resource.TestCheckResourceAttr(name, "include.0.email.email", email), - resource.TestCheckResourceAttr(name, "include.0.email_domain.domain", "example.com"), - resource.TestCheckResourceAttrSet(name, "include.0.any_valid_service_token.%"), - resource.TestCheckResourceAttr(name, "include.0.ip.ip", "192.0.2.1/32"), - resource.TestCheckResourceAttr(name, "include.1.ip.ip", "192.0.2.2/32"), - resource.TestCheckResourceAttr(name, "include.0.ip_list.id", "e3a0f205-c525-4e48-a293-ba5d1f00e638"), - resource.TestCheckResourceAttr(name, "include.1.ip_list.id", "5d54cd30-ce52-46e4-9a46-a47887e1a167"), + resource.TestCheckResourceAttr(name, "include.0.any_valid_service_token.%", "0"), + resource.TestCheckResourceAttr(name, "include.1.email.email", email), + resource.TestCheckResourceAttr(name, "include.2.email_domain.domain", "example.com"), + resource.TestCheckResourceAttr(name, "include.3.ip.ip", "192.0.2.1/32"), + resource.TestCheckResourceAttr(name, "include.4.ip_list.id", "e3a0f205-c525-4e48-a293-ba5d1f00e638"), + resource.TestCheckResourceAttr(name, "include.5.saml.attribute_name", "Name1"), + resource.TestCheckResourceAttr(name, "include.5.saml.attribute_value", "Value1"), + resource.TestCheckResourceAttr(name, "include.5.saml.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.6.azure_ad.id", "group1"), + resource.TestCheckResourceAttr(name, "include.6.azure_ad.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.7.ip.ip", "192.0.2.2/32"), + resource.TestCheckResourceAttr(name, "include.8.ip_list.id", "5d54cd30-ce52-46e4-9a46-a47887e1a167"), + resource.TestCheckResourceAttr(name, "include.9.saml.attribute_name", "Name2"), + resource.TestCheckResourceAttr(name, "include.9.saml.attribute_value", "Value2"), + resource.TestCheckResourceAttr(name, "include.9.saml.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.10.azure_ad.id", "group2"), + resource.TestCheckResourceAttr(name, "include.10.azure_ad.identity_provider_id", "5678"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigBasic(rnd, email, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, }, }) } @@ -140,46 +170,60 @@ func TestAccCloudflareAccessGroup_ConfigBasicZone(t *testing.T) { testAccCheckCloudflareAccessGroupExists(name, cloudflare.ZoneIdentifier(zoneID), &accessGroup), resource.TestCheckResourceAttr(name, consts.ZoneIDSchemaKey, zoneID), resource.TestCheckResourceAttr(name, "name", rnd), - resource.TestCheckResourceAttr(name, "include.0.email.email", email), - resource.TestCheckResourceAttr(name, "include.0.email_domain.domain", "example.com"), - resource.TestCheckResourceAttrSet(name, "include.0.any_valid_service_token.%"), - resource.TestCheckResourceAttr(name, "include.0.ip.ip", "192.0.2.1/32"), - resource.TestCheckResourceAttr(name, "include.1.ip.ip", "192.0.2.2/32"), - resource.TestCheckResourceAttr(name, "include.0.ip_list.id", "e3a0f205-c525-4e48-a293-ba5d1f00e638"), - resource.TestCheckResourceAttr(name, "include.1.ip_list.id", "5d54cd30-ce52-46e4-9a46-a47887e1a167"), - resource.TestCheckResourceAttr(name, "include.0.saml.attribute_name", "Name1"), - resource.TestCheckResourceAttr(name, "include.0.saml.attribute_value", "Value1"), - resource.TestCheckResourceAttr(name, "include.1.saml.attribute_name", "Name2"), - resource.TestCheckResourceAttr(name, "include.1.saml.attribute_value", "Value2"), - resource.TestCheckResourceAttr(name, "include.0.azure_ad.id", "group1"), - resource.TestCheckResourceAttr(name, "include.0.azure_ad.identity_provider_id", "1234"), - resource.TestCheckResourceAttr(name, "include.1.azure_ad.id", "group2"), - resource.TestCheckResourceAttr(name, "include.1.azure_ad.identity_provider_id", "5678"), + resource.TestCheckResourceAttr(name, "include.0.any_valid_service_token.%", "0"), + resource.TestCheckResourceAttr(name, "include.1.email.email", email), + resource.TestCheckResourceAttr(name, "include.2.email_domain.domain", "example.com"), + resource.TestCheckResourceAttr(name, "include.3.ip.ip", "192.0.2.1/32"), + resource.TestCheckResourceAttr(name, "include.4.ip_list.id", "e3a0f205-c525-4e48-a293-ba5d1f00e638"), + resource.TestCheckResourceAttr(name, "include.5.saml.attribute_name", "Name1"), + resource.TestCheckResourceAttr(name, "include.5.saml.attribute_value", "Value1"), + resource.TestCheckResourceAttr(name, "include.5.saml.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.6.azure_ad.id", "group1"), + resource.TestCheckResourceAttr(name, "include.6.azure_ad.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.7.ip.ip", "192.0.2.2/32"), + resource.TestCheckResourceAttr(name, "include.8.ip_list.id", "5d54cd30-ce52-46e4-9a46-a47887e1a167"), + resource.TestCheckResourceAttr(name, "include.9.saml.attribute_name", "Name2"), + resource.TestCheckResourceAttr(name, "include.9.saml.attribute_value", "Value2"), + resource.TestCheckResourceAttr(name, "include.9.saml.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.10.azure_ad.id", "group2"), + resource.TestCheckResourceAttr(name, "include.10.azure_ad.identity_provider_id", "5678"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigBasic(rnd, email, cloudflare.ZoneIdentifier(zoneID)), + PlanOnly: true, + }, { Config: testAccCloudflareAccessGroupConfigBasic(rnd, email, cloudflare.ZoneIdentifier(zoneID)), Check: resource.ComposeTestCheckFunc( testAccCheckCloudflareAccessGroupExists(name, cloudflare.ZoneIdentifier(zoneID), &accessGroup), resource.TestCheckResourceAttr(name, consts.ZoneIDSchemaKey, zoneID), resource.TestCheckResourceAttr(name, "name", rnd), - resource.TestCheckResourceAttr(name, "include.0.email.email", email), - resource.TestCheckResourceAttr(name, "include.0.email_domain.domain", "example.com"), - resource.TestCheckResourceAttrSet(name, "include.0.any_valid_service_token.%"), - resource.TestCheckResourceAttr(name, "include.0.ip.ip", "192.0.2.1/32"), - resource.TestCheckResourceAttr(name, "include.1.ip.ip", "192.0.2.2/32"), - resource.TestCheckResourceAttr(name, "include.0.ip_list.id", "e3a0f205-c525-4e48-a293-ba5d1f00e638"), - resource.TestCheckResourceAttr(name, "include.1.ip_list.id", "5d54cd30-ce52-46e4-9a46-a47887e1a167"), - resource.TestCheckResourceAttr(name, "include.0.saml.attribute_name", "Name1"), - resource.TestCheckResourceAttr(name, "include.0.saml.attribute_value", "Value1"), - resource.TestCheckResourceAttr(name, "include.1.saml.attribute_name", "Name2"), - resource.TestCheckResourceAttr(name, "include.1.saml.attribute_value", "Value2"), - resource.TestCheckResourceAttr(name, "include.0.azure_ad.id", "group1"), - resource.TestCheckResourceAttr(name, "include.0.azure_ad.identity_provider_id", "1234"), - resource.TestCheckResourceAttr(name, "include.1.azure_ad.id", "group2"), - resource.TestCheckResourceAttr(name, "include.1.azure_ad.identity_provider_id", "5678"), + resource.TestCheckResourceAttr(name, "include.0.any_valid_service_token.%", "0"), + resource.TestCheckResourceAttr(name, "include.1.email.email", email), + resource.TestCheckResourceAttr(name, "include.2.email_domain.domain", "example.com"), + resource.TestCheckResourceAttr(name, "include.3.ip.ip", "192.0.2.1/32"), + resource.TestCheckResourceAttr(name, "include.4.ip_list.id", "e3a0f205-c525-4e48-a293-ba5d1f00e638"), + resource.TestCheckResourceAttr(name, "include.5.saml.attribute_name", "Name1"), + resource.TestCheckResourceAttr(name, "include.5.saml.attribute_value", "Value1"), + resource.TestCheckResourceAttr(name, "include.5.saml.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.6.azure_ad.id", "group1"), + resource.TestCheckResourceAttr(name, "include.6.azure_ad.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.7.ip.ip", "192.0.2.2/32"), + resource.TestCheckResourceAttr(name, "include.8.ip_list.id", "5d54cd30-ce52-46e4-9a46-a47887e1a167"), + resource.TestCheckResourceAttr(name, "include.9.saml.attribute_name", "Name2"), + resource.TestCheckResourceAttr(name, "include.9.saml.attribute_value", "Value2"), + resource.TestCheckResourceAttr(name, "include.9.saml.identity_provider_id", "1234"), + resource.TestCheckResourceAttr(name, "include.10.azure_ad.id", "group2"), + resource.TestCheckResourceAttr(name, "include.10.azure_ad.identity_provider_id", "5678"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigBasic(rnd, email, cloudflare.ZoneIdentifier(zoneID)), + PlanOnly: true, + }, }, }) } @@ -211,6 +255,11 @@ func TestAccCloudflareAccessGroup_ConfigEmailList(t *testing.T) { resource.TestCheckResourceAttr(emailListName, "items.0.value", "test@example.com"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigEmailList(rnd, rnd2, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, }, }) } @@ -234,10 +283,15 @@ func TestAccCloudflareAccessGroup_Exclude(t *testing.T) { resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), resource.TestCheckResourceAttr(name, "name", rnd), resource.TestCheckResourceAttr(name, "include.0.email.email", email), - resource.TestCheckResourceAttr(name, "include.0.email_domain.domain", "example.com"), + resource.TestCheckResourceAttr(name, "include.1.email_domain.domain", "example.com"), resource.TestCheckResourceAttr(name, "exclude.0.email.email", email), ), }, + { + // Ensures no diff on last plan + Config: testAccessGroupConfigExclude(rnd, accountID, email), + PlanOnly: true, + }, }, }) } @@ -261,10 +315,15 @@ func TestAccCloudflareAccessGroup_Require(t *testing.T) { resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), resource.TestCheckResourceAttr(name, "name", rnd), resource.TestCheckResourceAttr(name, "include.0.email.email", email), - resource.TestCheckResourceAttr(name, "include.0.email_domain.domain", "example.com"), + resource.TestCheckResourceAttr(name, "include.1.email_domain.domain", "example.com"), resource.TestCheckResourceAttr(name, "require.0.email.email", email), ), }, + { + // Ensures no diff on last plan + Config: testAccessGroupConfigRequire(rnd, accountID, email), + PlanOnly: true, + }, }, }) } @@ -288,13 +347,18 @@ func TestAccCloudflareAccessGroup_FullConfig(t *testing.T) { resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), resource.TestCheckResourceAttr(name, "name", rnd), resource.TestCheckResourceAttr(name, "include.0.email.email", email), - resource.TestCheckResourceAttr(name, "include.0.email_domain.domain", "example.com"), + resource.TestCheckResourceAttr(name, "include.1.email_domain.domain", "example.com"), + resource.TestCheckResourceAttr(name, "include.2.common_name.common_name", "common"), + resource.TestCheckResourceAttr(name, "include.3.common_name.common_name", "name"), resource.TestCheckResourceAttr(name, "exclude.0.email.email", email), resource.TestCheckResourceAttr(name, "require.0.email.email", email), - resource.TestCheckResourceAttr(name, "include.0.common_name.common_name", "common"), - resource.TestCheckResourceAttr(name, "include.1.common_name.common_name", "name"), ), }, + { + // Ensures no diff on last plan + Config: testAccessGroupConfigFullConfig(rnd, accountID, email), + PlanOnly: true, + }, }, }) } @@ -324,6 +388,11 @@ func TestAccCloudflareAccessGroup_WithIDP(t *testing.T) { resource.TestCheckResourceAttr(groupName, "include.0.github_organization.team", team), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupWithIDP(accountID, rnd, githubOrg, team), + PlanOnly: true, + }, }, }) } @@ -353,6 +422,11 @@ func TestAccCloudflareAccessGroup_WithIDPAuthContext(t *testing.T) { resource.TestCheckResourceAttr(groupName, "require.0.auth_context.ac_id", ctxACID), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupWithIDPAuthContext(accountID, rnd, ctxID, ctxACID), + PlanOnly: true, + }, }, }) } @@ -376,14 +450,24 @@ func TestAccCloudflareAccessGroup_Updated(t *testing.T) { testAccCheckCloudflareAccessGroupExists(name, cloudflare.AccountIdentifier(accountID), &before), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigBasic(rnd, email, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, { Config: testAccCloudflareAccessGroupConfigBasic(rnd, "test-changed@example.com", cloudflare.AccountIdentifier(accountID)), Check: resource.ComposeTestCheckFunc( testAccCheckCloudflareAccessGroupExists(name, cloudflare.AccountIdentifier(accountID), &after), testAccCheckCloudflareAccessGroupIDUnchanged(&before, &after), - resource.TestCheckResourceAttr(name, "include.0.email.email", "test-changed@example.com"), + resource.TestCheckResourceAttr(name, "include.1.email.email", "test-changed@example.com"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigBasic(rnd, "test-changed@example.com", cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, }, }) } @@ -407,6 +491,11 @@ func TestAccCloudflareAccessGroup_UpdatedFromCommonNameToCommonNames(t *testing. testAccCheckCloudflareAccessGroupExists(name, cloudflare.AccountIdentifier(accountID), &before), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigBasicWithCommonName(rnd, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, { Config: testAccCloudflareAccessGroupConfigBasicWithCommonNames(rnd, cloudflare.AccountIdentifier(accountID)), Check: resource.ComposeTestCheckFunc( @@ -416,6 +505,11 @@ func TestAccCloudflareAccessGroup_UpdatedFromCommonNameToCommonNames(t *testing. resource.TestCheckResourceAttr(name, "include.1.common_name.common_name", "name"), ), }, + { + // Ensures no diff on last plan + Config: testAccCloudflareAccessGroupConfigBasicWithCommonNames(rnd, cloudflare.AccountIdentifier(accountID)), + PlanOnly: true, + }, }, }) } diff --git a/internal/services/zero_trust_access_group/schema.go b/internal/services/zero_trust_access_group/schema.go index 0a6b8d14f9..712de09130 100644 --- a/internal/services/zero_trust_access_group/schema.go +++ b/internal/services/zero_trust_access_group/schema.go @@ -4,8 +4,9 @@ package zero_trust_access_group import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customvalidator" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" - "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -40,6 +41,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Rules evaluated with an OR logical operator. A user needs to meet only one of the Include rules.", Required: true, NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, @@ -277,6 +281,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Rules evaluated with a NOT logical operator. To match a policy, a user cannot meet any of the Exclude rules.", Optional: true, NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, @@ -510,6 +517,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Rules evaluated with an AND logical operator. To match a policy, a user must meet all of the Require rules.", Optional: true, NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, @@ -739,14 +749,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, - "created_at": schema.StringAttribute{ - Computed: true, - CustomType: timetypes.RFC3339Type{}, - }, - "updated_at": schema.StringAttribute{ - Computed: true, - CustomType: timetypes.RFC3339Type{}, - }, }, } } diff --git a/internal/services/zero_trust_access_group/testdata/accessgroupconfigbasic.tf b/internal/services/zero_trust_access_group/testdata/accessgroupconfigbasic.tf index 6f4353b640..89b2a7552d 100644 --- a/internal/services/zero_trust_access_group/testdata/accessgroupconfigbasic.tf +++ b/internal/services/zero_trust_access_group/testdata/accessgroupconfigbasic.tf @@ -1,38 +1,51 @@ resource "cloudflare_zero_trust_access_group" "%[1]s" { %[3]s_id = "%[4]s" - name = "%[1]s" - - include = [{ - any_valid_service_token = {} - email = { email = "%[2]s" } - email_domain = { domain = "example.com" } - ip = { ip = "192.0.2.1/32" } - ip_list = { - id = "e3a0f205-c525-4e48-a293-ba5d1f00e638", - } - saml = { - attribute_name = "Name1" - attribute_value = "Value1" - identity_provider_id = "1234" - } - azure_ad = { - id = "group1" - identity_provider_id = "1234" - }, - }, - { - ip = { ip = "192.0.2.2/32" } - ip_list = { - id = "5d54cd30-ce52-46e4-9a46-a47887e1a167", - } - saml = { - attribute_name = "Name2" - attribute_value = "Value2" - identity_provider_id = "1234" - } - azure_ad = { - id = "group2" - identity_provider_id = "5678" - } - }] + name = "%[1]s" + include = [ + { + any_valid_service_token = {} + }, + { email = { email = "%[2]s" } }, + { email_domain = { domain = "example.com" } }, + { ip = { ip = "192.0.2.1/32" } }, + { + ip_list = { + id = "e3a0f205-c525-4e48-a293-ba5d1f00e638", + } + }, + { + saml = { + attribute_name = "Name1" + attribute_value = "Value1" + identity_provider_id = "1234" + } + }, + { + azure_ad = { + id = "group1" + identity_provider_id = "1234" + } + }, + { + ip = { ip = "192.0.2.2/32" } + }, + { + ip_list = { + id = "5d54cd30-ce52-46e4-9a46-a47887e1a167", + } + }, + { + saml = { + attribute_name = "Name2" + attribute_value = "Value2" + identity_provider_id = "1234" + } + }, + { + azure_ad = { + id = "group2" + identity_provider_id = "5678" + } + }, + ] } diff --git a/internal/services/zero_trust_access_group/testdata/accessgroupconfigexclude.tf b/internal/services/zero_trust_access_group/testdata/accessgroupconfigexclude.tf index 2cf5a5170d..80267cb0a6 100644 --- a/internal/services/zero_trust_access_group/testdata/accessgroupconfigexclude.tf +++ b/internal/services/zero_trust_access_group/testdata/accessgroupconfigexclude.tf @@ -1,13 +1,19 @@ resource "cloudflare_zero_trust_access_group" "%[1]s" { account_id = "%[2]s" - name = "%[1]s" + name = "%[1]s" - include = [{ - email = { email = "%[3]s" } - email_domain = { domain = "example.com" } - }] + include = [ + { + email = { email = "%[3]s" } + }, + { + email_domain = { domain = "example.com" } + } + ] - exclude = [{ - email = { email = "%[3]s" } - }] + exclude = [ + { + email = { email = "%[3]s" } + } + ] } diff --git a/internal/services/zero_trust_access_group/testdata/accessgroupconfigfullconfig.tf b/internal/services/zero_trust_access_group/testdata/accessgroupconfigfullconfig.tf index 529c8e5025..77752a8946 100644 --- a/internal/services/zero_trust_access_group/testdata/accessgroupconfigfullconfig.tf +++ b/internal/services/zero_trust_access_group/testdata/accessgroupconfigfullconfig.tf @@ -5,7 +5,11 @@ resource "cloudflare_zero_trust_access_group" "%[1]s" { include = [ { email = { email = "%[3]s" } + }, + { email_domain = { domain = "example.com" } + }, + { common_name = { common_name = "common" } }, { @@ -13,11 +17,15 @@ resource "cloudflare_zero_trust_access_group" "%[1]s" { } ] - require = [{ - email = { email = "%[3]s" } - }] + require = [ + { + email = { email = "%[3]s" } + } + ] - exclude = [{ - email = { email = "%[3]s" } - }] + exclude = [ + { + email = { email = "%[3]s" } + } + ] } diff --git a/internal/services/zero_trust_access_group/testdata/accessgroupconfigrequire.tf b/internal/services/zero_trust_access_group/testdata/accessgroupconfigrequire.tf index e3f7920594..9fa6a78717 100644 --- a/internal/services/zero_trust_access_group/testdata/accessgroupconfigrequire.tf +++ b/internal/services/zero_trust_access_group/testdata/accessgroupconfigrequire.tf @@ -1,13 +1,19 @@ resource "cloudflare_zero_trust_access_group" "%[1]s" { account_id = "%[2]s" - name = "%[1]s" + name = "%[1]s" - include = [{ - email = { email = "%[3]s" } - email_domain = { domain = "example.com" } - }] + include = [ + { + email = { email = "%[3]s" } + }, + { + email_domain = { domain = "example.com" } + } + ] - require = [{ - email = { email = "%[3]s" } - }] + require = [ + { + email = { email = "%[3]s" } + } + ] } diff --git a/internal/services/zero_trust_access_policy/model.go b/internal/services/zero_trust_access_policy/model.go index 9b65c946b6..532d034907 100644 --- a/internal/services/zero_trust_access_policy/model.go +++ b/internal/services/zero_trust_access_policy/model.go @@ -4,8 +4,6 @@ package zero_trust_access_policy import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" - "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -14,21 +12,19 @@ type ZeroTrustAccessPolicyResultEnvelope struct { } type ZeroTrustAccessPolicyModel struct { - ID types.String `tfsdk:"id" json:"id,computed"` - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - Decision types.String `tfsdk:"decision" json:"decision,required"` - Name types.String `tfsdk:"name" json:"name,required"` - ApprovalRequired types.Bool `tfsdk:"approval_required" json:"approval_required,optional"` - IsolationRequired types.Bool `tfsdk:"isolation_required" json:"isolation_required,optional"` - PurposeJustificationPrompt types.String `tfsdk:"purpose_justification_prompt" json:"purpose_justification_prompt,optional"` - PurposeJustificationRequired types.Bool `tfsdk:"purpose_justification_required" json:"purpose_justification_required,optional"` - ApprovalGroups *[]*ZeroTrustAccessPolicyApprovalGroupsModel `tfsdk:"approval_groups" json:"approval_groups,optional"` - SessionDuration types.String `tfsdk:"session_duration" json:"session_duration,computed_optional"` - Exclude customfield.NestedObjectList[ZeroTrustAccessPolicyExcludeModel] `tfsdk:"exclude" json:"exclude,computed_optional"` - Include customfield.NestedObjectList[ZeroTrustAccessPolicyIncludeModel] `tfsdk:"include" json:"include,computed_optional"` - Require customfield.NestedObjectList[ZeroTrustAccessPolicyRequireModel] `tfsdk:"require" json:"require,computed_optional"` - CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` - UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` + ID types.String `tfsdk:"id" json:"id,computed"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Decision types.String `tfsdk:"decision" json:"decision,required"` + Name types.String `tfsdk:"name" json:"name,required"` + ApprovalRequired types.Bool `tfsdk:"approval_required" json:"approval_required,optional"` + IsolationRequired types.Bool `tfsdk:"isolation_required" json:"isolation_required,optional"` + PurposeJustificationPrompt types.String `tfsdk:"purpose_justification_prompt" json:"purpose_justification_prompt,optional"` + PurposeJustificationRequired types.Bool `tfsdk:"purpose_justification_required" json:"purpose_justification_required,optional"` + ApprovalGroups *[]*ZeroTrustAccessPolicyApprovalGroupsModel `tfsdk:"approval_groups" json:"approval_groups,optional"` + SessionDuration types.String `tfsdk:"session_duration" json:"session_duration,computed_optional"` + Exclude *[]*ZeroTrustAccessPolicyExcludeModel `tfsdk:"exclude" json:"exclude,optional"` + Include *[]*ZeroTrustAccessPolicyIncludeModel `tfsdk:"include" json:"include,optional"` + Require *[]*ZeroTrustAccessPolicyRequireModel `tfsdk:"require" json:"require,optional"` } func (m ZeroTrustAccessPolicyModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/zero_trust_access_policy/normalizations.go b/internal/services/zero_trust_access_policy/normalizations.go new file mode 100644 index 0000000000..0566e55e2e --- /dev/null +++ b/internal/services/zero_trust_access_policy/normalizations.go @@ -0,0 +1,30 @@ +package zero_trust_access_policy + +import ( + "context" + "github.com/hashicorp/terraform-plugin-framework/diag" +) + +type IsNull interface { + IsNull() bool +} + +func normalizeEmptyAndNullSlice[T any](data **[]T, stateData *[]T) { + if (*data != nil && len(**data) != 0) || (stateData != nil && len(*stateData) != 0) { + return + } + *data = stateData +} + +// Normalizing function to ensure consistency between the state/plan and the meaning of the API response. +// Alters the API response before applying it to the state by laxing equalities between null & zero-value +// for some attributes, and nullifies fields that terraform should not be saving in the state. +func normalizeReadZeroTrustAccessPolicyAPIData(ctx context.Context, data, sourceData *ZeroTrustAccessPolicyModel) diag.Diagnostics { + diags := make(diag.Diagnostics, 0) + + normalizeEmptyAndNullSlice(&data.Include, sourceData.Include) + normalizeEmptyAndNullSlice(&data.Require, sourceData.Require) + normalizeEmptyAndNullSlice(&data.Exclude, sourceData.Exclude) + + return diags +} diff --git a/internal/services/zero_trust_access_policy/resource.go b/internal/services/zero_trust_access_policy/resource.go index 9ee3638a23..5a0af5f22c 100644 --- a/internal/services/zero_trust_access_policy/resource.go +++ b/internal/services/zero_trust_access_policy/resource.go @@ -141,6 +141,13 @@ func (r *ZeroTrustAccessPolicyResource) Update(ctx context.Context, req resource } data = &env.Result + var planData *ZeroTrustAccessPolicyModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(normalizeReadZeroTrustAccessPolicyAPIData(ctx, data, planData)...) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -181,6 +188,14 @@ func (r *ZeroTrustAccessPolicyResource) Read(ctx context.Context, req resource.R } data = &env.Result + var stateData *ZeroTrustAccessPolicyModel + resp.Diagnostics.Append(req.State.Get(ctx, &stateData)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(normalizeReadZeroTrustAccessPolicyAPIData(ctx, data, stateData)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } diff --git a/internal/services/zero_trust_access_policy/resource_test.go b/internal/services/zero_trust_access_policy/resource_test.go index a31b106ba0..20209c1f40 100644 --- a/internal/services/zero_trust_access_policy/resource_test.go +++ b/internal/services/zero_trust_access_policy/resource_test.go @@ -44,6 +44,11 @@ func TestAccCloudflareAccessPolicy_ServiceToken(t *testing.T) { resource.TestCheckResourceAttr(name, "include.0.service_token.%", "1"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyServiceTokenConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -69,6 +74,11 @@ func TestAccCloudflareAccessPolicy_AnyServiceToken(t *testing.T) { resource.TestCheckResourceAttrSet(name, "include.0.any_valid_service_token.%"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyAnyServiceTokenConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -110,6 +120,11 @@ func TestAccCloudflareAccessPolicy_Group(t *testing.T) { resource.TestCheckResourceAttr(name, "include.0.group.%", "1"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyGroupConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -139,6 +154,11 @@ func TestAccCloudflareAccessPolicy_MTLS(t *testing.T) { resource.TestCheckResourceAttrSet(name, "include.0.certificate.%"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyMTLSConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -173,6 +193,11 @@ func TestAccCloudflareAccessPolicy_EmailDomain(t *testing.T) { resource.TestCheckResourceAttr(name, "session_duration", "12h"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyEmailDomainConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -202,6 +227,11 @@ func TestAccCloudflareAccessPolicy_Emails(t *testing.T) { resource.TestCheckResourceAttr(name, "include.0.email.email", "a@example.com"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyEmailsConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -231,6 +261,11 @@ func TestAccCloudflareAccessPolicy_Everyone(t *testing.T) { resource.TestCheckResourceAttrSet(name, "include.0.everyone.%"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyEveryoneConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -260,6 +295,11 @@ func TestAccCloudflareAccessPolicy_IPs(t *testing.T) { resource.TestCheckResourceAttr(name, "include.0.ip.ip", "10.0.0.1/32"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyIPsConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -289,6 +329,11 @@ func TestAccCloudflareAccessPolicy_AuthMethod(t *testing.T) { resource.TestCheckResourceAttr(name, "include.0.auth_method.auth_method", "hwk"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyAuthMethodConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -318,6 +363,11 @@ func TestAccCloudflareAccessPolicy_Geo(t *testing.T) { resource.TestCheckResourceAttr(name, "include.0.geo.country_code", "US"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyGeoConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -348,6 +398,11 @@ func TestAccCloudflareAccessPolicy_Okta(t *testing.T) { resource.TestCheckResourceAttr(name, "include.0.okta.identity_provider_id", "225934dc-14e4-4f55-87be-f5d798d23f91"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyOktaConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -378,6 +433,11 @@ func TestAccCloudflareAccessPolicy_PurposeJustification(t *testing.T) { resource.TestCheckResourceAttr(name, "purpose_justification_prompt", "Why should we let you in?"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyPurposeJustificationConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -456,6 +516,11 @@ func TestAccCloudflareAccessPolicy_ApprovalGroup(t *testing.T) { resource.TestCheckResourceAttr(name, "approval_groups.1.approvals_needed", "1"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyApprovalGroupConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -527,6 +592,11 @@ func TestAccCloudflareAccessPolicy_ExternalEvaluation(t *testing.T) { resource.TestCheckResourceAttr(name, "include.0.external_evaluation.keys_url", "https://example.com/keys"), ), }, + { + // Ensures no diff on last plan + Config: testAccessPolicyExternalEvalautionConfig(rnd, zone, accountID), + PlanOnly: true, + }, }, }) } @@ -535,6 +605,8 @@ func testAccessPolicyExternalEvalautionConfig(resourceID, zone, accountID string return acctest.LoadTestCase("accesspolicyexternalevalautionconfig.tf", resourceID, zone, accountID) } +/* +Commented out until cloudflare_zero_trust_gateway_settings gets fixed func TestAccCloudflareAccessPolicy_IsolationRequired(t *testing.T) { rnd := utils.GenerateRandomResourceName() name := "cloudflare_zero_trust_access_policy." + rnd @@ -559,6 +631,7 @@ func TestAccCloudflareAccessPolicy_IsolationRequired(t *testing.T) { }, }) } +*/ func testAccessPolicyIsolationRequiredConfig(resourceID, zone, accountID string) string { return acctest.LoadTestCase("accesspolicyisolationrequiredconfig.tf", resourceID, zone, accountID) diff --git a/internal/services/zero_trust_access_policy/schema.go b/internal/services/zero_trust_access_policy/schema.go index 10ac9021de..726ad2b503 100644 --- a/internal/services/zero_trust_access_policy/schema.go +++ b/internal/services/zero_trust_access_policy/schema.go @@ -4,9 +4,8 @@ package zero_trust_access_policy import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customvalidator" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" - "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -97,10 +96,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "exclude": schema.ListNestedAttribute{ Description: "Rules evaluated with a NOT logical operator. To match the policy, a user cannot meet any of the Exclude rules.", - Computed: true, Optional: true, - CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessPolicyExcludeModel](ctx), NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, @@ -332,10 +332,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "include": schema.ListNestedAttribute{ Description: "Rules evaluated with an OR logical operator. A user needs to meet only one of the Include rules.", - Computed: true, - Optional: true, - CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessPolicyIncludeModel](ctx), + Required: true, NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, @@ -567,10 +568,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "require": schema.ListNestedAttribute{ Description: "Rules evaluated with an AND logical operator. To match the policy, a user must meet all of the Require rules.", - Computed: true, Optional: true, - CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessPolicyRequireModel](ctx), NestedObject: schema.NestedAttributeObject{ + Validators: []validator.Object{ + customvalidator.ObjectSizeAtMost(1), + }, Attributes: map[string]schema.Attribute{ "group": schema.SingleNestedAttribute{ Optional: true, @@ -800,14 +802,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, - "created_at": schema.StringAttribute{ - Computed: true, - CustomType: timetypes.RFC3339Type{}, - }, - "updated_at": schema.StringAttribute{ - Computed: true, - CustomType: timetypes.RFC3339Type{}, - }, }, } } diff --git a/scripts/run-ci-acceptance-tests b/scripts/run-ci-acceptance-tests index bf8d6d22cc..7e20b2c614 100755 --- a/scripts/run-ci-acceptance-tests +++ b/scripts/run-ci-acceptance-tests @@ -114,10 +114,12 @@ go test -run "^TestAcc" -count 1 \ ./internal/services/workers_script \ ./internal/services/workers_script_subdomain \ ./internal/services/zero_trust_access_application \ + ./internal/services/zero_trust_access_group \ ./internal/services/zero_trust_access_identity_provider \ ./internal/services/zero_trust_access_infrastructure_target \ ./internal/services/zero_trust_access_key_configuration \ ./internal/services/zero_trust_access_mtls_hostname_settings \ + ./internal/services/zero_trust_access_policy \ ./internal/services/zero_trust_access_service_token \ ./internal/services/zero_trust_access_tag \ ./internal/services/zero_trust_device_custom_profile \ From 644e48e13936fe61efdce29ae57a1fefd394c18b Mon Sep 17 00:00:00 2001 From: Steve Conrad Date: Wed, 25 Jun 2025 12:28:55 -0500 Subject: [PATCH 185/187] fixing api token tests --- internal/services/api_token/resource_test.go | 84 ++----------------- .../testdata/apitokenconfigallowdeny.tf | 13 --- .../api_token/testdata/apitokendatasource.tf | 1 + .../testdata/apitokenwithallcondition.tf | 11 +-- .../apitokenwithindividualcondition.tf | 7 +- .../testdata/apitokenwithoutcondition.tf | 1 + .../api_token/testdata/apitokenwithttl.tf | 1 + 7 files changed, 19 insertions(+), 99 deletions(-) delete mode 100644 internal/services/api_token/testdata/apitokenconfigallowdeny.tf diff --git a/internal/services/api_token/resource_test.go b/internal/services/api_token/resource_test.go index ab302efde2..1c5b82ac84 100644 --- a/internal/services/api_token/resource_test.go +++ b/internal/services/api_token/resource_test.go @@ -1,7 +1,6 @@ package api_token_test import ( - "os" "testing" "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" @@ -10,12 +9,6 @@ import ( ) func TestAccAPIToken_Basic(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 := utils.GenerateRandomResourceName() resourceID := "cloudflare_api_token." + rnd permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read @@ -40,41 +33,7 @@ func TestAccAPIToken_Basic(t *testing.T) { }) } -func TestAccAPIToken_AllowDeny(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 := utils.GenerateRandomResourceName() - zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") - permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.TestAccPreCheck(t) }, - ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, - Steps: []resource.TestStep{ - { - Config: testAPITokenConfigAllowDeny(rnd, permissionID, zoneID, false), - }, - { - Config: testAPITokenConfigAllowDeny(rnd, permissionID, zoneID, true), - }, - { - Config: testAPITokenConfigAllowDeny(rnd, permissionID, zoneID, false), - }, - }, - }) -} - func TestAccAPIToken_DoesNotSetConditions(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 := utils.GenerateRandomResourceName() name := "cloudflare_api_token." + rnd permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read @@ -87,8 +46,8 @@ func TestAccAPIToken_DoesNotSetConditions(t *testing.T) { Config: testAccCloudflareAPITokenWithoutCondition(rnd, rnd, permissionID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", rnd), - resource.TestCheckNoResourceAttr(name, "condition.0.request_ip.0.in"), - resource.TestCheckNoResourceAttr(name, "condition.0.request_ip.0.not_in"), + resource.TestCheckNoResourceAttr(name, "condition.request_ip.0.in"), + resource.TestCheckNoResourceAttr(name, "condition.request_ip.0.not_in"), ), }, }, @@ -100,14 +59,6 @@ func testAccCloudflareAPITokenWithoutCondition(resourceName, rnd, permissionID s } func TestAccAPIToken_SetIndividualCondition(t *testing.T) { - acctest.TestAccSkipForDefaultZone(t, "Pending service fix to address nested object syntax as strings for `conditions`.") - - // 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 := utils.GenerateRandomResourceName() name := "cloudflare_api_token." + rnd permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read @@ -120,8 +71,8 @@ func TestAccAPIToken_SetIndividualCondition(t *testing.T) { Config: testAccCloudflareAPITokenWithIndividualCondition(rnd, permissionID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", rnd), - resource.TestCheckResourceAttr(name, "condition.0.request_ip.0.in.0", "192.0.2.1/32"), - resource.TestCheckNoResourceAttr(name, "condition.0.request_ip.0.not_in"), + resource.TestCheckResourceAttr(name, "condition.request_ip.in.0", "192.0.2.1/32"), + resource.TestCheckNoResourceAttr(name, "condition.request_ip.not_in"), ), }, }, @@ -133,14 +84,6 @@ func testAccCloudflareAPITokenWithIndividualCondition(rnd string, permissionID s } func TestAccAPIToken_SetAllCondition(t *testing.T) { - acctest.TestAccSkipForDefaultZone(t, "Pending service fix to address nested object syntax as strings for `conditions`.") - - // 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 := utils.GenerateRandomResourceName() name := "cloudflare_api_token." + rnd permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read @@ -153,8 +96,8 @@ func TestAccAPIToken_SetAllCondition(t *testing.T) { Config: testAccCloudflareAPITokenWithAllCondition(rnd, permissionID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", rnd), - resource.TestCheckResourceAttr(name, "condition.0.request_ip.0.in.0", "192.0.2.1/32"), - resource.TestCheckResourceAttr(name, "condition.0.request_ip.0.not_in.0", "198.51.100.1/32"), + resource.TestCheckResourceAttr(name, "condition.request_ip.in.0", "192.0.2.1/32"), + resource.TestCheckResourceAttr(name, "condition.request_ip.not_in.0", "198.51.100.1/32"), ), }, }, @@ -165,22 +108,7 @@ func testAccCloudflareAPITokenWithAllCondition(rnd string, permissionID string) return acctest.LoadTestCase("apitokenwithallcondition.tf", rnd, permissionID) } -func testAPITokenConfigAllowDeny(resourceID, permissionID, zoneID string, allowAllZonesExceptOne bool) string { - var add string - if allowAllZonesExceptOne { - add = acctest.LoadTestCase("apitokenconfigallowdeny.tf", permissionID, zoneID) - } - - return acctest.LoadTestCase("apitokenconfigallowdeny.tf", resourceID, permissionID, add) -} - func TestAccAPIToken_TokenTTL(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 := utils.GenerateRandomResourceName() name := "cloudflare_api_token." + rnd permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read diff --git a/internal/services/api_token/testdata/apitokenconfigallowdeny.tf b/internal/services/api_token/testdata/apitokenconfigallowdeny.tf deleted file mode 100644 index 1614716f0a..0000000000 --- a/internal/services/api_token/testdata/apitokenconfigallowdeny.tf +++ /dev/null @@ -1,13 +0,0 @@ -resource "cloudflare_api_token" "%[1]s" { - name = "%[1]s" - - policies = [{ - effect = "allow" - permission_groups = [{ - id = "%[2]s" - }] - resources = { - "com.cloudflare.api.account.zone.*" = "*" - } - }] -} diff --git a/internal/services/api_token/testdata/apitokendatasource.tf b/internal/services/api_token/testdata/apitokendatasource.tf index 15d87c23ac..6f481dd8cf 100644 --- a/internal/services/api_token/testdata/apitokendatasource.tf +++ b/internal/services/api_token/testdata/apitokendatasource.tf @@ -1,5 +1,6 @@ resource "cloudflare_api_token" "%[1]s" { name = "%[1]s" + status = "active" policies = [{ effect = "allow" diff --git a/internal/services/api_token/testdata/apitokenwithallcondition.tf b/internal/services/api_token/testdata/apitokenwithallcondition.tf index 839a043ff4..3c0e1003ab 100644 --- a/internal/services/api_token/testdata/apitokenwithallcondition.tf +++ b/internal/services/api_token/testdata/apitokenwithallcondition.tf @@ -1,19 +1,20 @@ resource "cloudflare_api_token" "%[1]s" { name = "%[1]s" + status = "active" policies = [{ effect = "allow" permission_groups = [{ - id = "%[2]s" + id = "%[2]s" }] resources = { "com.cloudflare.api.account.zone.*" = "*" } }] condition = { - request_ip = { - in = ["192.0.2.1/32"] - not_in = ["198.51.100.1/32"] - } + request_ip = { + in = ["192.0.2.1/32"] + not_in = ["198.51.100.1/32"] + } } } diff --git a/internal/services/api_token/testdata/apitokenwithindividualcondition.tf b/internal/services/api_token/testdata/apitokenwithindividualcondition.tf index 4807db2a97..304f6f3adb 100644 --- a/internal/services/api_token/testdata/apitokenwithindividualcondition.tf +++ b/internal/services/api_token/testdata/apitokenwithindividualcondition.tf @@ -1,5 +1,6 @@ resource "cloudflare_api_token" "%[1]s" { name = "%[1]s" + status = "active" policies = [{ effect = "allow" @@ -10,8 +11,8 @@ resource "cloudflare_api_token" "%[1]s" { }] condition = { - request_ip = { - in = ["192.0.2.1/32"] - } + request_ip = { + in = ["192.0.2.1/32"] + } } } diff --git a/internal/services/api_token/testdata/apitokenwithoutcondition.tf b/internal/services/api_token/testdata/apitokenwithoutcondition.tf index b64c34d059..083d1663f5 100644 --- a/internal/services/api_token/testdata/apitokenwithoutcondition.tf +++ b/internal/services/api_token/testdata/apitokenwithoutcondition.tf @@ -1,5 +1,6 @@ resource "cloudflare_api_token" "%[1]s" { name = "%[2]s" + status = "active" policies = [{ effect = "allow" diff --git a/internal/services/api_token/testdata/apitokenwithttl.tf b/internal/services/api_token/testdata/apitokenwithttl.tf index 829f99750e..4ae016b49f 100644 --- a/internal/services/api_token/testdata/apitokenwithttl.tf +++ b/internal/services/api_token/testdata/apitokenwithttl.tf @@ -1,5 +1,6 @@ resource "cloudflare_api_token" "%[1]s" { name = "%[1]s" + status = "active" policies = [{ effect = "allow" From 2b2ddd1720d8d9f2f5f143b299b2fd69d12241f6 Mon Sep 17 00:00:00 2001 From: Steve Conrad Date: Tue, 24 Jun 2025 14:53:07 -0500 Subject: [PATCH 186/187] api token permission groups order does not matter --- internal/services/api_token/schema.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/api_token/schema.go b/internal/services/api_token/schema.go index 8ae1089fa1..b791033bd9 100644 --- a/internal/services/api_token/schema.go +++ b/internal/services/api_token/schema.go @@ -45,7 +45,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { stringvalidator.OneOfCaseInsensitive("allow", "deny"), }, }, - "permission_groups": schema.ListNestedAttribute{ + "permission_groups": schema.SetNestedAttribute{ Description: "A set of permission groups that are specified to the policy.", Required: true, NestedObject: schema.NestedAttributeObject{ From 5282125abc0f4536299b1b43d19d1bd5be140ec6 Mon Sep 17 00:00:00 2001 From: steve-thousand Date: Thu, 3 Jul 2025 17:30:44 -0500 Subject: [PATCH 187/187] adding account_token tests --- .../services/account_token/resource_test.go | 208 ++++++++++++++++++ internal/services/account_token/schema.go | 4 +- .../account_token-permissiongroup-order.tf | 22 ++ .../account_token-with-all-condition.tf | 22 ++ ...account_token-with-individual-condition.tf | 20 ++ .../testdata/account_token-with-ttl.tf | 15 ++ .../account_token-without-condition.tf | 12 + 7 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 internal/services/account_token/resource_test.go create mode 100644 internal/services/account_token/testdata/account_token-permissiongroup-order.tf create mode 100644 internal/services/account_token/testdata/account_token-with-all-condition.tf create mode 100644 internal/services/account_token/testdata/account_token-with-individual-condition.tf create mode 100644 internal/services/account_token/testdata/account_token-with-ttl.tf create mode 100644 internal/services/account_token/testdata/account_token-without-condition.tf diff --git a/internal/services/account_token/resource_test.go b/internal/services/account_token/resource_test.go new file mode 100644 index 0000000000..1e6c8c2382 --- /dev/null +++ b/internal/services/account_token/resource_test.go @@ -0,0 +1,208 @@ +package account_token_test + +import ( + "os" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" + "github.com/cloudflare/terraform-provider-cloudflare/internal/utils" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" +) + +func TestAccAccountToken_Basic(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + resourceID := "cloudflare_account_token." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareAccountTokenWithoutCondition(rnd, accountID, rnd, permissionID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceID, "name", rnd), + resource.TestCheckResourceAttr(resourceID, "policies.0.permission_groups.0.id", permissionID), + ), + }, + { + Config: testAccCloudflareAccountTokenWithoutCondition(rnd, accountID, rnd+"-updated", permissionID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceID, "name", rnd+"-updated"), + resource.TestCheckResourceAttr(resourceID, "policies.0.permission_groups.0.id", permissionID), + ), + }, + }, + }) +} + +func TestAccAccountToken_DoesNotSetConditions(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_account_token." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareAccountTokenWithoutCondition(rnd, accountID, rnd, permissionID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckNoResourceAttr(name, "condition.request_ip.0.in"), + resource.TestCheckNoResourceAttr(name, "condition.request_ip.0.not_in"), + ), + }, + }, + }) +} + +func testAccCloudflareAccountTokenWithoutCondition(resourceName, accountId, rnd, permissionID string) string { + return acctest.LoadTestCase("account_token-without-condition.tf", resourceName, accountId, rnd, permissionID) +} + +func TestAccAccountToken_SetIndividualCondition(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_account_token." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareAccountTokenWithIndividualCondition(rnd, accountID, permissionID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "condition.request_ip.in.0", "192.0.2.1/32"), + resource.TestCheckNoResourceAttr(name, "condition.request_ip.not_in"), + ), + }, + }, + }) +} + +func testAccCloudflareAccountTokenWithIndividualCondition(rnd, accountID, permissionID string) string { + return acctest.LoadTestCase("account_token-with-individual-condition.tf", rnd, accountID, permissionID) +} + +func TestAccAccountToken_SetAllCondition(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_account_token." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareAccountTokenWithAllCondition(rnd, accountID, permissionID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "condition.request_ip.in.0", "192.0.2.1/32"), + resource.TestCheckResourceAttr(name, "condition.request_ip.not_in.0", "198.51.100.1/32"), + ), + }, + }, + }) +} + +func testAccCloudflareAccountTokenWithAllCondition(rnd, accountID, permissionID string) string { + return acctest.LoadTestCase("account_token-with-all-condition.tf", rnd, accountID, permissionID) +} + +func TestAccAccountToken_TokenTTL(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_account_token." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + permissionID := "82e64a83756745bbbb1c9c2701bf816b" // DNS read + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareAccountTokenWithTTL(rnd, accountID, permissionID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "not_before", "2018-07-01T05:20:00Z"), + resource.TestCheckResourceAttr(name, "expires_on", "2032-01-01T00:00:00Z"), + ), + }, + }, + }) +} + +func testAccCloudflareAccountTokenWithTTL(rnd, accountID, permissionID string) string { + return acctest.LoadTestCase("account_token-with-ttl.tf", rnd, accountID, permissionID) +} + +func TestAccAccountToken_PermissionGroupOrder(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_account_token." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + permissionID1 := "82e64a83756745bbbb1c9c2701bf816b" // DNS read + permissionID2 := "e199d584e69344eba202452019deafe3" // Disable ESC read + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: acctest.LoadTestCase("account_token-permissiongroup-order.tf", rnd, accountID, permissionID1, permissionID2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "policies.0.permission_groups.0.id", permissionID1), + resource.TestCheckResourceAttr(name, "policies.0.permission_groups.1.id", permissionID2), + ), + }, + { + Config: acctest.LoadTestCase("account_token-permissiongroup-order.tf", rnd, accountID, permissionID2, permissionID1), + // changing the order of permission groups should not affect plan + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: acctest.LoadTestCase("account_token-permissiongroup-order.tf", rnd, accountID, permissionID2, permissionID1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "policies.0.permission_groups.0.id", permissionID1), + resource.TestCheckResourceAttr(name, "policies.0.permission_groups.1.id", permissionID2), + ), + }, + { + Config: acctest.LoadTestCase("account_token-permissiongroup-order.tf", rnd, accountID, permissionID2, permissionID1), + // re-applying same change does not produce drift + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + { + Config: acctest.LoadTestCase("account_token-permissiongroup-order.tf", rnd, accountID, permissionID1, permissionID2), + // changing the order of permission groups should not affect plan + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} diff --git a/internal/services/account_token/schema.go b/internal/services/account_token/schema.go index a765151b8b..9f33904c06 100644 --- a/internal/services/account_token/schema.go +++ b/internal/services/account_token/schema.go @@ -35,7 +35,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Token name.", Required: true, }, - "policies": schema.SetNestedAttribute{ + "policies": schema.ListNestedAttribute{ Description: "List of access policies assigned to the token.", Required: true, NestedObject: schema.NestedAttributeObject{ @@ -51,7 +51,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { stringvalidator.OneOfCaseInsensitive("allow", "deny"), }, }, - "permission_groups": schema.ListNestedAttribute{ + "permission_groups": schema.SetNestedAttribute{ Description: "A set of permission groups that are specified to the policy.", Required: true, NestedObject: schema.NestedAttributeObject{ diff --git a/internal/services/account_token/testdata/account_token-permissiongroup-order.tf b/internal/services/account_token/testdata/account_token-permissiongroup-order.tf new file mode 100644 index 0000000000..2dc46b6590 --- /dev/null +++ b/internal/services/account_token/testdata/account_token-permissiongroup-order.tf @@ -0,0 +1,22 @@ +resource "cloudflare_account_token" "%[1]s" { + name = "%[1]s" + account_id = "%[2]s" + + policies = [{ + effect = "allow" + permission_groups = [{ + id = "%[3]s" + },{ + id = "%[4]s" + }] + resources = { + "com.cloudflare.api.account.%[2]s" = "*" + } + }] +} + +data "cloudflare_account_token" "%[1]s" { + account_id = "%[2]s" + token_id = cloudflare_account_token.%[1]s.id + depends_on = [cloudflare_account_token.%[1]s] +} \ No newline at end of file diff --git a/internal/services/account_token/testdata/account_token-with-all-condition.tf b/internal/services/account_token/testdata/account_token-with-all-condition.tf new file mode 100644 index 0000000000..22a9cb57de --- /dev/null +++ b/internal/services/account_token/testdata/account_token-with-all-condition.tf @@ -0,0 +1,22 @@ + +resource "cloudflare_account_token" "%[1]s" { + name = "%[1]s" + account_id = "%[2]s" + + policies = [{ + effect = "allow" + permission_groups = [{ + id = "%[3]s" + }] + resources = { + "com.cloudflare.api.account.%[2]s" = "*" + } + }] + + condition = { + request_ip = { + in = ["192.0.2.1/32"] + not_in = ["198.51.100.1/32"] + } + } +} diff --git a/internal/services/account_token/testdata/account_token-with-individual-condition.tf b/internal/services/account_token/testdata/account_token-with-individual-condition.tf new file mode 100644 index 0000000000..12a737dc3f --- /dev/null +++ b/internal/services/account_token/testdata/account_token-with-individual-condition.tf @@ -0,0 +1,20 @@ +resource "cloudflare_account_token" "%[1]s" { + name = "%[1]s" + account_id = "%[2]s" + + policies = [{ + effect = "allow" + permission_groups = [{ + id = "%[3]s" + }] + resources = { + "com.cloudflare.api.account.%[2]s" = "*" + } + }] + + condition = { + request_ip = { + in = ["192.0.2.1/32"] + } + } +} diff --git a/internal/services/account_token/testdata/account_token-with-ttl.tf b/internal/services/account_token/testdata/account_token-with-ttl.tf new file mode 100644 index 0000000000..91f3de5a62 --- /dev/null +++ b/internal/services/account_token/testdata/account_token-with-ttl.tf @@ -0,0 +1,15 @@ +resource "cloudflare_account_token" "%[1]s" { + name = "%[1]s" + account_id = "%[2]s" + + policies = [{ + effect = "allow" + permission_groups = [{ id = "%[3]s" }] + resources = { + "com.cloudflare.api.account.%[2]s" = "*" + } + }] + + not_before = "2018-07-01T05:20:00Z" + expires_on = "2032-01-01T00:00:00Z" +} diff --git a/internal/services/account_token/testdata/account_token-without-condition.tf b/internal/services/account_token/testdata/account_token-without-condition.tf new file mode 100644 index 0000000000..7e554f97e3 --- /dev/null +++ b/internal/services/account_token/testdata/account_token-without-condition.tf @@ -0,0 +1,12 @@ +resource "cloudflare_account_token" "%[1]s" { + name = "%[3]s" + account_id = "%[2]s" + + policies = [{ + effect = "allow" + permission_groups = [{ id = "%[4]s" }] + resources = { + "com.cloudflare.api.account.%[2]s" = "*" + } + }] +}