From cae85e2723a858e8d05db8dc106a43f32225ffb5 Mon Sep 17 00:00:00 2001
From: Pedro Pombeiro <noreply@pedro.pombei.ro>
Date: Thu, 15 Feb 2024 13:59:13 +0000
Subject: [PATCH] GraphQL: Allow specifying Google Cloud project

EE: true
---
 .../graphql_shared/possible_types.json        |   3 +
 doc/api/graphql/reference/index.md            |  69 ++++++------
 ee/app/graphql/ee/types/project_type.rb       |  16 +--
 ...runner_cloud_provisioning_base_resolver.rb |  31 ------
 ...oud_provisioning_machine_types_resolver.rb |  26 -----
 ...ner_cloud_provisioning_regions_resolver.rb |  22 ----
 ...unner_cloud_provisioning_zones_resolver.rb |  29 -----
 .../runner_cloud_provisioning_options_type.rb |  29 ++---
 ..._google_cloud_provisioning_options_type.rb | 101 ++++++++++++++++++
 .../compute/base_service.rb                   |   2 +-
 ...er_cloud_provisioning_options_type_spec.rb |  35 ++++++
 ee/spec/graphql/types/project_type_spec.rb    |  12 +--
 .../compute/client_spec.rb                    |   2 +-
 ...google_cloud_provisioning_options_spec.rb} |  16 ++-
 .../list_machine_types_service_spec.rb        |   7 +-
 .../compute/list_regions_service_spec.rb      |   7 +-
 .../compute/list_zones_service_spec.rb        |   7 +-
 .../compute/services_shared_contexts.rb       |   5 +-
 .../compute/services_shared_examples.rb       |  20 ++++
 19 files changed, 254 insertions(+), 185 deletions(-)
 delete mode 100644 ee/app/graphql/resolvers/ci/runner_cloud_provisioning_base_resolver.rb
 delete mode 100644 ee/app/graphql/resolvers/ci/runner_cloud_provisioning_machine_types_resolver.rb
 delete mode 100644 ee/app/graphql/resolvers/ci/runner_cloud_provisioning_regions_resolver.rb
 delete mode 100644 ee/app/graphql/resolvers/ci/runner_cloud_provisioning_zones_resolver.rb
 create mode 100644 ee/app/graphql/types/ci/runner_google_cloud_provisioning_options_type.rb
 create mode 100644 ee/spec/graphql/types/ci/runner_cloud_provisioning_options_type_spec.rb
 rename ee/spec/requests/api/graphql/project/{runner_cloud_provisioning_options_spec.rb => runner_google_cloud_provisioning_options_spec.rb} (94%)

diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json
index 1322d4082c8f6..9584f2fcd8f4c 100644
--- a/app/assets/javascripts/graphql_shared/possible_types.json
+++ b/app/assets/javascripts/graphql_shared/possible_types.json
@@ -11,6 +11,9 @@
     "AuditEventStreamingHeader",
     "AuditEventsStreamingInstanceHeader"
   ],
+  "CiRunnerCloudProvisioningOptions": [
+    "CiRunnerGoogleCloudProvisioningOptions"
+  ],
   "CiVariable": [
     "CiGroupVariable",
     "CiInstanceVariable",
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index e27e26cdbfeff..54fe0a0284dba 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -16443,19 +16443,41 @@ Machine type used for runner cloud provisioning.
 | <a id="cirunnercloudprovisioningmachinetypename"></a>`name` | [`String`](#string) | Name of the machine type. |
 | <a id="cirunnercloudprovisioningmachinetypezone"></a>`zone` | [`String`](#string) | Zone of the machine type. |
 
-### `CiRunnerCloudProvisioningOptions`
+### `CiRunnerCloudProvisioningRegion`
 
-Options for runner cloud provisioning.
+Region used for runner cloud provisioning.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cirunnercloudprovisioningregiondescription"></a>`description` | [`String`](#string) | Description of the region. |
+| <a id="cirunnercloudprovisioningregionname"></a>`name` | [`String`](#string) | Name of the region. |
+
+### `CiRunnerCloudProvisioningZone`
+
+Zone used for runner cloud provisioning.
 
 #### Fields
 
 | Name | Type | Description |
 | ---- | ---- | ----------- |
-| <a id="cirunnercloudprovisioningoptionsregions"></a>`regions` | [`CiRunnerCloudProvisioningRegionConnection`](#cirunnercloudprovisioningregionconnection) | Regions available for provisioning a runner. (see [Connections](#connections)) |
+| <a id="cirunnercloudprovisioningzonedescription"></a>`description` | [`String`](#string) | Description of the zone. |
+| <a id="cirunnercloudprovisioningzonename"></a>`name` | [`String`](#string) | Name of the zone. |
+
+### `CiRunnerGoogleCloudProvisioningOptions`
+
+Options for runner Google Cloud provisioning.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="cirunnergooglecloudprovisioningoptionsregions"></a>`regions` | [`CiRunnerCloudProvisioningRegionConnection`](#cirunnercloudprovisioningregionconnection) | Regions available for provisioning a runner. (see [Connections](#connections)) |
 
 #### Fields with arguments
 
-##### `CiRunnerCloudProvisioningOptions.machineTypes`
+##### `CiRunnerGoogleCloudProvisioningOptions.machineTypes`
 
 Machine types available for provisioning a runner.
 
@@ -16469,9 +16491,9 @@ four standard [pagination arguments](#connection-pagination-arguments):
 
 | Name | Type | Description |
 | ---- | ---- | ----------- |
-| <a id="cirunnercloudprovisioningoptionsmachinetypeszone"></a>`zone` | [`String!`](#string) | Zone for which to retrieve machine types. |
+| <a id="cirunnergooglecloudprovisioningoptionsmachinetypeszone"></a>`zone` | [`String!`](#string) | Zone to retrieve machine types for. |
 
-##### `CiRunnerCloudProvisioningOptions.zones`
+##### `CiRunnerGoogleCloudProvisioningOptions.zones`
 
 Zones available for provisioning a runner.
 
@@ -16485,29 +16507,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
 
 | Name | Type | Description |
 | ---- | ---- | ----------- |
-| <a id="cirunnercloudprovisioningoptionszonesregion"></a>`region` | [`String`](#string) | Region for which to retrieve zones. Returns all zones if not specified. |
-
-### `CiRunnerCloudProvisioningRegion`
-
-Region used for runner cloud provisioning.
-
-#### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="cirunnercloudprovisioningregiondescription"></a>`description` | [`String`](#string) | Description of the region. |
-| <a id="cirunnercloudprovisioningregionname"></a>`name` | [`String`](#string) | Name of the region. |
-
-### `CiRunnerCloudProvisioningZone`
-
-Zone used for runner cloud provisioning.
-
-#### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="cirunnercloudprovisioningzonedescription"></a>`description` | [`String`](#string) | Description of the zone. |
-| <a id="cirunnercloudprovisioningzonename"></a>`name` | [`String`](#string) | Name of the zone. |
+| <a id="cirunnergooglecloudprovisioningoptionszonesregion"></a>`region` | [`String`](#string) | Region to retrieve zones for. Returns all zones if not specified. |
 
 ### `CiRunnerManager`
 
@@ -26273,7 +26273,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
 
 ##### `Project.runnerCloudProvisioningOptions`
 
-Options for runner cloud provisioning by a specified cloud provider. Returns `null` if `:google_cloud_runner_provisioning` feature flag is disabled, or the GitLab instance is not a SaaS instance.
+Options for provisioning the runner on Google Cloud. Returns `null` if `:google_cloud_runner_provisioning` feature flag is disabled, or the GitLab instance is not a SaaS instance.
 
 NOTE:
 **Introduced** in 16.9.
@@ -26285,6 +26285,7 @@ Returns [`CiRunnerCloudProvisioningOptions`](#cirunnercloudprovisioningoptions).
 
 | Name | Type | Description |
 | ---- | ---- | ----------- |
+| <a id="projectrunnercloudprovisioningoptionscloudprojectid"></a>`cloudProjectId` | [`String!`](#string) | Identifier of the cloud project. |
 | <a id="projectrunnercloudprovisioningoptionsprovider"></a>`provider` | [`CiRunnerCloudProvider!`](#cirunnercloudprovider) | Identifier of the cloud provider. |
 
 ##### `Project.runners`
@@ -34014,6 +34015,14 @@ abstract types.
 
 ### Unions
 
+#### `CiRunnerCloudProvisioningOptions`
+
+Options for runner cloud provisioning.
+
+One of:
+
+- [`CiRunnerGoogleCloudProvisioningOptions`](#cirunnergooglecloudprovisioningoptions)
+
 #### `DependencyLinkMetadata`
 
 Represents metadata associated with a dependency link.
diff --git a/ee/app/graphql/ee/types/project_type.rb b/ee/app/graphql/ee/types/project_type.rb
index 9f26eb371fe76..7018f03110b04 100644
--- a/ee/app/graphql/ee/types/project_type.rb
+++ b/ee/app/graphql/ee/types/project_type.rb
@@ -342,11 +342,13 @@ module ProjectType
           ::Types::Ci::RunnerCloudProvisioningOptionsType,
           null: true,
           alpha: { milestone: '16.9' },
-          description: 'Options for runner cloud provisioning by a specified cloud provider. ' \
+          description: 'Options for provisioning the runner on Google Cloud. ' \
                        'Returns `null` if `:google_cloud_runner_provisioning` feature flag is disabled, ' \
                        'or the GitLab instance is not a SaaS instance.' do
                          argument :provider, ::Types::Ci::RunnerCloudProviderEnum, required: true,
                            description: 'Identifier of the cloud provider.'
+                         argument :cloud_project_id, GraphQL::Types::String, required: true,
+                           description: 'Identifier of the cloud project.'
                        end
 
         field :ai_agents, ::Types::Ai::Agents::AgentType.connection_type,
@@ -406,14 +408,14 @@ def compliance_frameworks
         end
       end
 
-      # TODO To be removed along with :google_cloud_runner_provisioning feature flag.
-      # Use `method: :itself` on the related field (see https://graphql-ruby.org/fields/introduction.html#field-resolution).
-      # TODO Before unmarking the field as alpha, figure out solution for polymorphism based on provider argument,
-      #      so that child objects call the correct cloud services
-      def runner_cloud_provisioning_options(provider:) # rubocop:disable Lint/UnusedMethodArgument -- Only one provider type is possible, and is already enforced by GraphQL
+      def runner_cloud_provisioning_options(provider:, cloud_project_id:)
         return if ::Feature.disabled?(:google_cloud_runner_provisioning, project)
 
-        project
+        {
+          project: project,
+          provider: provider,
+          cloud_project_id: cloud_project_id
+        }
       end
 
       def google_cloud_artifact_registry_repository
diff --git a/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_base_resolver.rb b/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_base_resolver.rb
deleted file mode 100644
index 660234a337bb9..0000000000000
--- a/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_base_resolver.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
-  module Ci
-    # rubocop: disable Graphql/ResolverType -- the type is decided on the derived resolver class
-    class RunnerCloudProvisioningBaseResolver < BaseResolver
-      include Gitlab::Graphql::Authorize::AuthorizeResource
-
-      authorize :read_runner_cloud_provisioning_options
-
-      private
-
-      alias_method :project, :object
-
-      def default_params(after, first)
-        { max_results: first, page_token: after }.compact
-      end
-
-      def externally_paginated_array(response, after)
-        raise_resource_not_available_error!(response.message) if response.error?
-
-        Gitlab::Graphql::ExternallyPaginatedArray.new(
-          after,
-          response.payload[:next_page_token],
-          *response.payload[:items]
-        )
-      end
-    end
-    # rubocop: enable Graphql/ResolverType
-  end
-end
diff --git a/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_machine_types_resolver.rb b/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_machine_types_resolver.rb
deleted file mode 100644
index ac64b780534fe..0000000000000
--- a/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_machine_types_resolver.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
-  module Ci
-    class RunnerCloudProvisioningMachineTypesResolver < Resolvers::Ci::RunnerCloudProvisioningBaseResolver
-      type Types::Ci::RunnerCloudProvisioningMachineTypeType.connection_type, null: true
-
-      description 'Machine types available for provisioning a runner.'
-
-      argument :zone, GraphQL::Types::String,
-        required: true,
-        description: 'Zone for which to retrieve machine types.'
-
-      max_page_size GoogleCloudPlatform::Compute::ListMachineTypesService::MAX_RESULTS_LIMIT
-      default_page_size GoogleCloudPlatform::Compute::ListMachineTypesService::MAX_RESULTS_LIMIT
-
-      def resolve(zone:, after: nil, first: nil)
-        response = GoogleCloudPlatform::Compute::ListMachineTypesService
-          .new(project: project, current_user: current_user, zone: zone, params: default_params(after, first))
-          .execute
-
-        externally_paginated_array(response, after)
-      end
-    end
-  end
-end
diff --git a/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_regions_resolver.rb b/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_regions_resolver.rb
deleted file mode 100644
index bc641b3dcdd58..0000000000000
--- a/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_regions_resolver.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
-  module Ci
-    class RunnerCloudProvisioningRegionsResolver < Resolvers::Ci::RunnerCloudProvisioningBaseResolver
-      type Types::Ci::RunnerCloudProvisioningRegionType.connection_type, null: true
-
-      description 'Regions available for provisioning a runner.'
-
-      max_page_size GoogleCloudPlatform::Compute::ListRegionsService::MAX_RESULTS_LIMIT
-      default_page_size GoogleCloudPlatform::Compute::ListRegionsService::MAX_RESULTS_LIMIT
-
-      def resolve(after: nil, first: nil)
-        response = GoogleCloudPlatform::Compute::ListRegionsService
-          .new(project: project, current_user: current_user, params: default_params(after, first))
-          .execute
-
-        externally_paginated_array(response, after)
-      end
-    end
-  end
-end
diff --git a/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_zones_resolver.rb b/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_zones_resolver.rb
deleted file mode 100644
index 72cd216eb9fe8..0000000000000
--- a/ee/app/graphql/resolvers/ci/runner_cloud_provisioning_zones_resolver.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
-  module Ci
-    class RunnerCloudProvisioningZonesResolver < Resolvers::Ci::RunnerCloudProvisioningBaseResolver
-      type Types::Ci::RunnerCloudProvisioningZoneType.connection_type, null: true
-
-      description 'Zones available for provisioning a runner.'
-
-      argument :region, GraphQL::Types::String,
-        required: false,
-        description: 'Region for which to retrieve zones. Returns all zones if not specified.'
-
-      max_page_size GoogleCloudPlatform::Compute::ListZonesService::MAX_RESULTS_LIMIT
-      default_page_size GoogleCloudPlatform::Compute::ListZonesService::MAX_RESULTS_LIMIT
-
-      def resolve(region: nil, after: nil, first: nil)
-        params = default_params(after, first)
-        params[:filter] = "name=#{region}-*" if region
-
-        response = GoogleCloudPlatform::Compute::ListZonesService
-          .new(project: project, current_user: current_user, params: params)
-          .execute
-
-        externally_paginated_array(response, after)
-      end
-    end
-  end
-end
diff --git a/ee/app/graphql/types/ci/runner_cloud_provisioning_options_type.rb b/ee/app/graphql/types/ci/runner_cloud_provisioning_options_type.rb
index dc7f52e3d7b94..35e1cca7f4292 100644
--- a/ee/app/graphql/types/ci/runner_cloud_provisioning_options_type.rb
+++ b/ee/app/graphql/types/ci/runner_cloud_provisioning_options_type.rb
@@ -2,29 +2,22 @@
 
 module Types
   module Ci
-    class RunnerCloudProvisioningOptionsType < BaseObject
+    class RunnerCloudProvisioningOptionsType < BaseUnion
       graphql_name 'CiRunnerCloudProvisioningOptions'
       description 'Options for runner cloud provisioning.'
 
-      include Gitlab::Graphql::Authorize::AuthorizeResource
+      UnexpectedProviderType = Class.new(StandardError)
 
-      authorize :read_runner_cloud_provisioning_options
+      possible_types ::Types::Ci::RunnerGoogleCloudProvisioningOptionsType
 
-      field :regions, Types::Ci::RunnerCloudProvisioningRegionType.connection_type,
-        null: true,
-        resolver: ::Resolvers::Ci::RunnerCloudProvisioningRegionsResolver,
-        connection_extension: Gitlab::Graphql::Extensions::ForwardOnlyExternallyPaginatedArrayExtension
-
-      field :zones, Types::Ci::RunnerCloudProvisioningZoneType.connection_type,
-        null: true,
-        resolver: ::Resolvers::Ci::RunnerCloudProvisioningZonesResolver,
-        connection_extension: Gitlab::Graphql::Extensions::ForwardOnlyExternallyPaginatedArrayExtension
-
-      field :machine_types,
-        Types::Ci::RunnerCloudProvisioningMachineTypeType.connection_type,
-        null: true,
-        resolver: ::Resolvers::Ci::RunnerCloudProvisioningMachineTypesResolver,
-        connection_extension: Gitlab::Graphql::Extensions::ForwardOnlyExternallyPaginatedArrayExtension
+      def self.resolve_type(object, _context)
+        case object[:provider]
+        when :google_cloud
+          ::Types::Ci::RunnerGoogleCloudProvisioningOptionsType
+        else
+          raise UnexpectedProviderType, 'Unsupported CI runner cloud provider'
+        end
+      end
     end
   end
 end
diff --git a/ee/app/graphql/types/ci/runner_google_cloud_provisioning_options_type.rb b/ee/app/graphql/types/ci/runner_google_cloud_provisioning_options_type.rb
new file mode 100644
index 0000000000000..f5bbe2b8bf97d
--- /dev/null
+++ b/ee/app/graphql/types/ci/runner_google_cloud_provisioning_options_type.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+module Types
+  module Ci
+    class RunnerGoogleCloudProvisioningOptionsType < BaseObject
+      graphql_name 'CiRunnerGoogleCloudProvisioningOptions'
+      description 'Options for runner Google Cloud provisioning.'
+
+      include Gitlab::Graphql::Authorize::AuthorizeResource
+
+      authorize :read_runner_cloud_provisioning_options
+
+      field :regions, Types::Ci::RunnerCloudProvisioningRegionType.connection_type,
+        description: 'Regions available for provisioning a runner.',
+        null: true,
+        connection_extension: Gitlab::Graphql::Extensions::ForwardOnlyExternallyPaginatedArrayExtension,
+        max_page_size: GoogleCloudPlatform::Compute::ListRegionsService::MAX_RESULTS_LIMIT,
+        default_page_size: GoogleCloudPlatform::Compute::ListRegionsService::MAX_RESULTS_LIMIT
+
+      field :zones, Types::Ci::RunnerCloudProvisioningZoneType.connection_type,
+        description: 'Zones available for provisioning a runner.',
+        null: true,
+        connection_extension: Gitlab::Graphql::Extensions::ForwardOnlyExternallyPaginatedArrayExtension,
+        max_page_size: GoogleCloudPlatform::Compute::ListZonesService::MAX_RESULTS_LIMIT,
+        default_page_size: GoogleCloudPlatform::Compute::ListZonesService::MAX_RESULTS_LIMIT do
+          argument :region, GraphQL::Types::String, required: false,
+            description: 'Region to retrieve zones for. Returns all zones if not specified.'
+        end
+
+      field :machine_types,
+        Types::Ci::RunnerCloudProvisioningMachineTypeType.connection_type,
+        description: 'Machine types available for provisioning a runner.',
+        null: true,
+        connection_extension: Gitlab::Graphql::Extensions::ForwardOnlyExternallyPaginatedArrayExtension,
+        max_page_size: GoogleCloudPlatform::Compute::ListMachineTypesService::MAX_RESULTS_LIMIT,
+        default_page_size: GoogleCloudPlatform::Compute::ListMachineTypesService::MAX_RESULTS_LIMIT do
+          argument :zone, GraphQL::Types::String, required: true, description: 'Zone to retrieve machine types for.'
+        end
+
+      def self.authorized?(object, context)
+        super(object[:project], context)
+      end
+
+      def regions(after: nil, first: nil)
+        response = GoogleCloudPlatform::Compute::ListRegionsService
+          .new(project: project, current_user: current_user,
+            params: default_params(after, first).merge(google_cloud_project_id: google_cloud_project_id))
+          .execute
+
+        externally_paginated_array(response, after)
+      end
+
+      def zones(region: nil, after: nil, first: nil)
+        params = default_params(after, first)
+        params[:filter] = "name=#{region}-*" if region
+        params[:google_cloud_project_id] = google_cloud_project_id if google_cloud_project_id
+
+        response = GoogleCloudPlatform::Compute::ListZonesService
+          .new(project: project, current_user: current_user, params: params)
+          .execute
+
+        externally_paginated_array(response, after)
+      end
+
+      def machine_types(zone:, after: nil, first: nil)
+        response = GoogleCloudPlatform::Compute::ListMachineTypesService
+          .new(
+            project: project, current_user: current_user, zone: zone,
+            params: default_params(after, first).merge(google_cloud_project_id: google_cloud_project_id)
+          )
+          .execute
+
+        externally_paginated_array(response, after)
+      end
+
+      private
+
+      def project
+        object[:project]
+      end
+
+      def google_cloud_project_id
+        object[:cloud_project_id]
+      end
+
+      def default_params(after, first)
+        { max_results: first, page_token: after }.compact
+      end
+
+      def externally_paginated_array(response, after)
+        raise_resource_not_available_error!(response.message) if response.error?
+
+        Gitlab::Graphql::ExternallyPaginatedArray.new(
+          after,
+          response.payload[:next_page_token],
+          *response.payload[:items]
+        )
+      end
+    end
+  end
+end
diff --git a/ee/app/services/google_cloud_platform/compute/base_service.rb b/ee/app/services/google_cloud_platform/compute/base_service.rb
index aae1545116835..97d9221f785d8 100644
--- a/ee/app/services/google_cloud_platform/compute/base_service.rb
+++ b/ee/app/services/google_cloud_platform/compute/base_service.rb
@@ -78,7 +78,7 @@ def client
       end
 
       def gcp_project_id
-        project_integration.artifact_registry_project_id
+        params[:google_cloud_project_id] || project_integration.artifact_registry_project_id
       end
 
       def gcp_wlif
diff --git a/ee/spec/graphql/types/ci/runner_cloud_provisioning_options_type_spec.rb b/ee/spec/graphql/types/ci/runner_cloud_provisioning_options_type_spec.rb
new file mode 100644
index 0000000000000..16d1d8358d869
--- /dev/null
+++ b/ee/spec/graphql/types/ci/runner_cloud_provisioning_options_type_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CiRunnerCloudProvisioningOptions'], feature_category: :fleet_visibility do
+  it 'returns all possible types' do
+    expect(described_class.possible_types).to include(
+      ::Types::Ci::RunnerGoogleCloudProvisioningOptionsType
+    )
+  end
+
+  describe '#resolve_type' do
+    using RSpec::Parameterized::TableSyntax
+
+    where(:provider, :expected_type) do
+      :google_cloud | ::Types::Ci::RunnerGoogleCloudProvisioningOptionsType
+    end
+
+    subject(:resolved_type) do
+      described_class.resolve_type({ project: nil, provider: provider, cloud_project_id: 'some_project_id' }, {})
+    end
+
+    with_them do
+      specify { expect(resolved_type).to eq(expected_type) }
+    end
+
+    context 'when provider is unknown' do
+      let(:provider) { :unknown }
+
+      it 'raises an error' do
+        expect { resolved_type }.to raise_error(Types::Ci::RunnerCloudProvisioningOptionsType::UnexpectedProviderType)
+      end
+    end
+  end
+end
diff --git a/ee/spec/graphql/types/project_type_spec.rb b/ee/spec/graphql/types/project_type_spec.rb
index 5067a443d8c72..a557eae0f6a68 100644
--- a/ee/spec/graphql/types/project_type_spec.rb
+++ b/ee/spec/graphql/types/project_type_spec.rb
@@ -29,8 +29,8 @@
       security_policy_project security_training_urls vulnerability_images only_allow_merge_if_all_status_checks_passed
       security_policy_project_linked_projects security_policy_project_linked_namespaces
       dependencies merge_requests_disable_committers_approval has_jira_vulnerability_issue_creation_enabled
-      ci_subscriptions_projects ci_subscribed_projects ai_agents duo_features_enabled runner_cloud_provisioning_options
-      google_cloud_artifact_registry_repository
+      ci_subscriptions_projects ci_subscribed_projects ai_agents duo_features_enabled
+      runner_cloud_provisioning_options google_cloud_artifact_registry_repository
     ]
 
     expect(described_class).to include_graphql_fields(*expected_fields)
@@ -497,12 +497,4 @@
 
     it { is_expected.to have_graphql_type(::Types::Ci::RunnerCloudProvisioningOptionsType) }
   end
-
-  private
-
-  def query_for_project(project)
-    graphql_query_for(
-      :projects, { ids: [global_id_of(project)] }, "nodes { #{query_nodes(:compliance_frameworks)} }"
-    )
-  end
 end
diff --git a/ee/spec/lib/google_cloud_platform/compute/client_spec.rb b/ee/spec/lib/google_cloud_platform/compute/client_spec.rb
index e613dfb69d2e6..3bfddda200c98 100644
--- a/ee/spec/lib/google_cloud_platform/compute/client_spec.rb
+++ b/ee/spec/lib/google_cloud_platform/compute/client_spec.rb
@@ -7,7 +7,7 @@
   let_it_be(:rsa_key) { OpenSSL::PKey::RSA.generate(3072) }
   let_it_be(:rsa_key_data) { rsa_key.to_s }
 
-  let(:gcp_project_id) { 'gcp_project_id' }
+  let(:gcp_project_id) { 'cloud_project_id' }
   let(:gcp_wlif) { '//wlif.test' }
 
   let(:user) { project.owner }
diff --git a/ee/spec/requests/api/graphql/project/runner_cloud_provisioning_options_spec.rb b/ee/spec/requests/api/graphql/project/runner_google_cloud_provisioning_options_spec.rb
similarity index 94%
rename from ee/spec/requests/api/graphql/project/runner_cloud_provisioning_options_spec.rb
rename to ee/spec/requests/api/graphql/project/runner_google_cloud_provisioning_options_spec.rb
index 11a0d712e1dab..8fffbe7ac9766 100644
--- a/ee/spec/requests/api/graphql/project/runner_cloud_provisioning_options_spec.rb
+++ b/ee/spec/requests/api/graphql/project/runner_google_cloud_provisioning_options_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe 'runnerCloudProvisioningOptions', feature_category: :fleet_visibility do
+RSpec.describe 'runnerGoogleCloudProvisioningOptions', feature_category: :fleet_visibility do
   include GraphqlHelpers
 
   let_it_be_with_refind(:project) { create(:project) }
@@ -11,11 +11,12 @@
 
   let(:client_klass) { GoogleCloudPlatform::Compute::Client }
   let(:current_user) { maintainer }
+  let(:google_cloud_project_id) { 'project_id_override' }
   let(:expected_compute_client_args) do
     {
       project: project,
       user: current_user,
-      gcp_project_id: integration.artifact_registry_project_id,
+      gcp_project_id: google_cloud_project_id,
       gcp_wlif: integration.wlif
     }
   end
@@ -30,9 +31,14 @@
     graphql_query_for(
       :project, { fullPath: project.full_path },
       query_graphql_field(
-        :runner_cloud_provisioning_options, { provider: :GOOGLE_CLOUD },
-        query_nodes(node_name, args: base_item_query_args.merge(item_query_args), of: item_type,
-          include_pagination_info: true)
+        :runner_cloud_provisioning_options, { provider: :GOOGLE_CLOUD, cloud_project_id: google_cloud_project_id },
+        "... on CiRunnerGoogleCloudProvisioningOptions {
+          #{query_nodes(
+            node_name,
+            args: base_item_query_args.merge(item_query_args),
+            of: item_type,
+            include_pagination_info: true)}
+        }"
       )
     )
   end
diff --git a/ee/spec/services/google_cloud_platform/compute/list_machine_types_service_spec.rb b/ee/spec/services/google_cloud_platform/compute/list_machine_types_service_spec.rb
index aa1099f12e9f3..cdd8f03cea782 100644
--- a/ee/spec/services/google_cloud_platform/compute/list_machine_types_service_spec.rb
+++ b/ee/spec/services/google_cloud_platform/compute/list_machine_types_service_spec.rb
@@ -14,7 +14,10 @@
     let(:order_by) { 'name asc' }
     let(:service) { described_class.new(project: project, current_user: user, zone: zone, params: params) }
     let(:params) do
-      { filter: filter, max_results: max_results, page_token: page_token, order_by: order_by }
+      {
+        google_cloud_project_id: google_cloud_project_id, filter: filter,
+        max_results: max_results, page_token: page_token, order_by: order_by
+      }.compact
     end
 
     subject(:response) { service.execute }
@@ -30,6 +33,8 @@
           .and_return(dummy_list_response)
       end
 
+      it_behaves_like 'overriding the google cloud project id'
+
       it 'returns the machine_types' do
         expect(response).to be_success
         expect(response.payload[:items]).to be_a Enumerable
diff --git a/ee/spec/services/google_cloud_platform/compute/list_regions_service_spec.rb b/ee/spec/services/google_cloud_platform/compute/list_regions_service_spec.rb
index 23b6b520f7e42..ce8347b1e5f2c 100644
--- a/ee/spec/services/google_cloud_platform/compute/list_regions_service_spec.rb
+++ b/ee/spec/services/google_cloud_platform/compute/list_regions_service_spec.rb
@@ -12,7 +12,10 @@
     let(:page_token) { 'token' }
     let(:order_by) { 'name asc' }
     let(:params) do
-      { filter: filter, max_results: max_results, page_token: page_token, order_by: order_by }
+      {
+        google_cloud_project_id: google_cloud_project_id, filter: filter,
+        max_results: max_results, page_token: page_token, order_by: order_by
+      }.compact
     end
 
     subject(:response) { service.execute }
@@ -35,6 +38,8 @@
         expect(response.payload[:next_page_token]).to eq('next_page_token')
       end
 
+      it_behaves_like 'overriding the google cloud project id'
+
       context 'with an invalid order_by' do
         where(:field, :direction) do
           'test' | 'asc'
diff --git a/ee/spec/services/google_cloud_platform/compute/list_zones_service_spec.rb b/ee/spec/services/google_cloud_platform/compute/list_zones_service_spec.rb
index 3f989884adaea..c6c37fec2fc04 100644
--- a/ee/spec/services/google_cloud_platform/compute/list_zones_service_spec.rb
+++ b/ee/spec/services/google_cloud_platform/compute/list_zones_service_spec.rb
@@ -12,7 +12,10 @@
     let(:page_token) { 'token' }
     let(:order_by) { 'name asc' }
     let(:params) do
-      { filter: filter, max_results: max_results, page_token: page_token, order_by: order_by }
+      {
+        google_cloud_project_id: google_cloud_project_id, filter: filter,
+        max_results: max_results, page_token: page_token, order_by: order_by
+      }.compact
     end
 
     subject(:response) { service.execute }
@@ -35,6 +38,8 @@
         expect(response.payload[:next_page_token]).to eq('next_page_token')
       end
 
+      it_behaves_like 'overriding the google cloud project id'
+
       context 'with an invalid order_by' do
         where(:field, :direction) do
           'test' | 'asc'
diff --git a/ee/spec/support/shared_contexts/google_cloud_platform/compute/services_shared_contexts.rb b/ee/spec/support/shared_contexts/google_cloud_platform/compute/services_shared_contexts.rb
index 7eb5aece3a916..f5879130772d1 100644
--- a/ee/spec/support/shared_contexts/google_cloud_platform/compute/services_shared_contexts.rb
+++ b/ee/spec/support/shared_contexts/google_cloud_platform/compute/services_shared_contexts.rb
@@ -6,7 +6,7 @@
     create(
       :google_cloud_platform_artifact_registry_integration,
       project: project,
-      artifact_registry_project_id: 'gcp_project_id',
+      artifact_registry_project_id: 'cloud_project_id',
       workload_identity_pool_project_number: '555',
       workload_identity_pool_id: 'my_pool',
       workload_identity_pool_provider_id: 'my_provider'
@@ -16,13 +16,14 @@
   let(:user) { project.owner }
   let(:service) { described_class.new(project: project, current_user: user, params: params) }
   let(:client_double) { instance_double('::GoogleCloudPlatform::Compute::Client') }
+  let(:google_cloud_project_id) { nil }
 
   before do
     allow(::GoogleCloudPlatform::Compute::Client).to receive(:new)
       .with(
         project: project,
         user: user,
-        gcp_project_id: project_integration.artifact_registry_project_id,
+        gcp_project_id: google_cloud_project_id || project_integration.artifact_registry_project_id,
         gcp_wlif: project_integration.wlif
       ).and_return(client_double)
   end
diff --git a/ee/spec/support/shared_examples/google_cloud_platform/compute/services_shared_examples.rb b/ee/spec/support/shared_examples/google_cloud_platform/compute/services_shared_examples.rb
index 319c6fabd6e34..28fe29b918ffc 100644
--- a/ee/spec/support/shared_examples/google_cloud_platform/compute/services_shared_examples.rb
+++ b/ee/spec/support/shared_examples/google_cloud_platform/compute/services_shared_examples.rb
@@ -67,3 +67,23 @@
     end
   end
 end
+
+RSpec.shared_examples 'overriding the google cloud project id' do
+  let(:google_cloud_project_id) { 'project_id_override' }
+  let(:extra_params) { { google_cloud_project_id: google_cloud_project_id } }
+
+  it 'returns results by calling the specified project id' do
+    expect(::GoogleCloudPlatform::Compute::Client).to receive(:new)
+      .with(
+        project: project,
+        user: user,
+        gcp_project_id: google_cloud_project_id,
+        gcp_wlif: project_integration.wlif
+      ).and_return(client_double)
+
+    expect(response).to be_success
+    expect(response.payload[:items]).to be_a Enumerable
+    expect(response.payload[:items].count).to be 1
+    expect(response.payload[:next_page_token]).to eq('next_page_token')
+  end
+end
-- 
GitLab