mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
fix: compatibility gaps in the new Google Vertex ADC manifest evidence
Tighten Google Vertex ADC manifest evidence to canonical project env vars and canonical ADC fallback paths only. Local proof: - OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test src/agents/model-auth.profiles.test.ts src/plugins/manifest-registry.test.ts src/secrets/provider-env-vars.dynamic.test.ts - pnpm exec oxfmt --check --threads=1 docs/plugins/manifest.md extensions/google/openclaw.plugin.json src/agents/model-auth-env.ts src/agents/model-auth.profiles.test.ts src/plugins/manifest.ts - git diff --check origin/main...HEAD CI note: checks-node-core-support-boundary was red on an unrelated tooling assertion in test/scripts/test-projects.test.ts for packages/sdk/src/index.test.ts routing; that file and scripts/test-projects.mjs are unchanged from origin/main.
This commit is contained in:
@@ -431,15 +431,15 @@ provider API probes.
|
||||
|
||||
Supported evidence entries:
|
||||
|
||||
| Field | Required | Type | What it means |
|
||||
| ------------------ | -------- | ---------- | --------------------------------------------------------------------------------------------- |
|
||||
| `type` | Yes | `string` | Currently `local-file-with-env`. |
|
||||
| `fileEnvVar` | No | `string` | Env var containing an explicit credential file path. |
|
||||
| `fallbackPaths` | No | `string[]` | Local credential file paths checked when `fileEnvVar` is absent or empty. Supports `${HOME}`. |
|
||||
| `requiresAnyEnv` | No | `string[]` | At least one listed env var must be non-empty before the evidence is valid. |
|
||||
| `requiresAllEnv` | No | `string[]` | Every listed env var must be non-empty before the evidence is valid. |
|
||||
| `credentialMarker` | Yes | `string` | Non-secret marker returned when the evidence is present. |
|
||||
| `source` | No | `string` | User-facing source label for auth/status output. |
|
||||
| Field | Required | Type | What it means |
|
||||
| ------------------ | -------- | ---------- | -------------------------------------------------------------------------------------------------------------- |
|
||||
| `type` | Yes | `string` | Currently `local-file-with-env`. |
|
||||
| `fileEnvVar` | No | `string` | Env var containing an explicit credential file path. |
|
||||
| `fallbackPaths` | No | `string[]` | Local credential file paths checked when `fileEnvVar` is absent or empty. Supports `${HOME}` and `${APPDATA}`. |
|
||||
| `requiresAnyEnv` | No | `string[]` | At least one listed env var must be non-empty before the evidence is valid. |
|
||||
| `requiresAllEnv` | No | `string[]` | Every listed env var must be non-empty before the evidence is valid. |
|
||||
| `credentialMarker` | Yes | `string` | Non-secret marker returned when the evidence is present. |
|
||||
| `source` | No | `string` | User-facing source label for auth/status output. |
|
||||
|
||||
### setup fields
|
||||
|
||||
|
||||
@@ -81,7 +81,10 @@
|
||||
{
|
||||
"type": "local-file-with-env",
|
||||
"fileEnvVar": "GOOGLE_APPLICATION_CREDENTIALS",
|
||||
"fallbackPaths": ["${HOME}/.config/gcloud/application_default_credentials.json"],
|
||||
"fallbackPaths": [
|
||||
"${HOME}/.config/gcloud/application_default_credentials.json",
|
||||
"${APPDATA}/gcloud/application_default_credentials.json"
|
||||
],
|
||||
"requiresAnyEnv": ["GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT"],
|
||||
"requiresAllEnv": ["GOOGLE_CLOUD_LOCATION"],
|
||||
"credentialMarker": "gcp-vertex-credentials",
|
||||
|
||||
@@ -32,7 +32,11 @@ function expandAuthEvidencePath(rawPath: string, env: NodeJS.ProcessEnv): string
|
||||
return undefined;
|
||||
}
|
||||
const homeDir = normalizeOptionalPathInput(env.HOME) ?? os.homedir();
|
||||
return trimmed.replaceAll("${HOME}", homeDir);
|
||||
const appDataDir = normalizeOptionalPathInput(env.APPDATA);
|
||||
if (trimmed.includes("${APPDATA}") && !appDataDir) {
|
||||
return undefined;
|
||||
}
|
||||
return trimmed.replaceAll("${HOME}", homeDir).replaceAll("${APPDATA}", appDataDir ?? "");
|
||||
}
|
||||
|
||||
function normalizeOptionalPathInput(value: unknown): string | undefined {
|
||||
|
||||
@@ -129,7 +129,10 @@ vi.mock("./model-auth-env-vars.js", () => {
|
||||
{
|
||||
type: "local-file-with-env",
|
||||
fileEnvVar: "GOOGLE_APPLICATION_CREDENTIALS",
|
||||
fallbackPaths: ["${HOME}/.config/gcloud/application_default_credentials.json"],
|
||||
fallbackPaths: [
|
||||
"${HOME}/.config/gcloud/application_default_credentials.json",
|
||||
"${APPDATA}/gcloud/application_default_credentials.json",
|
||||
],
|
||||
requiresAnyEnv: ["GOOGLE_CLOUD_PROJECT", "GCLOUD_PROJECT"],
|
||||
requiresAllEnv: ["GOOGLE_CLOUD_LOCATION"],
|
||||
credentialMarker: "gcp-vertex-credentials",
|
||||
@@ -1013,6 +1016,76 @@ describe("getApiKeyForModel", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("resolveEnvApiKey('google-vertex') rejects GOOGLE_CLOUD_PROJECT_ID-only ADC auth evidence", async () => {
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-google-adc-project-id-"));
|
||||
const credentialsPath = path.join(tempDir, "adc.json");
|
||||
await fs.writeFile(credentialsPath, "{}", "utf8");
|
||||
|
||||
try {
|
||||
const resolved = resolveEnvApiKey("google-vertex", {
|
||||
GOOGLE_APPLICATION_CREDENTIALS: credentialsPath,
|
||||
GOOGLE_CLOUD_LOCATION: "us-central1",
|
||||
GOOGLE_CLOUD_PROJECT_ID: "vertex-project",
|
||||
} as NodeJS.ProcessEnv);
|
||||
|
||||
expect(resolved).toBeNull();
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("resolveEnvApiKey('google-vertex') accepts Windows APPDATA ADC fallback evidence", async () => {
|
||||
const appDataDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-google-adc-appdata-"));
|
||||
const fallbackDir = path.join(appDataDir, "gcloud");
|
||||
await fs.mkdir(fallbackDir, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(fallbackDir, "application_default_credentials.json"),
|
||||
"{}",
|
||||
"utf8",
|
||||
);
|
||||
|
||||
try {
|
||||
const resolved = resolveEnvApiKey("google-vertex", {
|
||||
APPDATA: appDataDir,
|
||||
GOOGLE_CLOUD_LOCATION: "us-central1",
|
||||
GOOGLE_CLOUD_PROJECT: "vertex-project",
|
||||
} as NodeJS.ProcessEnv);
|
||||
|
||||
expect(resolved?.apiKey).toBe("gcp-vertex-credentials");
|
||||
expect(resolved?.source).toBe("gcloud adc");
|
||||
} finally {
|
||||
await fs.rm(appDataDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("resolveEnvApiKey('google-vertex') does not synthesize APPDATA from USERPROFILE", async () => {
|
||||
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-google-adc-home-"));
|
||||
const userProfileDir = await fs.mkdtemp(
|
||||
path.join(os.tmpdir(), "openclaw-google-adc-userprofile-"),
|
||||
);
|
||||
const fallbackDir = path.join(userProfileDir, "AppData", "Roaming", "gcloud");
|
||||
await fs.mkdir(fallbackDir, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(fallbackDir, "application_default_credentials.json"),
|
||||
"{}",
|
||||
"utf8",
|
||||
);
|
||||
|
||||
try {
|
||||
const resolved = resolveEnvApiKey("google-vertex", {
|
||||
HOME: homeDir,
|
||||
USERPROFILE: userProfileDir,
|
||||
GOOGLE_CLOUD_LOCATION: "us-central1",
|
||||
GOOGLE_CLOUD_PROJECT: "vertex-project",
|
||||
} as NodeJS.ProcessEnv);
|
||||
|
||||
expect(resolved).toBeNull();
|
||||
} finally {
|
||||
await fs.rm(homeDir, { recursive: true, force: true });
|
||||
await fs.rm(userProfileDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("resolveEnvApiKey('google-vertex') keeps ADC fallback when manifest env candidates are empty", async () => {
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-google-adc-candidates-"));
|
||||
const credentialsPath = path.join(tempDir, "adc.json");
|
||||
|
||||
@@ -201,7 +201,7 @@ export type PluginManifestSetupProviderAuthEvidence = {
|
||||
type: "local-file-with-env";
|
||||
/** Optional env var containing an explicit credential file path. */
|
||||
fileEnvVar?: string;
|
||||
/** Optional fallback credential file paths. Supports `${HOME}` only. */
|
||||
/** Optional fallback credential file paths. Supports `${HOME}` and `${APPDATA}`. */
|
||||
fallbackPaths?: string[];
|
||||
/** At least one of these env vars must be non-empty when provided. */
|
||||
requiresAnyEnv?: string[];
|
||||
|
||||
Reference in New Issue
Block a user