Fix enforce field in google_securityposture_posture always being sent…#17147
Fix enforce field in google_securityposture_posture always being sent…#17147steffencircle wants to merge 11 commits into
Conversation
|
Googlers: For automatic test runs see go/terraform-auto-test-runs. @c2thorn, a repository maintainer, has been assigned to review your changes. If you have not received review feedback within 2 business days, please leave a comment on this PR asking them to take a look. You can help make sure that review is quick by doing a self-review and by running impacted tests locally. |
|
@c2thorn This PR has been waiting for review for 3 weekdays. Please take a look! Use the label |
|
@GoogleCloudPlatform/terraform-team @c2thorn This PR has been waiting for review for 1 week. Please take a look! Use the label |
c2thorn
left a comment
There was a problem hiding this comment.
Given the complexity of the expander, can we add unit testing for securitypostureGetEnforceIsSetForOrgPolicyConstraint?
We can use schema.TestResourceDataRaw to mock the state and verify that the function correctly identifies when enforce is set or omitted, without needing to run full acceptance tests.
| } | ||
| for opcIt := orgPolicyConstraint.ElementIterator(); opcIt.Next(); { | ||
| _, opcVal := opcIt.Element() | ||
| idVal := opcVal.GetAttr("canned_constraint_id") |
There was a problem hiding this comment.
Should we identify by policy_id instead of canned_constraint_id to handle cases where the same constraint might be used multiple times in a posture?
There was a problem hiding this comment.
Since there is one constraint per policy?
|
running the build |
|
Hi there, I'm the Modular magician. I've detected the following information about your changes: Diff reportYour PR generated some diffs in downstreams - here they are.
|
Tests analyticsTotal tests: 3 Click here to see the affected service packages
Action takenFound 2 affected test(s) by replaying old test recordings. Starting RECORDING based on the most recent commit. Click here to see the affected tests
|
|
@steffencircle, this PR is waiting for action from you. If no action is taken, this PR will be closed in 28 days. Please address any comments or change requests, or re-request review from a core reviewer if no action is required. This notification can be disabled with the |
|
@steffencircle, this PR is waiting for action from you. If no action is taken, this PR will be closed in 14 days. Please address any comments or change requests, or re-request review from a core reviewer if no action is required. This notification can be disabled with the |
|
@steffencircle, this PR is waiting for action from you. If no action is taken, this PR will be closed in 2 weekdays. Please address any comments or change requests, or re-request review from a core reviewer if no action is required. This notification can be disabled with the |
…cy_id resolution and add unit tests
…b.com/steffencircle/magic-modules into bugfix/google_securityposture_posture
Changes addressing reviewer feedback1. Disambiguate by
|
|
@c2thorn This PR has been waiting for review for 3 weekdays. Please take a look! Use the label |
|
@GoogleCloudPlatform/terraform-team @c2thorn This PR has been waiting for review for 1 week. Please take a look! Use the label |
|
@GoogleCloudPlatform/terraform-team @c2thorn This PR has been waiting for review for 2 weeks. Please take a look! Use the label |
|
Thanks for the back and forth on this issue, @steffencircle. Before you put more into the With
The other cost is maintenance. "Don't send // rough sketch
func resourceSecurityposturePostureEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
for _, ps := range obj["policySets"].([]interface{}) {
for _, p := range ps.(map[string]interface{})["policies"].([]interface{}) {
constraint, _ := p.(map[string]interface{})["constraint"].(map[string]interface{})
opc, _ := constraint["orgPolicyConstraint"].(map[string]interface{})
rules, _ := opc["policyRules"].([]interface{})
for _, r := range rules {
rule := r.(map[string]interface{})
_, isList := rule["values"]
_, hasAllow := rule["allowAll"]
_, hasDeny := rule["denyAll"]
if isList || hasAllow || hasDeny {
delete(rule, "enforce") // enforce is only valid for boolean constraints
}
}
}
}
return obj, nil
}No Boolean constraint with Let me know what you think. |
c2thorn
left a comment
There was a problem hiding this comment.
see #17147 (comment)
I think we need to switch to a smaller encoder vs this large expander

Fix
enforcefield ingoogle_securityposture_posturealways being sent asfalseProblem
The
enforceattribute withinpolicy_sets[*].policies[*].constraint[*].org_policy_constraint[*].policy_rules[*]is optional and only valid for boolean constraints. For list constraints (which usevalues,allow_all, ordeny_allinstead), sendingenforce: falseto the API causes an error.The field was previously marked with
send_empty_value: true( added by myself in #16796 ) to allow users to explicitly setenforce = falsein their Terraform config (sincefalseis the Go zero value and would otherwise be dropped by theIsEmptyValueguard). However, this introduced a regression:send_empty_value: trueworks correctly for top-level properties, where the template generates:For nested properties inside arrays, the template instead generates an unconditional bare
else:At that point in the expand call stack, the value has already been deserialized from Terraform state as a plain Go
map[string]interface{}, where an unsetTypeBoolis indistinguishable fromfalse. The result was thatenforce: falsewas always included in every API request, regardless of whether the user had set it.Solution
Replace
send_empty_value: truewith acustom_expandon theorgPolicyConstraintNestedObject. The custom template is fully self-contained (inlining all nested field expansion) because placingcustom_expandon a NestedObject prevents the MMv1 template engine from recursively generating child expand functions.For the
enforcefield specifically, the custom expander callsd.GetRawConfig()which returns the unprocessed cty value tree from the Terraform configuration. In the cty type system, an omitted optional field iscty.NullVal(cty.Bool), while an explicitly configuredenforce = falseiscty.False— these are distinguishable. The helper functionsecuritypostureGetEnforceIsSetForOrgPolicyConstrainttraverses the raw config tree, locates the matchingorg_policy_constraintblock bycanned_constraint_id, and returns a per-rule boolean slice indicating whetherenforcewas explicitly set. Only rules where it was explicitly set includeenforcein the API request body.Behaviour after this change
enforceomittedenforcenot sentenforce = trueenforce: truesentenforce = falseenforce: falsesentFiles changed
send_empty_value: truefromenforceunderorgPolicyConstraint.policyRules; addedcustom_expandreference to theorgPolicyConstraintpropertypolicy_setsblock to both thefullandupdatetest configs using the list constraintconstraints/gcp.resourceLocationswithallowed_values = ["in:us-locations"]andenforceintentionally omitted, directly exercising the regression scenariopolicy_setsblock added to both thebasicandupdateconfigs for the same reasonRelease Note Template for Downstream PRs (will be copied)
See Write release notes for guidance.