mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 14:14:32 +00:00
Auth profiles: resolve keyRef/tokenRef outside gateway
This commit is contained in:
committed by
Peter Steinberger
parent
5ae367aadd
commit
6a251d8d74
@@ -168,3 +168,72 @@ describe("resolveApiKeyForProfile token expiry handling", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("resolveApiKeyForProfile secret refs", () => {
|
||||||
|
it("resolves api_key keyRef from env", async () => {
|
||||||
|
const profileId = "openai:default";
|
||||||
|
const previous = process.env.OPENAI_API_KEY;
|
||||||
|
process.env.OPENAI_API_KEY = "sk-openai-ref";
|
||||||
|
try {
|
||||||
|
const result = await resolveApiKeyForProfile({
|
||||||
|
cfg: cfgFor(profileId, "openai", "api_key"),
|
||||||
|
store: {
|
||||||
|
version: 1,
|
||||||
|
profiles: {
|
||||||
|
[profileId]: {
|
||||||
|
type: "api_key",
|
||||||
|
provider: "openai",
|
||||||
|
keyRef: { source: "env", id: "OPENAI_API_KEY" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
profileId,
|
||||||
|
});
|
||||||
|
expect(result).toEqual({
|
||||||
|
apiKey: "sk-openai-ref",
|
||||||
|
provider: "openai",
|
||||||
|
email: undefined,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
if (previous === undefined) {
|
||||||
|
delete process.env.OPENAI_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.OPENAI_API_KEY = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves token tokenRef from env", async () => {
|
||||||
|
const profileId = "github-copilot:default";
|
||||||
|
const previous = process.env.GITHUB_TOKEN;
|
||||||
|
process.env.GITHUB_TOKEN = "gh-ref-token";
|
||||||
|
try {
|
||||||
|
const result = await resolveApiKeyForProfile({
|
||||||
|
cfg: cfgFor(profileId, "github-copilot", "token"),
|
||||||
|
store: {
|
||||||
|
version: 1,
|
||||||
|
profiles: {
|
||||||
|
[profileId]: {
|
||||||
|
type: "token",
|
||||||
|
provider: "github-copilot",
|
||||||
|
token: "",
|
||||||
|
tokenRef: { source: "env", id: "GITHUB_TOKEN" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
profileId,
|
||||||
|
});
|
||||||
|
expect(result).toEqual({
|
||||||
|
apiKey: "gh-ref-token",
|
||||||
|
provider: "github-copilot",
|
||||||
|
email: undefined,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
if (previous === undefined) {
|
||||||
|
delete process.env.GITHUB_TOKEN;
|
||||||
|
} else {
|
||||||
|
process.env.GITHUB_TOKEN = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import {
|
|||||||
type OAuthCredentials,
|
type OAuthCredentials,
|
||||||
type OAuthProvider,
|
type OAuthProvider,
|
||||||
} from "@mariozechner/pi-ai";
|
} from "@mariozechner/pi-ai";
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
import { loadConfig, type OpenClawConfig } from "../../config/config.js";
|
||||||
|
import { isSecretRef } from "../../config/types.secrets.js";
|
||||||
import { withFileLock } from "../../infra/file-lock.js";
|
import { withFileLock } from "../../infra/file-lock.js";
|
||||||
import { refreshQwenPortalCredentials } from "../../providers/qwen-portal-oauth.js";
|
import { refreshQwenPortalCredentials } from "../../providers/qwen-portal-oauth.js";
|
||||||
|
import { resolveSecretRefString, type SecretRefResolveCache } from "../../secrets/resolve.js";
|
||||||
import { refreshChutesTokens } from "../chutes-oauth.js";
|
import { refreshChutesTokens } from "../chutes-oauth.js";
|
||||||
import { AUTH_STORE_LOCK_OPTIONS, log } from "./constants.js";
|
import { AUTH_STORE_LOCK_OPTIONS, log } from "./constants.js";
|
||||||
import { formatAuthDoctorHint } from "./doctor.js";
|
import { formatAuthDoctorHint } from "./doctor.js";
|
||||||
@@ -255,15 +257,48 @@ export async function resolveApiKeyForProfile(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refResolveCache: SecretRefResolveCache = { fileSecretsPromise: null };
|
||||||
|
const configForRefResolution = cfg ?? loadConfig();
|
||||||
|
|
||||||
if (cred.type === "api_key") {
|
if (cred.type === "api_key") {
|
||||||
const key = cred.key?.trim();
|
let key = cred.key?.trim();
|
||||||
|
if (!key && isSecretRef(cred.keyRef)) {
|
||||||
|
try {
|
||||||
|
key = await resolveSecretRefString(cred.keyRef, {
|
||||||
|
config: configForRefResolution,
|
||||||
|
env: process.env,
|
||||||
|
cache: refResolveCache,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
log.debug("failed to resolve auth profile api_key ref", {
|
||||||
|
profileId,
|
||||||
|
provider: cred.provider,
|
||||||
|
error: err instanceof Error ? err.message : String(err),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return buildApiKeyProfileResult({ apiKey: key, provider: cred.provider, email: cred.email });
|
return buildApiKeyProfileResult({ apiKey: key, provider: cred.provider, email: cred.email });
|
||||||
}
|
}
|
||||||
if (cred.type === "token") {
|
if (cred.type === "token") {
|
||||||
const token = cred.token?.trim();
|
let token = cred.token?.trim();
|
||||||
|
if (!token && isSecretRef(cred.tokenRef)) {
|
||||||
|
try {
|
||||||
|
token = await resolveSecretRefString(cred.tokenRef, {
|
||||||
|
config: configForRefResolution,
|
||||||
|
env: process.env,
|
||||||
|
cache: refResolveCache,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
log.debug("failed to resolve auth profile token ref", {
|
||||||
|
profileId,
|
||||||
|
provider: cred.provider,
|
||||||
|
error: err instanceof Error ? err.message : String(err),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user