Skip to content

initial Chrome Policy API support (google_chrome_policies resource + scaffolding)#17106

Open
keeleysam wants to merge 7 commits into
GoogleCloudPlatform:mainfrom
keeleysam:chromepolicy-support
Open

initial Chrome Policy API support (google_chrome_policies resource + scaffolding)#17106
keeleysam wants to merge 7 commits into
GoogleCloudPlatform:mainfrom
keeleysam:chromepolicy-support

Conversation

@keeleysam

@keeleysam keeleysam commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

This PR introduces the Chrome Policy API service in the Google Terraform provider with the google_chrome_policies resource for authoritative management of Chrome browser and ChromeOS policies.

Context

The Chrome Policy API manages browser and device policies for Google Workspace customers. There is currently no Terraform support for this API in the Google provider. The community terraform-provider-googleworkspace was archived by HashiCorp, leaving users without a maintained way to manage Chrome policies as code.

This implementation ports and improves upon the Chrome Policy resources from community forks of that provider, adapting them to magic-modules conventions.

Additional resources and data sources are ready and will be submitted as follow-up PRs once this foundation is merged.

Why handwritten?

The Chrome Policy API does not follow standard REST CRUD patterns. All mutation operations use RPC-style POST endpoints (batchModify, batchInherit) rather than standard GET/POST/PUT/DELETE on resource URLs. The read operation (resolve) is also a POST with a request body. This requires overriding all four CRUD methods, which per the contribution guidelines is the justification for handwritten resources.

The product.yaml auto-generates all provider plumbing (base path, endpoint config).

Why Plugin Framework?

This resources uses DynamicAttribute from the Terraform Plugin Framework. This allows the policies attribute to accept native HCL types (booleans, numbers, strings, lists) in value without requiring jsonencode() wrappers on every single field, which was one of the biggest pain points of the original version. DynamicAttribute is used for the policies list instead of SetNestedBlock because the Plugin Framework does not support dynamic types inside collections. If that limitation is addressed in a future framework release, this could be refactored to use block syntax.

What this PR adds

  • mmv1/products/chromepolicy/product.yaml — introduces the Chrome Policy service in MMv1
  • google_chrome_policies resource — authoritative management of all Chrome policies matching a schema filter for a target (org unit or group). Policies not declared in config are removed (inherited). Update does set-based diffing: only changed/added policies are sent via BatchModify, only removed policies via BatchInherit — at most 2 API calls per apply. Reorder-only changes make zero API calls.
  • chrome_policy_common.go — shared helpers for validation, batch operations, schema caching, and policy resolution (will be reused by follow-up resources)
  • Unit tests, acceptance test, documentation, meta.yaml

Design decisions

  • customer_id defaults to my_customer — the Workspace API alias for the authenticated account's customer. Multi-tenant users can override.
  • OAuth scope is user-configuredchrome.management.policy must be added to the provider scopes block. Not added to defaults since it would be inappropriate for users who don't use Chrome Policy.
  • Supports both org units and groups — via org_unit_id or group_id, both ForceNew.
  • schema_filter supports wildcards and exact names — wildcards (e.g. chrome.users.apps.*) manage entire policy namespaces authoritatively; exact names manage a single policy. Inferred automatically when only one policy is defined.

Precedent

Cloud Identity is already in the provider and is similarly a Workspace-adjacent API using customers/{customer_id} paths. The existing GOOGLE_CUST_ID test infrastructure supports Chrome Policy testing.

Release Note Template for Downstream PRs (will be copied)

`google_chrome_policies`

@modular-magician modular-magician added the awaiting-approval Pull requests that need reviewer's approval to run presubmit tests label Apr 14, 2026
@github-actions github-actions Bot requested a review from rileykarson April 14, 2026 02:10
@github-actions

github-actions Bot commented Apr 14, 2026

Copy link
Copy Markdown

Googlers: For automatic test runs see go/terraform-auto-test-runs.

@BBBmau, 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.

@rileykarson

Copy link
Copy Markdown
Member

@modular-magician reassign-reviewer

I'm OOO for a few days!

@github-actions github-actions Bot requested review from BBBmau and removed request for rileykarson April 14, 2026 17:44

@BBBmau BBBmau left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should refrain from having both resource and data-source in one PR. this is already quite complex given the nature of the Chrome Policy API.

Let's remove all mention of data-source and open it once we have resource merged.

Not only that but this is multiple resources being added in one PR. We should also pick the simplest resource in chrome policy API and have that be the starting point where we not only introduce the singular resource but also introduce the service in MMv1.

display_name: 'Chrome Policy'
versions:
- name: 'ga'
base_url: 'https://chromepolicy.googleapis.com/v1/'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this url returns a 404

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i believe this is expected, its just the base url and others 404 as well

@keeleysam keeleysam force-pushed the chromepolicy-support branch from 3a50c39 to 722ef1f Compare April 14, 2026 22:37
@github-actions github-actions Bot requested a review from BBBmau April 14, 2026 22:37
@keeleysam

Copy link
Copy Markdown
Contributor Author

@BBBmau i've stashed the bulk of this change into another branch, and now this PR should be much simpler, with scaffolding + a single resource

@keeleysam keeleysam force-pushed the chromepolicy-support branch from b16113c to 0b46add Compare April 14, 2026 23:11
@keeleysam keeleysam changed the title Add Chrome Policy API support (resources, data sources, and documentation) initial Chrome Policy API support (google_chrome_policies resource + scaffolding) Apr 15, 2026
@keeleysam keeleysam force-pushed the chromepolicy-support branch from 997bce2 to 5c6c92d Compare April 15, 2026 02:46
@keeleysam

Copy link
Copy Markdown
Contributor Author

updated docs and squashed commits, should be ready for review

@keeleysam keeleysam marked this pull request as draft April 15, 2026 16:05
@keeleysam

Copy link
Copy Markdown
Contributor Author

this is fully working, but i'm doing a bit more improvement this morning to this, simplifying behavior and making interface easier. will mark it back for review after a couple more commits

@keeleysam keeleysam force-pushed the chromepolicy-support branch 5 times, most recently from 3e065c9 to 06a5390 Compare April 16, 2026 00:51
@keeleysam keeleysam marked this pull request as ready for review April 16, 2026 00:54
Introduces the Chrome Policy API service in the Google Terraform
provider with an authoritative resource for managing Chrome browser
and ChromeOS policies for Google Workspace organizations.

Resource: google_chrome_policies

Manages all Chrome policies matching a schema filter for an org unit
or group. Policies not declared in config are removed (inherited from
parent). Supports wildcards (e.g. chrome.users.apps.*) for managing
entire policy namespaces, or exact schema names for individual
policies. Update logic does set-based diffing: only changed/added
policies are sent via BatchModify, only removed policies via
BatchInherit — at most 2 API calls per apply regardless of policy
count. Reorder-only changes make zero API calls.

Why Plugin Framework (not SDKv2):

Uses the Terraform Plugin Framework with a DynamicAttribute for the
policies list, which allows schema values to accept native HCL types
(booleans, numbers, strings, lists) without requiring jsonencode()
wrappers on every value. This is the first resource in the Google
provider to use DynamicAttribute.

DynamicAttribute is used instead of SetNestedBlock because the Plugin
Framework does not support dynamic types inside collections — this is
a known framework limitation (terraform-plugin-framework#973,
terraform#34574). If this is addressed in a future framework release,
the resource could be refactored to use block syntax.

Why handwritten (not MMv1):

The Chrome Policy API does not follow standard REST CRUD patterns.
All operations use RPC-style POST endpoints (batchModify, resolve,
batchInherit) rather than GET/POST/PUT/DELETE on resource URLs. This
requires overriding all four CRUD methods, which per the contribution
guidelines is the justification for handwritten resources.

The product.yaml auto-generates all provider plumbing (base path,
endpoint config). A typed Go client factory (NewChromePolicyClient)
is added for the handwritten resource's RPC-style API calls.
@keeleysam keeleysam force-pushed the chromepolicy-support branch from 06a5390 to 06e90ca Compare April 16, 2026 01:53
"displayName" to "Chronicle",
"path" to "./google/services/chronicle"
),
"chromepolicy" to mapOf(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is a new service being added you'll also need to enable it on our CI side, this can be done by including it in infra.tf. Here's a PR example of it being done:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added that :)

@github-actions github-actions Bot requested a review from BBBmau April 16, 2026 22:16
"blockchainnodeengine.googleapis.com",
"certificatemanager.googleapis.com",
"ces.googleapis.com",
"chromepolicy.googleapis.com",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be opened as a separate PR in order for the CI to be updated. if it gets added here CI will attempt to run it with the existing configuration on main

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resetting branch to commit without this, pulled this out into #17179

@modular-magician modular-magician removed the awaiting-approval Pull requests that need reviewer's approval to run presubmit tests label Apr 20, 2026
@modular-magician

Copy link
Copy Markdown
Collaborator

Hi there, I'm the Modular magician. I've detected the following information about your changes:

Diff report

Your PR generated some diffs in downstreams - here they are.

google provider: Diff ( 14 files changed, 1626 insertions(+))
google-beta provider: Diff ( 13 files changed, 1617 insertions(+))
terraform-google-conversion: Diff ( 3 files changed, 60 insertions(+))

@modular-magician

Copy link
Copy Markdown
Collaborator

Non-exercised tests

🔴 Tests were added that are skipped in VCR:

  • TestAccChromePolicies_basic

Tests analytics

Total tests: 6330
Passed tests: 5658
Skipped tests: 651
Affected tests: 21

Click here to see the affected service packages

All service packages are affected

Action taken

Found 21 affected test(s) by replaying old test recordings. Starting RECORDING based on the most recent commit. Click here to see the affected tests
  • TestAccApigeeOrganization_apigeeOrganizationCloudBasicDisableVpcPeeringTestExample
  • TestAccApigeeOrganization_apigeeOrganizationCloudFullDisableVpcPeeringTestExample
  • TestAccBeyondcorpAppConnection_beyondcorpAppConnectionBasicExample
  • TestAccCESApp_update
  • TestAccCESTool_cesToolDataStoreToolEngineSourceBasicExample
  • TestAccCESTool_cesToolDataStoreToolEngineSourceBasicExample_update
  • TestAccCloudRunService_cloudRunServiceGpuExample
  • TestAccComputeRouterPeer_AddMd5AuthenticationKey
  • TestAccContainerCluster_updateVersion
  • TestAccContainerCluster_withAutopilotResourceManagerTags
  • TestAccContainerCluster_withDatabaseEncryption
  • TestAccContainerCluster_withSandboxConfig
  • TestAccContainerNodePool_withHostMaintenancePolicy
  • TestAccDataSourceGoogleProjectService_basic
  • TestAccDataformConfig_update
  • TestAccDataformRepository_dataformRepositoryWithCloudsourceRepoAndSshExample
  • TestAccDataprocMetastoreService_dataprocMetastoreServicePrivateServiceConnectExample
  • TestAccDiscoveryEngineDataStore_discoveryengineDatastoreKmsKeyNameExample
  • TestAccManagedKafkaConnector_managedkafkaConnectorBasicExample
  • TestAccProjectIamMemberRemove_memberInMultipleBindings
  • TestAccPubsubSubscription_pubsubSubscriptionTagsExample

Get to know how VCR tests work

@modular-magician

Copy link
Copy Markdown
Collaborator

🟢 Tests passed during RECORDING mode:
TestAccComputeRouterPeer_AddMd5AuthenticationKey [Debug log]
TestAccContainerCluster_withSandboxConfig [Debug log]
TestAccDataformConfig_update [Debug log]
TestAccProjectIamMemberRemove_memberInMultipleBindings [Debug log]

🔴 Tests failed when rerunning REPLAYING mode:
TestAccDataformConfig_update [Error message] [Debug log]
TestAccProjectIamMemberRemove_memberInMultipleBindings [Error message] [Debug log]

Tests failed due to non-determinism or randomness when the VCR replayed the response after the HTTP request was made.

Please fix these to complete your PR. If you believe these test failures to be incorrect or unrelated to your change, or if you have any questions, please raise the concern with your reviewer.


🔴 Tests failed during RECORDING mode:
TestAccApigeeOrganization_apigeeOrganizationCloudBasicDisableVpcPeeringTestExample [Error message] [Debug log]
TestAccApigeeOrganization_apigeeOrganizationCloudFullDisableVpcPeeringTestExample [Error message] [Debug log]
TestAccBeyondcorpAppConnection_beyondcorpAppConnectionBasicExample [Error message] [Debug log]
TestAccCESApp_update [Error message] [Debug log]
TestAccCESTool_cesToolDataStoreToolEngineSourceBasicExample [Error message] [Debug log]
TestAccCESTool_cesToolDataStoreToolEngineSourceBasicExample_update [Error message] [Debug log]
TestAccCloudRunService_cloudRunServiceGpuExample [Error message] [Debug log]
TestAccContainerCluster_updateVersion [Error message] [Debug log]
TestAccContainerCluster_withAutopilotResourceManagerTags [Error message] [Debug log]
TestAccContainerCluster_withDatabaseEncryption [Error message] [Debug log]
TestAccContainerNodePool_withHostMaintenancePolicy [Error message] [Debug log]
TestAccDataSourceGoogleProjectService_basic [Error message] [Debug log]
TestAccDataformRepository_dataformRepositoryWithCloudsourceRepoAndSshExample [Error message] [Debug log]
TestAccDataprocMetastoreService_dataprocMetastoreServicePrivateServiceConnectExample [Error message] [Debug log]
TestAccDiscoveryEngineDataStore_discoveryengineDatastoreKmsKeyNameExample [Error message] [Debug log]
TestAccManagedKafkaConnector_managedkafkaConnectorBasicExample [Error message] [Debug log]
TestAccPubsubSubscription_pubsubSubscriptionTagsExample [Error message] [Debug log]

🔴 Errors occurred during RECORDING mode. Please fix them to complete your PR.

View the build log or the debug log for each test

@github-actions

Copy link
Copy Markdown

@BBBmau This PR has been waiting for review for 3 weekdays. Please take a look! Use the label disable-review-reminders to disable these notifications.

@github-actions

Copy link
Copy Markdown

@GoogleCloudPlatform/terraform-team @BBBmau This PR has been waiting for review for 1 week. Please take a look! Use the label disable-review-reminders to disable these notifications.

@modular-magician modular-magician added the awaiting-approval Pull requests that need reviewer's approval to run presubmit tests label Apr 27, 2026
return clientCloudIdentity
}

func (c *Config) NewChromePolicyClient(userAgent string) *chromepolicy.Service {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we absolutely need to utilize the client library?

What's preventing us from using tpgresource.SendRequest? We tend to stay away from client libraries due to dependency management where a new field may not be released due to underlying issues with bumping to the desired version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point - this API is simple enough that we can follow this path. updating the PR

Drops the chromepolicy/v1 typed client library in favor of raw HTTP
calls via transport_tpg.SendRequest, matching the convention used by
other handwritten resources. This avoids the dependency-management
overhead where a new field can be blocked on a client-library bump.

The Chrome Policy API surface here (4 endpoints: schema get, resolve,
batchModify, batchInherit) is JSON-in/JSON-out, and policy values were
already passed as raw bytes — so the typed client wasn't buying type
safety where it mattered.

- Replaces NewChromePolicyClient with a small chromePolicyAPI helper
- Replaces SDKv2 diag.Diagnostics with plain error returns
- No change to the resource's HCL surface or behavior
@github-actions github-actions Bot requested a review from BBBmau April 28, 2026 22:43
@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown

@BBBmau This PR has been waiting for review for 3 weekdays. Please take a look! Use the label disable-review-reminders to disable these notifications.

@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown

@GoogleCloudPlatform/terraform-team @BBBmau This PR has been waiting for review for 1 week. Please take a look! Use the label disable-review-reminders to disable these notifications.

@github-actions

Copy link
Copy Markdown

@GoogleCloudPlatform/terraform-team @BBBmau This PR has been waiting for review for 2 weeks. Please take a look! Use the label disable-review-reminders to disable these notifications.

@github-actions

Copy link
Copy Markdown

@GoogleCloudPlatform/terraform-team @BBBmau This PR has been waiting for review for 3 weeks. Please take a look! Use the label disable-review-reminders to disable these notifications.

keeleysam added 2 commits May 20, 2026 17:02
Resolve conflict in fwprovider/framework_provider.go.tmpl: main migrated framework resource registration to a self-registering pattern via registry.FrameworkResourceFuncs(). Drop the per-service imports and explicit Resources() list this branch added; instead register google_chrome_policies in an init() block in the chromepolicy package, matching the apigee/storage convention.

Signed-off-by: Samuel Keeley <samuel@keeley.net>
…oved Config field

main removed the per-product BasePath fields from transport.Config in favour of resolving base URLs through registry.GetProduct(<product>) + transport.BaseUrl(...). Update chrome_policy_common.go's url() helper to match — the previous a.config.ChromePolicyBasePath reference no longer compiles. Other services (apigee, storage, etc.) already use the same pattern via tpgresource.ReplaceVars; this is the equivalent for our hand-built API client wrapper that doesn't go through the template-based URL substitution.

Signed-off-by: Samuel Keeley <samuel@keeley.net>
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

@GoogleCloudPlatform/terraform-team @BBBmau This PR has been waiting for review for 5 weeks. Please take a look! Use the label disable-review-reminders to disable these notifications.

@BBBmau BBBmau left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR still needs to be broken down into individual PRs due to this being a 1400 line PR

@github-actions

Copy link
Copy Markdown

@keeleysam, 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.

Image showing the re-request review button

This notification can be disabled with the disable-automatic-closure label.

@github-actions

Copy link
Copy Markdown

@keeleysam, 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.

Image showing the re-request review button

This notification can be disabled with the disable-automatic-closure label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-approval Pull requests that need reviewer's approval to run presubmit tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants