diff --git a/.github/workflows/e2e-tests-next.yml b/.github/workflows/e2e-tests-next.yml new file mode 100644 index 00000000..c9e96161 --- /dev/null +++ b/.github/workflows/e2e-tests-next.yml @@ -0,0 +1,87 @@ +name: E2E Tests (provider next branch) +concurrency: + # Share the concurrency group with the stable e2e workflow — both operate on + # the same Cloudflare test account and R2 state, so they must not overlap. + group: e2e-tests + +# Manual-only. This workflow builds the Cloudflare provider from the tip of its +# `next` branch and runs the same e2e suite as e2e-tests.yml. Use it to: +# +# - validate an unreleased provider change against tf-migrate before it ships +# - reproduce upstream regressions that only surface on `next` +# - regression-test tf-migrate PRs against the upcoming provider release +# +# Failures here do NOT block main. They are advisory. When they fire, the +# expected action is to file / fix an issue against +# cloudflare/terraform-provider-cloudflare, then bump the stable pin in +# e2e-tests.yml once a new release includes the fix. + +on: + workflow_dispatch: + inputs: + provider_ref: + description: "Provider git ref to build (branch, tag, or commit SHA)" + required: false + default: "next" + target_provider_version: + description: "Version string written into v5 required_providers" + required: false + default: "5.21.1" + +env: + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} + CLOUDFLARE_DOMAIN: ${{ secrets.CLOUDFLARE_DOMAIN }} + CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }} + CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }} + CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }} + CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }} + CLOUDFLARE_CROWDSTRIKE_CLIENT_ID: ${{ secrets.CLOUDFLARE_CROWDSTRIKE_CLIENT_ID }} + CLOUDFLARE_CROWDSTRIKE_CLIENT_SECRET: ${{ secrets.CLOUDFLARE_CROWDSTRIKE_CLIENT_SECRET }} + CLOUDFLARE_CROWDSTRIKE_API_URL: ${{ secrets.CLOUDFLARE_CROWDSTRIKE_API_URL }} + CLOUDFLARE_CROWDSTRIKE_CUSTOMER_ID: ${{ secrets.CLOUDFLARE_CROWDSTRIKE_CUSTOMER_ID }} + TF_MIG_TEST: true + +jobs: + e2e-tests-provider-next: + name: E2E Tests (provider next) + runs-on: large-runner + permissions: + contents: read + steps: + - name: Checkout tf-migrate + uses: actions/checkout@v4 + with: + path: tf-migrate + + - name: Checkout cloudflare provider (${{ inputs.provider_ref }}) + uses: actions/checkout@v4 + with: + repository: cloudflare/terraform-provider-cloudflare + ref: ${{ inputs.provider_ref }} + path: provider + + - name: Record provider ref for the log + working-directory: ./provider + run: | + echo "provider_ref_input=${{ inputs.provider_ref }}" + echo "resolved_sha=$(git rev-parse HEAD)" + echo "head_message=$(git log -1 --pretty=%s)" + + - name: Setup go + uses: actions/setup-go@v5 + with: + go-version-file: ./tf-migrate/go.mod + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: "1.9.8" + + - name: Build provider + working-directory: ./provider + run: go build -o terraform-provider-cloudflare . + + - name: Run E2E Tests (provider state upgrader) + working-directory: ./tf-migrate + run: ./scripts/run-e2e-tests.sh --apply-exemptions --provider ../provider --parallelism 5 --exclude byo_ip_prefix --target-provider-version ${{ inputs.target_provider_version }} diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 459a85b9..1a80819f 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -2,6 +2,15 @@ name: E2E Tests concurrency: group: e2e-tests +# Runs on pushes to main against a PINNED provider tag. This is the blocking +# CI signal for merging: it verifies that migration is stable against the same +# provider release users install from the registry. +# +# To validate against the provider's development tip (next branch), run +# .github/workflows/e2e-tests-next.yml manually via workflow_dispatch. That +# workflow builds and tests against `next` and is expected to catch upstream +# regressions early — but its failures don't block tf-migrate PRs. + on: workflow_dispatch: push: @@ -9,6 +18,15 @@ on: - main env: + # Pinned target v5 provider version. Bump deliberately in its own PR when a + # new stable v5 release is out and you have confirmed compatibility. + # The pin is applied twice: + # 1. `ref` in the provider checkout below (builds this exact source) + # 2. `--target-provider-version` on the runner (writes this into the + # generated v5 config's required_providers block) + # Keep them in sync. + TARGET_PROVIDER_VERSION: "5.21.1" + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} CLOUDFLARE_DOMAIN: ${{ secrets.CLOUDFLARE_DOMAIN }} @@ -34,11 +52,11 @@ jobs: with: path: tf-migrate - - name: Checkout cloudflare provider (next branch) + - name: Checkout cloudflare provider (pinned release) uses: actions/checkout@v4 with: repository: cloudflare/terraform-provider-cloudflare - ref: next + ref: v${{ env.TARGET_PROVIDER_VERSION }} path: provider - name: Setup go @@ -57,4 +75,4 @@ jobs: - name: Run E2E Tests (provider state upgrader) working-directory: ./tf-migrate - run: ./scripts/run-e2e-tests.sh --apply-exemptions --provider ../provider --parallelism 5 --exclude byo_ip_prefix --target-provider-version 5.19.0-beta.5 + run: ./scripts/run-e2e-tests.sh --apply-exemptions --provider ../provider --parallelism 5 --exclude byo_ip_prefix --target-provider-version ${{ env.TARGET_PROVIDER_VERSION }} diff --git a/integration/v4_to_v5/testdata/logpush_job/expected/logpush_job.tf b/integration/v4_to_v5/testdata/logpush_job/expected/logpush_job.tf index 7edf7a40..2581635b 100644 --- a/integration/v4_to_v5/testdata/logpush_job/expected/logpush_job.tf +++ b/integration/v4_to_v5/testdata/logpush_job/expected/logpush_job.tf @@ -25,11 +25,14 @@ resource "cloudflare_logpush_job" "minimal" { } # Job with logpull_options only (no output_options) +# NOTE: audit_logs dataset fields are e.g. ActorEmail, ActionType, ResourceType. +# ClientIP/EdgeStartTimestamp belong to the http_requests dataset and cause +# "no valid fields for dataset audit_logs" errors from the API. resource "cloudflare_logpush_job" "with_logpull_options" { account_id = var.cloudflare_account_id dataset = "audit_logs" destination_conf = "https://logpush-receiver.sd.cfplat.com" - logpull_options = "fields=ClientIP,EdgeStartTimestamp×tamps=unixnano" + logpull_options = "fields=ActorEmail,ActionType,When×tamps=unixnano" } # Job with output_options block @@ -41,7 +44,7 @@ resource "cloudflare_logpush_job" "with_output_options" { output_options = { batch_prefix = "{" batch_suffix = "}" - field_names = ["ClientIP", "EdgeStartTimestamp"] + field_names = ["ActorEmail", "ActionType", "When"] output_type = "ndjson" cve_2021_44228 = false field_delimiter = "," diff --git a/integration/v4_to_v5/testdata/logpush_job/input/logpush_job.tf b/integration/v4_to_v5/testdata/logpush_job/input/logpush_job.tf index 32351ef0..8552da7b 100644 --- a/integration/v4_to_v5/testdata/logpush_job/input/logpush_job.tf +++ b/integration/v4_to_v5/testdata/logpush_job/input/logpush_job.tf @@ -25,11 +25,14 @@ resource "cloudflare_logpush_job" "minimal" { } # Job with logpull_options only (no output_options) +# NOTE: audit_logs dataset fields are e.g. ActorEmail, ActionType, ResourceType. +# ClientIP/EdgeStartTimestamp belong to the http_requests dataset and cause +# "no valid fields for dataset audit_logs" errors from the API. resource "cloudflare_logpush_job" "with_logpull_options" { account_id = var.cloudflare_account_id dataset = "audit_logs" destination_conf = "https://logpush-receiver.sd.cfplat.com" - logpull_options = "fields=ClientIP,EdgeStartTimestamp×tamps=unixnano" + logpull_options = "fields=ActorEmail,ActionType,When×tamps=unixnano" } # Job with output_options block @@ -41,7 +44,7 @@ resource "cloudflare_logpush_job" "with_output_options" { output_options { batch_prefix = "{" batch_suffix = "}" - field_names = ["ClientIP", "EdgeStartTimestamp"] + field_names = ["ActorEmail", "ActionType", "When"] output_type = "ndjson" } } diff --git a/integration/v4_to_v5/testdata/notification_policy/expected/notification_policy_e2e.tf b/integration/v4_to_v5/testdata/notification_policy/expected/notification_policy_e2e.tf index 4148570e..fe817348 100644 --- a/integration/v4_to_v5/testdata/notification_policy/expected/notification_policy_e2e.tf +++ b/integration/v4_to_v5/testdata/notification_policy/expected/notification_policy_e2e.tf @@ -35,19 +35,19 @@ locals { resource "cloudflare_notification_policy_webhooks" "e2e_webhook_1" { account_id = var.cloudflare_account_id name = "${local.name_prefix}-e2e-webhook-1" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" } resource "cloudflare_notification_policy_webhooks" "e2e_webhook_2" { account_id = var.cloudflare_account_id name = "${local.name_prefix}-e2e-webhook-2" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" } resource "cloudflare_notification_policy_webhooks" "e2e_webhook_3" { account_id = var.cloudflare_account_id name = "${local.name_prefix}-e2e-webhook-3" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" } ########################## diff --git a/integration/v4_to_v5/testdata/notification_policy/input/notification_policy_e2e.tf b/integration/v4_to_v5/testdata/notification_policy/input/notification_policy_e2e.tf index b1dd22f2..31e4e4a9 100644 --- a/integration/v4_to_v5/testdata/notification_policy/input/notification_policy_e2e.tf +++ b/integration/v4_to_v5/testdata/notification_policy/input/notification_policy_e2e.tf @@ -35,19 +35,19 @@ locals { resource "cloudflare_notification_policy_webhooks" "e2e_webhook_1" { account_id = var.cloudflare_account_id name = "${local.name_prefix}-e2e-webhook-1" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" } resource "cloudflare_notification_policy_webhooks" "e2e_webhook_2" { account_id = var.cloudflare_account_id name = "${local.name_prefix}-e2e-webhook-2" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" } resource "cloudflare_notification_policy_webhooks" "e2e_webhook_3" { account_id = var.cloudflare_account_id name = "${local.name_prefix}-e2e-webhook-3" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" } ########################## diff --git a/integration/v4_to_v5/testdata/notification_policy_webhooks/expected/notification_policy_webhooks.tf b/integration/v4_to_v5/testdata/notification_policy_webhooks/expected/notification_policy_webhooks.tf index 5106fe1c..9c78ba56 100644 --- a/integration/v4_to_v5/testdata/notification_policy_webhooks/expected/notification_policy_webhooks.tf +++ b/integration/v4_to_v5/testdata/notification_policy_webhooks/expected/notification_policy_webhooks.tf @@ -16,9 +16,12 @@ variable "cloudflare_domain" { type = string } -# Use Cloudflare trace endpoint for webhook testing -# URL: https://www.cloudflare.com/cdn-cgi/trace -# This endpoint responds with 200 OK to all requests for webhook validation +# Use Cloudflare-hosted httpbin as the webhook endpoint +# URL: https://httpbin.cfdata.org/post +# This endpoint returns 200 OK for POST requests, which is what the Cloudflare +# Notifications API needs to succeed webhook validation on create. +# (The previous URL, cloudflare.com/cdn-cgi/trace, only accepts GET and now +# returns 4xx for the validator's POST, breaking fresh webhook creates.) # ======================================== # Locals @@ -26,7 +29,7 @@ variable "cloudflare_domain" { locals { common_account = var.cloudflare_account_id name_prefix = "cftftest" - webhook_base_url = "https://www.cloudflare.com/cdn-cgi/trace" + webhook_base_url = "https://httpbin.cfdata.org/post" enable_backup = true enable_test = false } @@ -39,14 +42,14 @@ locals { resource "cloudflare_notification_policy_webhooks" "basic_webhook" { account_id = var.cloudflare_account_id name = "basic-webhook" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" } # Test Case 2: Full webhook with all fields resource "cloudflare_notification_policy_webhooks" "full_webhook" { account_id = var.cloudflare_account_id name = "production-webhook" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" secret = "webhook-secret-token-12345" } diff --git a/integration/v4_to_v5/testdata/notification_policy_webhooks/input/notification_policy_webhooks.tf b/integration/v4_to_v5/testdata/notification_policy_webhooks/input/notification_policy_webhooks.tf index 2c88058d..62ad10ab 100644 --- a/integration/v4_to_v5/testdata/notification_policy_webhooks/input/notification_policy_webhooks.tf +++ b/integration/v4_to_v5/testdata/notification_policy_webhooks/input/notification_policy_webhooks.tf @@ -16,9 +16,12 @@ variable "cloudflare_domain" { type = string } -# Use Cloudflare trace endpoint for webhook testing -# URL: https://www.cloudflare.com/cdn-cgi/trace -# This endpoint responds with 200 OK to all requests for webhook validation +# Use Cloudflare-hosted httpbin as the webhook endpoint +# URL: https://httpbin.cfdata.org/post +# This endpoint returns 200 OK for POST requests, which is what the Cloudflare +# Notifications API needs to succeed webhook validation on create. +# (The previous URL, cloudflare.com/cdn-cgi/trace, only accepts GET and now +# returns 4xx for the validator's POST, breaking fresh webhook creates.) # ======================================== # Locals @@ -26,7 +29,7 @@ variable "cloudflare_domain" { locals { common_account = var.cloudflare_account_id name_prefix = "cftftest" - webhook_base_url = "https://www.cloudflare.com/cdn-cgi/trace" + webhook_base_url = "https://httpbin.cfdata.org/post" enable_backup = true enable_test = false } @@ -39,14 +42,14 @@ locals { resource "cloudflare_notification_policy_webhooks" "basic_webhook" { account_id = var.cloudflare_account_id name = "basic-webhook" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" } # Test Case 2: Full webhook with all fields resource "cloudflare_notification_policy_webhooks" "full_webhook" { account_id = var.cloudflare_account_id name = "production-webhook" - url = "https://www.cloudflare.com/cdn-cgi/trace" + url = "https://httpbin.cfdata.org/post" secret = "webhook-secret-token-12345" }