Skip to content

Commit 53c16c9

Browse files
authored
Merge pull request #1815 from transformerlab/add/gcs-sa-key-setup
add: prompt for GCP service account key path during setup
2 parents f1662a2 + a2d6098 commit 53c16c9

5 files changed

Lines changed: 53 additions & 14 deletions

File tree

api/transformerlab/services/compute_provider/launch_credentials.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,19 @@ def escape_bash(s: str) -> str:
6666
return setup_script
6767

6868

69-
def generate_gcp_credentials_setup(service_account_json: str, credentials_path: Optional[str] = None) -> str:
70-
target_path = credentials_path or "~/.config/gcloud/application_default_credentials.json"
71-
encoded = base64.b64encode(service_account_json.encode()).decode()
69+
def generate_gcp_credentials_setup(sa_json_path: str) -> str:
70+
"""Read service account JSON from *sa_json_path* and emit a setup script that writes
71+
it to the standard ADC location so GCP client libraries pick it up automatically."""
72+
sa_json_path = os.path.expanduser(sa_json_path)
73+
with open(sa_json_path, "r", encoding="utf-8") as f:
74+
encoded = base64.b64encode(f.read().encode()).decode()
75+
adc_path = "~/.config/gcloud/application_default_credentials.json"
7276
setup_script = (
7377
"echo 'Setting up GCP service account credentials...'; "
74-
f"mkdir -p $(dirname {target_path}); "
75-
f"echo '{encoded}' | base64 -d > {target_path}; "
76-
f"chmod 600 {target_path}; "
77-
f"export GOOGLE_APPLICATION_CREDENTIALS={target_path}; "
78+
"mkdir -p ~/.config/gcloud; "
79+
f"echo '{encoded}' | base64 -d > {adc_path}; "
80+
f"chmod 600 {adc_path}; "
81+
f"export GOOGLE_APPLICATION_CREDENTIALS={adc_path}; "
7882
"echo 'GCP credentials configured successfully'"
7983
)
8084
return setup_script

api/transformerlab/services/compute_provider/launch_sweep.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ async def launch_sweep_jobs(
254254
if aws_credentials_dir:
255255
env_vars["AWS_SHARED_CREDENTIALS_FILE"] = f"{aws_credentials_dir}/credentials"
256256
elif STORAGE_PROVIDER == "gcp":
257-
gcp_sa_json = os.getenv("TFL_GCP_SERVICE_ACCOUNT_JSON")
258-
if gcp_sa_json:
259-
gcp_setup = generate_gcp_credentials_setup(gcp_sa_json)
257+
gcp_sa_json_path = os.getenv("TFL_GCP_SERVICE_ACCOUNT_JSON_PATH")
258+
if gcp_sa_json_path:
259+
gcp_setup = generate_gcp_credentials_setup(gcp_sa_json_path)
260260
setup_commands.append(gcp_setup)
261261
elif STORAGE_PROVIDER == "azure":
262262
azure_connection_string = os.getenv("AZURE_STORAGE_CONNECTION_STRING")

api/transformerlab/services/compute_provider/launch_template.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,9 @@ async def launch_template_on_provider(
231231
if aws_credentials_dir:
232232
env_vars["AWS_SHARED_CREDENTIALS_FILE"] = f"{aws_credentials_dir}/credentials"
233233
elif STORAGE_PROVIDER == "gcp":
234-
gcp_sa_json = os.getenv("TFL_GCP_SERVICE_ACCOUNT_JSON")
235-
if gcp_sa_json:
236-
gcp_setup = generate_gcp_credentials_setup(gcp_sa_json)
234+
gcp_sa_json_path = os.getenv("TFL_GCP_SERVICE_ACCOUNT_JSON_PATH")
235+
if gcp_sa_json_path:
236+
gcp_setup = generate_gcp_credentials_setup(gcp_sa_json_path)
237237
setup_commands.append(gcp_setup)
238238
elif STORAGE_PROVIDER == "azure":
239239
azure_connection_string = os.getenv("AZURE_STORAGE_CONNECTION_STRING")

cli/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "transformerlab-cli"
7-
version = "0.0.19"
7+
version = "0.0.20"
88
description = "Transformer Lab CLI"
99
requires-python = ">=3.10"
1010
authors = [{ name = "Transformer Lab", email = "hello@transformerlab.ai" }]

cli/src/transformerlab_cli/commands/server.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import os
23
import secrets
34
import shutil
@@ -173,6 +174,40 @@ def _prompt_storage(existing: dict[str, str]) -> dict[str, str]:
173174
if project.strip():
174175
env["GCP_PROJECT"] = project.strip()
175176
env["REMOTE_WORKSPACE_HOST"] = "gcp"
177+
178+
default_sa_path = existing.get("TFL_GCP_SERVICE_ACCOUNT_JSON_PATH", "")
179+
sa_path = typer.prompt(
180+
"Path to service account JSON key file (for remote job launches, press Enter to skip)",
181+
default=default_sa_path,
182+
show_default=False,
183+
).strip()
184+
if sa_path:
185+
sa_path = os.path.expanduser(sa_path)
186+
if not os.path.isfile(sa_path):
187+
console.print(
188+
f"[error]File not found: {sa_path} — skipping service account key setup.[/error]"
189+
"\n[bold error]WARNING: Remote Job (using GCP for storage) launches will fail without a valid service account key.[/bold error]"
190+
)
191+
else:
192+
try:
193+
with open(sa_path, "r", encoding="utf-8") as _f:
194+
json.load(_f)
195+
env["TFL_GCP_SERVICE_ACCOUNT_JSON_PATH"] = sa_path
196+
except json.JSONDecodeError:
197+
console.print(
198+
"[error]File is not valid JSON — skipping service account key setup.[/error]"
199+
"\n[bold error]WARNING: Remote Job (using GCP for storage) launches will fail without a valid service account key.[/bold error]"
200+
)
201+
except OSError as e:
202+
console.print(
203+
f"[error]Could not read file: {e} — skipping service account key setup.[/error]"
204+
"\n[bold error]WARNING: Remote Job (using GCP for storage) launches will fail without a valid service account key.[/bold error]"
205+
)
206+
else:
207+
console.print(
208+
"[bold error]WARNING: No service account key provided. Remote Job (using GCP for storage) launches will fail.[/bold error]"
209+
"\n[dim]You can re-run 'lab server init' to configure this later.[/dim]"
210+
)
176211
elif provider == "azure":
177212
console.print("\n[info]Azure Blob Storage authentication:[/info]")
178213
use_conn_string = typer.confirm("Use a connection string?", default=True)

0 commit comments

Comments
 (0)