Community Note
- Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request.
- Please do not leave +1 or me too comments, they generate extra noise for issue followers and do not help prioritize the request.
- If you are interested in working on this issue or have submitted a pull request, please leave a comment.
- If an issue is assigned to a user, that user is claiming responsibility for the issue.
- Customers working with a Google Technical Account Manager or Customer Engineer can ask them to reach out internally to expedite investigation and resolution of this issue.
Terraform Version & Provider Version(s)
Terraform v1.15.7
on linux_amd64
+ provider registry.terraform.io/hashicorp/google v7.38.0
The same relevant generated source is still present in provider v7.41.0 and the current main branch.
Affected Resource(s)
google_recaptcha_enterprise_key
Terraform Configuration
Apply this initial configuration:
resource "google_recaptcha_enterprise_key" "example" {
project = var.project_id
display_name = "policy-based-challenge-example"
web_settings {
integration_type = "POLICY_BASED_CHALLENGE"
allow_all_domains = false
allowed_domains = ["example.com"]
challenge_settings {
default_settings {
score_threshold = 0.1
}
action_settings {
action = "auth_email"
score_threshold = 0.45
}
action_settings {
action = "auth_phone"
score_threshold = 0.1
}
}
}
}
Then change only the membership of action_settings:
resource "google_recaptcha_enterprise_key" "example" {
project = var.project_id
display_name = "policy-based-challenge-example"
web_settings {
integration_type = "POLICY_BASED_CHALLENGE"
allow_all_domains = false
allowed_domains = ["example.com"]
challenge_settings {
default_settings {
score_threshold = 0.1
}
action_settings {
action = "auth"
score_threshold = 0.45
}
}
}
}
Debug Output
Standard Terraform logs report an in-place modification completing successfully, but do not contain a PATCH request or updateMask. Cloud Audit Logs contain no UpdateKey event for the apply window.
Expected Behavior
The provider should send an update to replace the two existing action-map entries with the single auth entry.
After apply:
- a direct
projects.keys.get request should return only auth = 0.45;
- Terraform state should contain only
auth = 0.45;
- a refresh should detect any difference between state and the live API.
Actual Behavior
The Terraform plan correctly reports one in-place update:
Plan: 0 to add, 1 to change, 0 to destroy.
The apply reports success after approximately one second. However:
- no PATCH request is sent to the reCAPTCHA Enterprise API;
- no
UpdateKey audit event is created;
- direct REST GET and
gcloud recaptcha keys describe continue to return the old auth_email and auth_phone entries after more than 45 minutes;
- Terraform state is nevertheless rewritten to contain only
auth;
- the next refresh/plan incorrectly reports
0 to change.
This creates a false-success result and hides live drift.
Steps to reproduce
- Apply the initial configuration.
- Confirm with
projects.keys.get that the key contains auth_email and auth_phone.
- Replace both action blocks with the single
auth action shown above.
- Run
terraform plan and observe an in-place update.
- Run
terraform apply.
- Query the key directly with
projects.keys.get.
- Run another Terraform refresh/plan.
Root cause analysis
The problem occurs before PATCH/update-mask generation:
- The resource update builds a desired object and calls
ApplyKey:
resource_recaptcha_enterprise_key.go.
keyDiffsForRawDesired uses the complete desired object as fetchState and passes it to GetKey:
key_internal.go.
GetKey retrieves the real REST response and then canonicalizes it with the supplied desired object:
key.go.
canonicalizeNewKeyWebSettingsChallengeSettingsActionSettingsMap iterates only over desired map keys. A desired-only key is copied into the canonicalized result, while actual-only keys are omitted:
key_internal.go.
- The canonicalized initial state and desired state therefore both contain only
auth. The internal diff is empty, the operation list is empty, and the PATCH code is never reached:
key.go.
The same canonicalization during reads also explains why subsequent refreshes mask the live drift.
The existing policy-based challenge acceptance test updates score values while keeping the same login and signup map keys. It does not cover adding, removing, or renaming action-map keys:
resource_recaptcha_enterprise_key_generated_test.go.
Suggested fix
The map canonicalizer should preserve the distinction between desired-only and actual-only map entries until after the internal diff is calculated. Please also add an acceptance-test step that changes the action map from two keys to a differently named single key and verifies the live API response, not only Terraform state.
Important Factoids
- The default Google endpoint is used.
- Authentication uses a service account.
- No custom provider endpoint or manual concurrent key update is involved.
- Updating scalar thresholds while retaining the same action-map keys follows a different path and is already covered by the existing acceptance test.
References
b/539545848
Community Note
Terraform Version & Provider Version(s)
The same relevant generated source is still present in provider v7.41.0 and the current
mainbranch.Affected Resource(s)
google_recaptcha_enterprise_keyTerraform Configuration
Apply this initial configuration:
Then change only the membership of
action_settings:Debug Output
Standard Terraform logs report an in-place modification completing successfully, but do not contain a PATCH request or
updateMask. Cloud Audit Logs contain noUpdateKeyevent for the apply window.Expected Behavior
The provider should send an update to replace the two existing action-map entries with the single
authentry.After apply:
projects.keys.getrequest should return onlyauth = 0.45;auth = 0.45;Actual Behavior
The Terraform plan correctly reports one in-place update:
The apply reports success after approximately one second. However:
UpdateKeyaudit event is created;gcloud recaptcha keys describecontinue to return the oldauth_emailandauth_phoneentries after more than 45 minutes;auth;0 to change.This creates a false-success result and hides live drift.
Steps to reproduce
projects.keys.getthat the key containsauth_emailandauth_phone.authaction shown above.terraform planand observe an in-place update.terraform apply.projects.keys.get.Root cause analysis
The problem occurs before PATCH/update-mask generation:
ApplyKey:resource_recaptcha_enterprise_key.go.keyDiffsForRawDesireduses the complete desired object asfetchStateand passes it toGetKey:key_internal.go.GetKeyretrieves the real REST response and then canonicalizes it with the supplied desired object:key.go.canonicalizeNewKeyWebSettingsChallengeSettingsActionSettingsMapiterates only over desired map keys. A desired-only key is copied into the canonicalized result, while actual-only keys are omitted:key_internal.go.auth. The internal diff is empty, the operation list is empty, and the PATCH code is never reached:key.go.The same canonicalization during reads also explains why subsequent refreshes mask the live drift.
The existing policy-based challenge acceptance test updates score values while keeping the same
loginandsignupmap keys. It does not cover adding, removing, or renaming action-map keys:resource_recaptcha_enterprise_key_generated_test.go.Suggested fix
The map canonicalizer should preserve the distinction between desired-only and actual-only map entries until after the internal diff is calculated. Please also add an acceptance-test step that changes the action map from two keys to a differently named single key and verifies the live API response, not only Terraform state.
Important Factoids
References
b/539545848