From a69b200fb3a26680cc99b562a4be7a856a56daf0 Mon Sep 17 00:00:00 2001 From: Shadow0614 <64795827+CoreyKatzburg@users.noreply.github.com> Date: Wed, 11 Nov 2026 12:05:21 -0500 Subject: [PATCH 1/3] feat(antigravity): add a credentials file path setting for Agent Platform Agent Platform without an API key signs in with Application Default Credentials, but there was no way to choose the credentials file: T3 strips GOOGLE_APPLICATION_CREDENTIALS from the environment, including a value set on the instance. Add a Credentials file setting and pass it to the runtime as GOOGLE_APPLICATION_CREDENTIALS. An API key still wins, since it already names a project. Co-Authored-By: Claude Opus 5.5 --- .../src/provider/Drivers/AntigravityDriver.ts | 1 + .../provider/antigravityAuthSupport.test.ts | 18 ++++++++++++++++++ .../src/provider/antigravityAuthSupport.ts | 6 +++++- docs/user/providers-antigravity.md | 14 ++++++++------ packages/contracts/src/settings.ts | 11 ++++++++++- 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.ts b/apps/server/src/provider/Drivers/AntigravityDriver.ts index 7bb1f25b67ce7..5e6d444e9f2f6 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.ts @@ -146,6 +146,7 @@ export const AntigravityDriver: ProviderDriver< apiKey: settingsSecretLiteral(settings.apiKey), gcpProject: settings.gcpProject, gcpLocation: settings.gcpLocation, + credentialsFile: settings.credentialsFile, }; const authConfigIssue = antigravityAuthConfigIssue(auth); const processEnvironment = yield* mergeProviderInstanceEnvironment(environment); diff --git a/apps/server/src/provider/antigravityAuthSupport.test.ts b/apps/server/src/provider/antigravityAuthSupport.test.ts index 0220f9fd153c7..38924d1a1be53 100644 --- a/apps/server/src/provider/antigravityAuthSupport.test.ts +++ b/apps/server/src/provider/antigravityAuthSupport.test.ts @@ -139,28 +139,45 @@ describe("Antigravity process environment", () => { apiKey: "gemini-secret", gcpProject: "proj", gcpLocation: "us-central1", + credentialsFile: "/ignored.json", }); expect(geminiKey.GEMINI_API_KEY).toBe("gemini-secret"); expect(geminiKey.GOOGLE_API_KEY).toBeUndefined(); expect(geminiKey.GOOGLE_CLOUD_PROJECT).toBeUndefined(); + expect(geminiKey.GOOGLE_APPLICATION_CREDENTIALS).toBeUndefined(); + // An API key belongs to one project, so it wins over a credentials file. const vertexKey = spawnFor({ authMethod: "agent-platform", apiKey: "vertex-secret", gcpProject: "", gcpLocation: "", + credentialsFile: "/ignored.json", }); expect(vertexKey.GOOGLE_API_KEY).toBe("vertex-secret"); expect(vertexKey.GEMINI_API_KEY).toBeUndefined(); + expect(vertexKey.GOOGLE_APPLICATION_CREDENTIALS).toBeUndefined(); + + const vertexAdc = spawnFor({ + authMethod: "agent-platform", + apiKey: "", + gcpProject: "proj", + gcpLocation: "global", + credentialsFile: "/keys/service-account.json", + }); + expect(vertexAdc.GOOGLE_APPLICATION_CREDENTIALS).toBe("/keys/service-account.json"); + expect(vertexAdc.GOOGLE_API_KEY).toBeUndefined(); const business = spawnFor({ authMethod: "oauth-business", apiKey: "ignored", gcpProject: "proj", gcpLocation: "us-central1", + credentialsFile: "/ignored.json", }); expect(business.GEMINI_API_KEY).toBeUndefined(); expect(business.GOOGLE_API_KEY).toBeUndefined(); + expect(business.GOOGLE_APPLICATION_CREDENTIALS).toBeUndefined(); }); it("isolates TEMP and TMP to the profile directory on Windows", () => { @@ -661,6 +678,7 @@ it.layer(NodeServices.layer)("Antigravity profile preparation", (it) => { apiKey: "vertex-secret", gcpProject: "proj", gcpLocation: "us-central1", + credentialsFile: "", }, }); const settingsPath = path.join(profile.acpDirectory, "settings.json"); diff --git a/apps/server/src/provider/antigravityAuthSupport.ts b/apps/server/src/provider/antigravityAuthSupport.ts index 6a926b12f7c90..e9d546df480e3 100644 --- a/apps/server/src/provider/antigravityAuthSupport.ts +++ b/apps/server/src/provider/antigravityAuthSupport.ts @@ -95,6 +95,7 @@ export interface AntigravityAuthConfig { readonly apiKey: string; readonly gcpProject: string; readonly gcpLocation: string; + readonly credentialsFile: string; } const ANTIGRAVITY_PERSONAL_AUTH: AntigravityAuthConfig = { @@ -102,6 +103,7 @@ const ANTIGRAVITY_PERSONAL_AUTH: AntigravityAuthConfig = { apiKey: "", gcpProject: "", gcpLocation: "", + credentialsFile: "", }; export function antigravityAuthUsesBrowser(authMethod: AntigravityAuthMethod): boolean { @@ -210,7 +212,9 @@ function antigravityEnvironment( ? { GEMINI_API_KEY: auth.apiKey } : auth.authMethod === "agent-platform" && auth.apiKey ? { GOOGLE_API_KEY: auth.apiKey } - : {}; + : auth.authMethod === "agent-platform" && auth.credentialsFile + ? { GOOGLE_APPLICATION_CREDENTIALS: auth.credentialsFile } + : {}; // Each launch unpacks about 1 GB; use T3-owned temp so the driver can reclaim files after force-kill. const tempDirectory = runtimeTempDirectory ?? profile.tempDirectory; return { diff --git a/docs/user/providers-antigravity.md b/docs/user/providers-antigravity.md index c3177c29a12c1..786d0f7dd2512 100644 --- a/docs/user/providers-antigravity.md +++ b/docs/user/providers-antigravity.md @@ -36,16 +36,18 @@ T3 Code's confirmation. Choose **Sign-in method** in the Antigravity provider settings: -| Method | Credentials | -| -------------------------- | -------------------------------------------------------------------------------------------- | -| Google account | Personal Google sign-in in the browser | -| Gemini Enterprise | Browser sign-in, GCP project, and GCP location | -| Gemini API key | API key; choose Connect without a browser | -| Agent Platform / Vertex AI | API key, or GCP project and location with Application Default Credentials on the environment | +| Method | Credentials | +| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| Google account | Personal Google sign-in in the browser | +| Gemini Enterprise | Browser sign-in, GCP project, and GCP location | +| Gemini API key | API key; choose Connect without a browser | +| Agent Platform / Vertex AI | API key; with no API key, GCP project and location with Application Default Credentials from **Credentials file** or the environment's default | The environment stores the Antigravity API key outside its settings file, and clients only see whether one is saved. The agent uses the method and credentials selected for this instance; ambient `GEMINI_API_KEY` and Google credential variables do not override them. +That includes `GOOGLE_APPLICATION_CREDENTIALS` in the instance's **Environment variables**; set the +path in **Credentials file** instead. Changing the method stops the instance's sessions. Sign out before replacing an account. diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts index 346213992e4b2..99e668c7eef1f 100644 --- a/packages/contracts/src/settings.ts +++ b/packages/contracts/src/settings.ts @@ -893,6 +893,15 @@ export const AntigravitySettings = makeProviderSettingsSchema( providerSettingsForm: { placeholder: "us-central1", clearWhenEmpty: "omit" }, }), ), + credentialsFile: TrimmedString.pipe( + Schema.withDecodingDefault(Effect.succeed("")), + Schema.annotateKey({ + title: "Credentials file", + description: + "Application Default Credentials or service account JSON. Agent Platform uses it when no API key is set, in place of GOOGLE_APPLICATION_CREDENTIALS.", + providerSettingsForm: { placeholder: "Default ADC", clearWhenEmpty: "omit" }, + }), + ), binaryPath: TrimmedString.pipe( Schema.withDecodingDefault(Effect.succeed("")), Schema.annotateKey({ @@ -906,7 +915,7 @@ export const AntigravitySettings = makeProviderSettingsSchema( Schema.annotateKey({ providerSettingsForm: { hidden: true } }), ), }, - { order: ["authMethod", "apiKey", "gcpProject", "gcpLocation", "binaryPath"] }, + { order: ["authMethod", "apiKey", "credentialsFile", "gcpProject", "gcpLocation", "binaryPath"] }, ); export type AntigravitySettings = typeof AntigravitySettings.Type; From 28fb17e69a9c339456af49f055129c27746ddd7b Mon Sep 17 00:00:00 2001 From: Shadow0614 <64795827+CoreyKatzburg@users.noreply.github.com> Date: Thu, 12 Nov 2026 00:08:26 -0500 Subject: [PATCH 2/3] fix(antigravity): allow GOOGLE_APPLICATION_CREDENTIALS fallback from environment when credentialsFile is blank --- .../src/provider/antigravityAuthSupport.test.ts | 17 +++++++++++++++++ .../src/provider/antigravityAuthSupport.ts | 7 +++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/server/src/provider/antigravityAuthSupport.test.ts b/apps/server/src/provider/antigravityAuthSupport.test.ts index 38924d1a1be53..e52fbe8d3e821 100644 --- a/apps/server/src/provider/antigravityAuthSupport.test.ts +++ b/apps/server/src/provider/antigravityAuthSupport.test.ts @@ -168,6 +168,23 @@ describe("Antigravity process environment", () => { expect(vertexAdc.GOOGLE_APPLICATION_CREDENTIALS).toBe("/keys/service-account.json"); expect(vertexAdc.GOOGLE_API_KEY).toBeUndefined(); + // When credentialsFile is blank, GOOGLE_APPLICATION_CREDENTIALS from the environment is preserved. + const vertexEnvAdc = + buildAntigravityAcpSpawnInput({ + installation: { executablePath: "/release/acp", harnessPath: "/release/harness" }, + profile, + cwd: "/project", + baseEnv: { PATH: "/usr/bin", GOOGLE_APPLICATION_CREDENTIALS: "/env/adc.json" }, + auth: { + authMethod: "agent-platform", + apiKey: "", + gcpProject: "proj", + gcpLocation: "global", + credentialsFile: "", + }, + }).env ?? {}; + expect(vertexEnvAdc.GOOGLE_APPLICATION_CREDENTIALS).toBe("/env/adc.json"); + const business = spawnFor({ authMethod: "oauth-business", apiKey: "ignored", diff --git a/apps/server/src/provider/antigravityAuthSupport.ts b/apps/server/src/provider/antigravityAuthSupport.ts index e9d546df480e3..99ccd525b0c1f 100644 --- a/apps/server/src/provider/antigravityAuthSupport.ts +++ b/apps/server/src/provider/antigravityAuthSupport.ts @@ -207,13 +207,16 @@ function antigravityEnvironment( if (!removedEnvironmentKeys.has(key.toUpperCase())) environment[key] = value; } // Put the GCP pair in settings.json because GOOGLE_API_KEY takes precedence in the environment. + const credentialsFile = + auth.credentialsFile || + (auth.authMethod === "agent-platform" ? baseEnv.GOOGLE_APPLICATION_CREDENTIALS : undefined); const credential = auth.authMethod === "gemini-api-key" && auth.apiKey ? { GEMINI_API_KEY: auth.apiKey } : auth.authMethod === "agent-platform" && auth.apiKey ? { GOOGLE_API_KEY: auth.apiKey } - : auth.authMethod === "agent-platform" && auth.credentialsFile - ? { GOOGLE_APPLICATION_CREDENTIALS: auth.credentialsFile } + : auth.authMethod === "agent-platform" && credentialsFile + ? { GOOGLE_APPLICATION_CREDENTIALS: credentialsFile } : {}; // Each launch unpacks about 1 GB; use T3-owned temp so the driver can reclaim files after force-kill. const tempDirectory = runtimeTempDirectory ?? profile.tempDirectory; From ddd87ba94b2048e0d4b589f0c2d435630db3b586 Mon Sep 17 00:00:00 2001 From: Shadow0614 <64795827+CoreyKatzburg@users.noreply.github.com> Date: Thu, 12 Nov 2026 17:44:45 -0500 Subject: [PATCH 3/3] fix(antigravity): require explicit credentialsFile and disclose ignored environment credentials --- apps/server/src/provider/antigravityAuthSupport.test.ts | 6 +++--- apps/server/src/provider/antigravityAuthSupport.ts | 7 ++----- packages/contracts/src/settings.ts | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/server/src/provider/antigravityAuthSupport.test.ts b/apps/server/src/provider/antigravityAuthSupport.test.ts index e52fbe8d3e821..4d2dd058b7fd5 100644 --- a/apps/server/src/provider/antigravityAuthSupport.test.ts +++ b/apps/server/src/provider/antigravityAuthSupport.test.ts @@ -168,8 +168,8 @@ describe("Antigravity process environment", () => { expect(vertexAdc.GOOGLE_APPLICATION_CREDENTIALS).toBe("/keys/service-account.json"); expect(vertexAdc.GOOGLE_API_KEY).toBeUndefined(); - // When credentialsFile is blank, GOOGLE_APPLICATION_CREDENTIALS from the environment is preserved. - const vertexEnvAdc = + // When credentialsFile is blank, ambient GOOGLE_APPLICATION_CREDENTIALS is ignored. + const vertexBlankAdc = buildAntigravityAcpSpawnInput({ installation: { executablePath: "/release/acp", harnessPath: "/release/harness" }, profile, @@ -183,7 +183,7 @@ describe("Antigravity process environment", () => { credentialsFile: "", }, }).env ?? {}; - expect(vertexEnvAdc.GOOGLE_APPLICATION_CREDENTIALS).toBe("/env/adc.json"); + expect(vertexBlankAdc.GOOGLE_APPLICATION_CREDENTIALS).toBeUndefined(); const business = spawnFor({ authMethod: "oauth-business", diff --git a/apps/server/src/provider/antigravityAuthSupport.ts b/apps/server/src/provider/antigravityAuthSupport.ts index 99ccd525b0c1f..e9d546df480e3 100644 --- a/apps/server/src/provider/antigravityAuthSupport.ts +++ b/apps/server/src/provider/antigravityAuthSupport.ts @@ -207,16 +207,13 @@ function antigravityEnvironment( if (!removedEnvironmentKeys.has(key.toUpperCase())) environment[key] = value; } // Put the GCP pair in settings.json because GOOGLE_API_KEY takes precedence in the environment. - const credentialsFile = - auth.credentialsFile || - (auth.authMethod === "agent-platform" ? baseEnv.GOOGLE_APPLICATION_CREDENTIALS : undefined); const credential = auth.authMethod === "gemini-api-key" && auth.apiKey ? { GEMINI_API_KEY: auth.apiKey } : auth.authMethod === "agent-platform" && auth.apiKey ? { GOOGLE_API_KEY: auth.apiKey } - : auth.authMethod === "agent-platform" && credentialsFile - ? { GOOGLE_APPLICATION_CREDENTIALS: credentialsFile } + : auth.authMethod === "agent-platform" && auth.credentialsFile + ? { GOOGLE_APPLICATION_CREDENTIALS: auth.credentialsFile } : {}; // Each launch unpacks about 1 GB; use T3-owned temp so the driver can reclaim files after force-kill. const tempDirectory = runtimeTempDirectory ?? profile.tempDirectory; diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts index 99e668c7eef1f..50f84a4744bde 100644 --- a/packages/contracts/src/settings.ts +++ b/packages/contracts/src/settings.ts @@ -898,7 +898,7 @@ export const AntigravitySettings = makeProviderSettingsSchema( Schema.annotateKey({ title: "Credentials file", description: - "Application Default Credentials or service account JSON. Agent Platform uses it when no API key is set, in place of GOOGLE_APPLICATION_CREDENTIALS.", + "Application Default Credentials or service account JSON. Set the file path here; ambient GOOGLE_APPLICATION_CREDENTIALS environment variables are ignored.", providerSettingsForm: { placeholder: "Default ADC", clearWhenEmpty: "omit" }, }), ),