Skip to content

Commit fe084f3

Browse files
committed
refactor(auth): rename ADC secret from GOOGLE_APPLICATION_CREDENTIALS to gcloud-adc
The GOOGLE_APPLICATION_CREDENTIALS name was ambiguous — it collides with the standard GCP env var of the same name (which holds a path to a file), making it confusing when used as a secret key whose value is file contents. Rename the special file-type secret to "gcloud-adc". This secret writes ADC contents to ~/.config/gcloud/application_default_credentials.json inside the container, where the GCP SDK auto-discovers it. Scion no longer sets the GOOGLE_APPLICATION_CREDENTIALS env var for vertex-ai auth, since the well-known path suffices. Users who need conventional GOOGLE_APPLICATION_CREDENTIALS usage can set up both an environment-type secret (with the path value) and a file secret (that writes the credential file) independently. Also removes the now-unused GoogleAppCredentialsExplicit field from AuthConfig, since no harness conditionally sets the env var anymore.
1 parent 224bf36 commit fe084f3

14 files changed

Lines changed: 56 additions & 76 deletions

File tree

cmd/common.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ func RunAgent(cmd *cobra.Command, args []string, resume bool) error {
478478
util.Debugf("[auth] hasGeminiAPIKey=%t, hasGoogleAPIKey=%t", localAuth.GeminiAPIKey != "", localAuth.GoogleAPIKey != "")
479479
util.Debugf("[auth] hasAnthropicAPIKey=%t", localAuth.AnthropicAPIKey != "")
480480
util.Debugf("[auth] hasOAuthCreds=%t (%s)", localAuth.OAuthCreds != "", localAuth.OAuthCreds)
481-
util.Debugf("[auth] hasGoogleAppCredentials=%t (explicit=%t)", localAuth.GoogleAppCredentials != "", localAuth.GoogleAppCredentialsExplicit)
481+
util.Debugf("[auth] hasGoogleAppCredentials=%t", localAuth.GoogleAppCredentials != "")
482482
util.Debugf("[auth] cloudProject=%q, cloudRegion=%q", localAuth.GoogleCloudProject, localAuth.GoogleCloudRegion)
483483
}
484484

@@ -678,7 +678,7 @@ func startAgentViaHub(hubCtx *HubContext, agentName, task string, resume bool, i
678678
util.Debugf("[auth] hasGeminiAPIKey=%t, hasGoogleAPIKey=%t", localAuth.GeminiAPIKey != "", localAuth.GoogleAPIKey != "")
679679
util.Debugf("[auth] hasAnthropicAPIKey=%t", localAuth.AnthropicAPIKey != "")
680680
util.Debugf("[auth] hasOAuthCreds=%t (%s)", localAuth.OAuthCreds != "", localAuth.OAuthCreds)
681-
util.Debugf("[auth] hasGoogleAppCredentials=%t (explicit=%t)", localAuth.GoogleAppCredentials != "", localAuth.GoogleAppCredentialsExplicit)
681+
util.Debugf("[auth] hasGoogleAppCredentials=%t", localAuth.GoogleAppCredentials != "")
682682
util.Debugf("[auth] cloudProject=%q, cloudRegion=%q", localAuth.GoogleCloudProject, localAuth.GoogleCloudRegion)
683683
}
684684

docs-site/src/content/docs/advanced-local/agent-credentials.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ scion hub secret set GEMINI_API_KEY "AIza..."
7777
Uses Google Cloud's Vertex AI endpoints with Application Default Credentials (ADC).
7878

7979
**Required Sources:**
80-
- `GOOGLE_APPLICATION_CREDENTIALS`: Path to the ADC JSON file (automatically discovered at `~/.config/gcloud/application_default_credentials.json` if present locally).
80+
- ADC JSON file: Automatically discovered at `~/.config/gcloud/application_default_credentials.json` if present locally. In Hub mode, upload via the `gcloud-adc` file secret.
8181
- `GOOGLE_CLOUD_PROJECT`: Your Google Cloud project ID.
8282
- `GOOGLE_CLOUD_REGION`: The region (e.g., `us-east5`). Required for Claude, optional but recommended for Gemini.
8383

@@ -90,18 +90,22 @@ scion start --harness claude my-agent
9090
```
9191

9292
**Hub Setup:**
93-
For Hub mode, you must upload the ADC file as a file-type secret and set the environment variables via the Web Interface or CLI:
93+
For Hub mode, you must upload the ADC file as the `gcloud-adc` file secret and set the environment variables via the Web Interface or CLI:
9494
```bash
95-
# 1. Upload the credential file
95+
# 1. Upload the ADC credential file (written to ~/.config/gcloud/application_default_credentials.json in container)
9696
scion hub secret set --type file \
9797
--target ~/.config/gcloud/application_default_credentials.json \
98-
GOOGLE_APPLICATION_CREDENTIALS @~/.config/gcloud/application_default_credentials.json
98+
gcloud-adc @~/.config/gcloud/application_default_credentials.json
9999

100100
# 2. Set the environment variables
101101
scion hub secret set GOOGLE_CLOUD_PROJECT "my-project"
102102
scion hub secret set GOOGLE_CLOUD_REGION "us-east5"
103103
```
104104

105+
:::note
106+
The `gcloud-adc` secret writes the ADC file to the well-known GCP path inside the container. The GCP SDK auto-discovers it there, so Scion does **not** set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable. If you need to use `GOOGLE_APPLICATION_CREDENTIALS` for other purposes (e.g., pointing to a non-standard path), set it up as a separate environment-type secret alongside a file secret that writes the credential file.
107+
:::
108+
105109
### Harness specific credential file (`auth-file`)
106110

107111
Some harnesses support their own specific credential files, such as OAuth tokens.

pkg/agent/run.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -954,8 +954,7 @@ func isAuthEnvKey(key string) bool {
954954
"ANTHROPIC_VERTEX_PROJECT_ID",
955955
"GOOGLE_CLOUD_REGION",
956956
"CLOUD_ML_REGION",
957-
"GOOGLE_CLOUD_LOCATION",
958-
"GOOGLE_APPLICATION_CREDENTIALS":
957+
"GOOGLE_CLOUD_LOCATION":
959958
return true
960959
default:
961960
return false
@@ -964,7 +963,7 @@ func isAuthEnvKey(key string) bool {
964963

965964
func authFileKind(name, target string) string {
966965
switch {
967-
case name == "GOOGLE_APPLICATION_CREDENTIALS" || strings.HasSuffix(target, "/application_default_credentials.json"):
966+
case name == "gcloud-adc" || strings.HasSuffix(target, "/application_default_credentials.json"):
968967
return "adc"
969968
case name == "GEMINI_OAUTH_CREDS" || strings.HasSuffix(target, "/oauth_creds.json"):
970969
return "gemini-oauth"

pkg/agent/run_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,7 +1755,7 @@ func TestBuildAuthEnvOverlay_EmptyValueOverriddenBySecret(t *testing.T) {
17551755
func TestFilterResolvedSecretsForResolvedAuth(t *testing.T) {
17561756
secrets := []api.ResolvedSecret{
17571757
{Name: "GEMINI_API_KEY", Type: "environment", Target: "GEMINI_API_KEY", Value: "gemini"},
1758-
{Name: "GOOGLE_APPLICATION_CREDENTIALS", Type: "file", Target: "/home/scion/.config/gcloud/application_default_credentials.json", Value: "adc"},
1758+
{Name: "gcloud-adc", Type: "file", Target: "/home/scion/.config/gcloud/application_default_credentials.json", Value: "adc"},
17591759
{Name: "NOT_AUTH_SECRET", Type: "environment", Target: "NOT_AUTH_SECRET", Value: "keep"},
17601760
}
17611761
resolved := &api.ResolvedAuth{
@@ -1780,8 +1780,8 @@ func TestFilterResolvedSecretsForResolvedAuth(t *testing.T) {
17801780
if _, ok := got["NOT_AUTH_SECRET"]; !ok {
17811781
t.Error("expected NOT_AUTH_SECRET to be kept")
17821782
}
1783-
if _, ok := got["GOOGLE_APPLICATION_CREDENTIALS"]; ok {
1784-
t.Error("expected GOOGLE_APPLICATION_CREDENTIALS to be dropped for api-key auth")
1783+
if _, ok := got["gcloud-adc"]; ok {
1784+
t.Error("expected gcloud-adc to be dropped for api-key auth")
17851785
}
17861786
}
17871787

pkg/api/types.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -358,13 +358,12 @@ func (c *ScionConfig) IsDetached() bool {
358358

359359
type AuthConfig struct {
360360
// Google/Gemini auth
361-
GeminiAPIKey string
362-
GoogleAPIKey string
363-
GoogleAppCredentials string
364-
GoogleAppCredentialsExplicit bool // true when value came from GOOGLE_APPLICATION_CREDENTIALS env var
365-
GoogleCloudProject string
366-
GoogleCloudRegion string
367-
OAuthCreds string
361+
GeminiAPIKey string
362+
GoogleAPIKey string
363+
GoogleAppCredentials string
364+
GoogleCloudProject string
365+
GoogleCloudRegion string
366+
OAuthCreds string
368367

369368
// Anthropic auth
370369
AnthropicAPIKey string

pkg/harness/auth.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,6 @@ func GatherAuthWithEnv(env map[string]string, localSources bool) api.AuthConfig
7272
GoogleAppCredentials: lookup("GOOGLE_APPLICATION_CREDENTIALS"),
7373
}
7474

75-
// Mark whether GOOGLE_APPLICATION_CREDENTIALS was explicitly set via env var
76-
auth.GoogleAppCredentialsExplicit = auth.GoogleAppCredentials != ""
77-
7875
// File-sourced fields: check well-known paths (skip in broker mode)
7976
if localSources {
8077
home, _ := os.UserHomeDir()
@@ -121,10 +118,9 @@ func OverlayFileSecrets(auth *api.AuthConfig, secrets []api.ResolvedSecret) {
121118
name := s.Name
122119

123120
switch {
124-
case name == "GOOGLE_APPLICATION_CREDENTIALS" ||
121+
case name == "gcloud-adc" ||
125122
strings.HasSuffix(target, "/application_default_credentials.json"):
126123
auth.GoogleAppCredentials = target
127-
auth.GoogleAppCredentialsExplicit = false // container GCP SDK auto-discovers well-known path
128124
case name == "GEMINI_OAUTH_CREDS" ||
129125
strings.HasSuffix(target, "/oauth_creds.json"):
130126
auth.OAuthCreds = target
@@ -215,7 +211,7 @@ func RequiredAuthSecrets(harnessName, authSelectedType string) []api.RequiredSec
215211
if effectiveType == "vertex-ai" {
216212
return []api.RequiredSecret{
217213
{
218-
Key: "GOOGLE_APPLICATION_CREDENTIALS",
214+
Key: "gcloud-adc",
219215
Type: "file",
220216
Description: "Google Cloud Application Default Credentials (ADC) file for vertex-ai authentication",
221217
},
@@ -243,12 +239,12 @@ func DetectAuthTypeFromFileSecrets(harnessName string, fileSecretNames map[strin
243239
if _, ok := fileSecretNames["GEMINI_OAUTH_CREDS"]; ok {
244240
return "auth-file"
245241
}
246-
if _, ok := fileSecretNames["GOOGLE_APPLICATION_CREDENTIALS"]; ok {
242+
if _, ok := fileSecretNames["gcloud-adc"]; ok {
247243
return "vertex-ai"
248244
}
249245
case "claude":
250246
// Auto-detect priority: api-key → ADC (vertex-ai)
251-
if _, ok := fileSecretNames["GOOGLE_APPLICATION_CREDENTIALS"]; ok {
247+
if _, ok := fileSecretNames["gcloud-adc"]; ok {
252248
return "vertex-ai"
253249
}
254250
case "codex":

pkg/harness/auth_test.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -438,10 +438,10 @@ func TestRequiredAuthSecrets(t *testing.T) {
438438
wantKey string
439439
wantType string
440440
}{
441-
{"claude vertex-ai", "claude", "vertex-ai", false, "GOOGLE_APPLICATION_CREDENTIALS", "file"},
442-
{"gemini vertex-ai", "gemini", "vertex-ai", false, "GOOGLE_APPLICATION_CREDENTIALS", "file"},
443-
{"opencode vertex-ai", "opencode", "vertex-ai", false, "GOOGLE_APPLICATION_CREDENTIALS", "file"},
444-
{"codex vertex-ai", "codex", "vertex-ai", false, "GOOGLE_APPLICATION_CREDENTIALS", "file"},
441+
{"claude vertex-ai", "claude", "vertex-ai", false, "gcloud-adc", "file"},
442+
{"gemini vertex-ai", "gemini", "vertex-ai", false, "gcloud-adc", "file"},
443+
{"opencode vertex-ai", "opencode", "vertex-ai", false, "gcloud-adc", "file"},
444+
{"codex vertex-ai", "codex", "vertex-ai", false, "gcloud-adc", "file"},
445445
{"claude api-key", "claude", "api-key", true, "", ""},
446446
{"gemini api-key", "gemini", "api-key", true, "", ""},
447447
{"claude empty auth type", "claude", "", true, "", ""},
@@ -491,15 +491,15 @@ func TestDetectAuthTypeFromFileSecrets(t *testing.T) {
491491
"auth-file",
492492
},
493493
{
494-
"gemini with GOOGLE_APPLICATION_CREDENTIALS",
494+
"gemini with gcloud-adc",
495495
"gemini",
496-
map[string]struct{}{"GOOGLE_APPLICATION_CREDENTIALS": {}},
496+
map[string]struct{}{"gcloud-adc": {}},
497497
"vertex-ai",
498498
},
499499
{
500500
"gemini with both OAuth and ADC prefers OAuth",
501501
"gemini",
502-
map[string]struct{}{"GEMINI_OAUTH_CREDS": {}, "GOOGLE_APPLICATION_CREDENTIALS": {}},
502+
map[string]struct{}{"GEMINI_OAUTH_CREDS": {}, "gcloud-adc": {}},
503503
"auth-file",
504504
},
505505
{
@@ -521,9 +521,9 @@ func TestDetectAuthTypeFromFileSecrets(t *testing.T) {
521521
"auth-file",
522522
},
523523
{
524-
"claude with GOOGLE_APPLICATION_CREDENTIALS",
524+
"claude with gcloud-adc",
525525
"claude",
526-
map[string]struct{}{"GOOGLE_APPLICATION_CREDENTIALS": {}},
526+
map[string]struct{}{"gcloud-adc": {}},
527527
"vertex-ai",
528528
},
529529
{
@@ -747,15 +747,12 @@ func TestOverlayFileSecrets(t *testing.T) {
747747
{
748748
name: "ADC by name",
749749
secrets: []api.ResolvedSecret{
750-
{Name: "GOOGLE_APPLICATION_CREDENTIALS", Type: "file", Target: "/home/gemini/.config/gcloud/application_default_credentials.json"},
750+
{Name: "gcloud-adc", Type: "file", Target: "/home/gemini/.config/gcloud/application_default_credentials.json"},
751751
},
752752
check: func(t *testing.T, auth api.AuthConfig) {
753753
if auth.GoogleAppCredentials != "/home/gemini/.config/gcloud/application_default_credentials.json" {
754754
t.Errorf("GoogleAppCredentials = %q, want ADC path", auth.GoogleAppCredentials)
755755
}
756-
if auth.GoogleAppCredentialsExplicit {
757-
t.Errorf("GoogleAppCredentialsExplicit should be false for ADC overlay")
758-
}
759756
},
760757
},
761758
{
@@ -805,7 +802,7 @@ func TestOverlayFileSecrets(t *testing.T) {
805802
{
806803
name: "non-file secrets are skipped",
807804
secrets: []api.ResolvedSecret{
808-
{Name: "GOOGLE_APPLICATION_CREDENTIALS", Type: "environment", Target: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/some/path"},
805+
{Name: "gcloud-adc", Type: "environment", Target: "gcloud-adc", Value: "/some/path"},
809806
},
810807
check: func(t *testing.T, auth api.AuthConfig) {
811808
if auth.GoogleAppCredentials != "" {

pkg/harness/claude_code.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ func (c *ClaudeCode) ResolveAuth(auth api.AuthConfig) (*api.ResolvedAuth, error)
362362
return c.resolveVertexAI(auth), nil
363363
}
364364

365-
return nil, fmt.Errorf("claude: no valid auth method found; set ANTHROPIC_API_KEY for direct API access, or provide GOOGLE_APPLICATION_CREDENTIALS + GOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_REGION for Vertex AI")
365+
return nil, fmt.Errorf("claude: no valid auth method found; set ANTHROPIC_API_KEY for direct API access, or provide ADC (gcloud-adc secret or ~/.config/gcloud/application_default_credentials.json) + GOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_REGION for Vertex AI")
366366
}
367367

368368
func (c *ClaudeCode) resolveVertexAI(auth api.AuthConfig) *api.ResolvedAuth {
@@ -376,9 +376,6 @@ func (c *ClaudeCode) resolveVertexAI(auth api.AuthConfig) *api.ResolvedAuth {
376376
},
377377
}
378378
if auth.GoogleAppCredentials != "" {
379-
if auth.GoogleAppCredentialsExplicit {
380-
result.EnvVars["GOOGLE_APPLICATION_CREDENTIALS"] = adcContainerPath
381-
}
382379
result.Files = append(result.Files, api.FileMapping{
383380
SourcePath: auth.GoogleAppCredentials,
384381
ContainerPath: adcContainerPath,

pkg/harness/gemini_cli.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,6 @@ func (g *GeminiCLI) resolveExplicit(auth api.AuthConfig) (*api.ResolvedAuth, err
378378
}
379379
if auth.GoogleAppCredentials != "" {
380380
adcContainerPath := "~/.config/gcloud/application_default_credentials.json"
381-
if auth.GoogleAppCredentialsExplicit {
382-
result.EnvVars["GOOGLE_APPLICATION_CREDENTIALS"] = adcContainerPath
383-
}
384381
result.Files = append(result.Files, api.FileMapping{
385382
SourcePath: auth.GoogleAppCredentials,
386383
ContainerPath: adcContainerPath,
@@ -449,9 +446,6 @@ func (g *GeminiCLI) resolveAutoDetect(auth api.AuthConfig) (*api.ResolvedAuth, e
449446
},
450447
},
451448
}
452-
if auth.GoogleAppCredentialsExplicit {
453-
result.EnvVars["GOOGLE_APPLICATION_CREDENTIALS"] = adcContainerPath
454-
}
455449
if auth.GoogleCloudRegion != "" {
456450
result.EnvVars["GOOGLE_CLOUD_REGION"] = auth.GoogleCloudRegion
457451
result.EnvVars["GOOGLE_CLOUD_LOCATION"] = auth.GoogleCloudRegion

pkg/harness/gemini_cli_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,10 @@ func TestGeminiResolveAuth_ExplicitAuthFileMissing(t *testing.T) {
205205
func TestGeminiResolveAuth_ExplicitVertexAI(t *testing.T) {
206206
g := &GeminiCLI{}
207207
auth := api.AuthConfig{
208-
SelectedType: "vertex-ai",
209-
GoogleCloudProject: "proj",
210-
GoogleCloudRegion: "us-east1",
211-
GoogleAppCredentials: "/path/to/adc.json",
212-
GoogleAppCredentialsExplicit: true,
208+
SelectedType: "vertex-ai",
209+
GoogleCloudProject: "proj",
210+
GoogleCloudRegion: "us-east1",
211+
GoogleAppCredentials: "/path/to/adc.json",
213212
}
214213
result, err := g.ResolveAuth(auth)
215214
if err != nil {

0 commit comments

Comments
 (0)