From f9990702622efd2f04a5c529ee24d0e100ddbe63 Mon Sep 17 00:00:00 2001 From: Loki Chen Date: Mon, 20 Jul 2026 07:49:37 -0700 Subject: [PATCH] Request cloud-platform scope in ControlPlaneClient credentials google.auth.default() was called without scopes. For external_account (Workload Identity Federation) credentials this yields an unscoped credential, which produces a malformed STS token exchange / service-account impersonation and causes the Hypercompute Cluster control plane to reject every request with HTTP 400 INVALID_ARGUMENT. This breaks MLRun create/get for GKE workloads authenticating via WIF. Pass scopes=['https://www.googleapis.com/auth/cloud-platform'] explicitly so token minting is well-formed for both user ADC and external_account creds. Fixes #4 --- .../clients/control_plane_client.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/google_cloud_mldiagnostics/clients/control_plane_client.py b/src/google_cloud_mldiagnostics/clients/control_plane_client.py index 0b860a4..9bc7d65 100644 --- a/src/google_cloud_mldiagnostics/clients/control_plane_client.py +++ b/src/google_cloud_mldiagnostics/clients/control_plane_client.py @@ -88,8 +88,20 @@ def __init__( self.base_url = base_url self.ml_runs_path = f"{base_url}/projects/{project_id}/locations/{location}/machineLearningRuns" - # Initialize Google Cloud credentials - self.credentials, _ = google.auth.default() + # Initialize Google Cloud credentials. + # + # Request the cloud-platform scope explicitly. Some credential types do not + # carry an implicit scope -- notably external_account (Workload Identity + # Federation) credentials, e.g. a GKE workload authenticating as a service + # account via WIF. With such a credential, google.auth.default() with no + # scopes yields an unscoped credential, and the subsequent STS token + # exchange / service-account impersonation is malformed, so the control + # plane rejects every request with HTTP 400 INVALID_ARGUMENT. Passing the + # scope explicitly makes token minting well-formed for both user ADC and + # external_account credentials. + self.credentials, _ = google.auth.default( + scopes=["https://www.googleapis.com/auth/cloud-platform"] + ) def _get_access_token(self) -> str: """Get Google Cloud access token for authentication."""