




















@@ -129,7 +129,10 @@ vi.mock("./model-auth-env-vars.js", () => {
129129{
130130type: "local-file-with-env",
131131fileEnvVar: "GOOGLE_APPLICATION_CREDENTIALS",
132-fallbackPaths: ["${HOME}/.config/gcloud/application_default_credentials.json"],
132+fallbackPaths: [
133+"${HOME}/.config/gcloud/application_default_credentials.json",
134+"${APPDATA}/gcloud/application_default_credentials.json",
135+],
133136requiresAnyEnv: ["GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT"],
134137requiresAllEnv: ["GOOGLE_CLOUD_LOCATION"],
135138credentialMarker: "gcp-vertex-credentials",
@@ -1013,6 +1016,76 @@ describe("getApiKeyForModel", () => {
10131016}
10141017});
101510181019+it("resolveEnvApiKey('google-vertex') rejects GOOGLE_CLOUD_PROJECT_ID-only ADC auth evidence", async () => {
1020+const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-google-adc-project-id-"));
1021+const credentialsPath = path.join(tempDir, "adc.json");
1022+await fs.writeFile(credentialsPath, "{}", "utf8");
1023+1024+try {
1025+const resolved = resolveEnvApiKey("google-vertex", {
1026+GOOGLE_APPLICATION_CREDENTIALS: credentialsPath,
1027+GOOGLE_CLOUD_LOCATION: "us-central1",
1028+GOOGLE_CLOUD_PROJECT_ID: "vertex-project",
1029+} as NodeJS.ProcessEnv);
1030+1031+expect(resolved).toBeNull();
1032+} finally {
1033+await fs.rm(tempDir, { recursive: true, force: true });
1034+}
1035+});
1036+1037+it("resolveEnvApiKey('google-vertex') accepts Windows APPDATA ADC fallback evidence", async () => {
1038+const appDataDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-google-adc-appdata-"));
1039+const fallbackDir = path.join(appDataDir, "gcloud");
1040+await fs.mkdir(fallbackDir, { recursive: true });
1041+await fs.writeFile(
1042+path.join(fallbackDir, "application_default_credentials.json"),
1043+"{}",
1044+"utf8",
1045+);
1046+1047+try {
1048+const resolved = resolveEnvApiKey("google-vertex", {
1049+APPDATA: appDataDir,
1050+GOOGLE_CLOUD_LOCATION: "us-central1",
1051+GOOGLE_CLOUD_PROJECT: "vertex-project",
1052+} as NodeJS.ProcessEnv);
1053+1054+expect(resolved?.apiKey).toBe("gcp-vertex-credentials");
1055+expect(resolved?.source).toBe("gcloud adc");
1056+} finally {
1057+await fs.rm(appDataDir, { recursive: true, force: true });
1058+}
1059+});
1060+1061+it("resolveEnvApiKey('google-vertex') does not synthesize APPDATA from USERPROFILE", async () => {
1062+const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-google-adc-home-"));
1063+const userProfileDir = await fs.mkdtemp(
1064+path.join(os.tmpdir(), "openclaw-google-adc-userprofile-"),
1065+);
1066+const fallbackDir = path.join(userProfileDir, "AppData", "Roaming", "gcloud");
1067+await fs.mkdir(fallbackDir, { recursive: true });
1068+await fs.writeFile(
1069+path.join(fallbackDir, "application_default_credentials.json"),
1070+"{}",
1071+"utf8",
1072+);
1073+1074+try {
1075+const resolved = resolveEnvApiKey("google-vertex", {
1076+HOME: homeDir,
1077+USERPROFILE: userProfileDir,
1078+GOOGLE_CLOUD_LOCATION: "us-central1",
1079+GOOGLE_CLOUD_PROJECT: "vertex-project",
1080+} as NodeJS.ProcessEnv);
1081+1082+expect(resolved).toBeNull();
1083+} finally {
1084+await fs.rm(homeDir, { recursive: true, force: true });
1085+await fs.rm(userProfileDir, { recursive: true, force: true });
1086+}
1087+});
1088+10161089it("resolveEnvApiKey('google-vertex') keeps ADC fallback when manifest env candidates are empty", async () => {
10171090const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-google-adc-candidates-"));
10181091const credentialsPath = path.join(tempDir, "adc.json");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。