mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
* fix: restore GitHub Copilot runtime routing Refs #106170 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6053811e-f081-436b-8741-54c5cab6c016 * fix: bind Copilot metadata to resolved credentials Refs #106170 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6053811e-f081-436b-8741-54c5cab6c016 * refactor: split Copilot runtime helpers * fix: satisfy Copilot runtime static gates * fix: satisfy Copilot runtime lint --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Galin Iliev <galin.iliev@microsoft.com>
116 lines
4.1 KiB
TypeScript
116 lines
4.1 KiB
TypeScript
// Github Copilot plugin module implements auth behavior.
|
|
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
|
import type { ProviderPrepareDynamicModelContext } from "openclaw/plugin-sdk/plugin-entry";
|
|
import {
|
|
coerceSecretRef,
|
|
ensureAuthProfileStore,
|
|
listProfilesForProvider,
|
|
normalizeOptionalSecretInput,
|
|
} from "openclaw/plugin-sdk/provider-auth";
|
|
import {
|
|
resolveConfiguredSecretInputWithFallback,
|
|
resolveRequiredConfiguredSecretRefInputString,
|
|
} from "openclaw/plugin-sdk/secret-input-runtime";
|
|
import { PROVIDER_ID } from "./models.js";
|
|
|
|
export async function resolveFirstGithubToken(params: {
|
|
agentDir?: string;
|
|
config?: OpenClawConfig;
|
|
env: NodeJS.ProcessEnv;
|
|
profileId?: string;
|
|
authProfileMode?: ProviderPrepareDynamicModelContext["authProfileMode"];
|
|
}): Promise<{
|
|
githubToken: string;
|
|
hasProfile: boolean;
|
|
}> {
|
|
const authStore = ensureAuthProfileStore(params.agentDir, {
|
|
allowKeychainPrompt: false,
|
|
});
|
|
const profileIds = listProfilesForProvider(authStore, PROVIDER_ID);
|
|
const hasProfile = profileIds.length > 0;
|
|
const requestedProfileId = params.profileId?.trim();
|
|
const githubToken =
|
|
[params.env.COPILOT_GITHUB_TOKEN, params.env.GH_TOKEN, params.env.GITHUB_TOKEN]
|
|
.map((value) => normalizeOptionalSecretInput(value))
|
|
.find((value) => value !== undefined) ?? "";
|
|
const providerConfig = params.config?.models?.providers?.[PROVIDER_ID];
|
|
const preferConfiguredToken =
|
|
providerConfig?.auth === "api-key" &&
|
|
Boolean(
|
|
normalizeOptionalSecretInput(providerConfig.apiKey) || coerceSecretRef(providerConfig.apiKey),
|
|
);
|
|
const resolveConfiguredGithubToken = async () => {
|
|
if (!params.config) {
|
|
return "";
|
|
}
|
|
const resolved = await resolveConfiguredSecretInputWithFallback({
|
|
config: params.config,
|
|
env: params.env,
|
|
value: providerConfig?.apiKey,
|
|
path: `models.providers.${PROVIDER_ID}.apiKey`,
|
|
readFallback: () => "",
|
|
});
|
|
return resolved.value?.trim() ?? "";
|
|
};
|
|
const resolveDirectGithubToken = async () => {
|
|
if (preferConfiguredToken) {
|
|
const configuredToken = await resolveConfiguredGithubToken();
|
|
if (configuredToken) {
|
|
return configuredToken;
|
|
}
|
|
}
|
|
if (githubToken) {
|
|
return githubToken;
|
|
}
|
|
return preferConfiguredToken ? "" : await resolveConfiguredGithubToken();
|
|
};
|
|
if (!requestedProfileId && params.authProfileMode) {
|
|
// A missing profile id plus an explicit mode is a prepared direct-auth
|
|
// attempt. Do not let it fall back into the first stored profile: model
|
|
// limits and the later runtime exchange must use the same source token.
|
|
// Stored profiles are therefore ineligible even when the store has one.
|
|
return { githubToken: await resolveDirectGithubToken(), hasProfile: false };
|
|
}
|
|
if (!requestedProfileId && (githubToken || !hasProfile)) {
|
|
return { githubToken: await resolveDirectGithubToken(), hasProfile };
|
|
}
|
|
|
|
const profileId = requestedProfileId
|
|
? profileIds.find((candidate) => candidate === requestedProfileId)
|
|
: profileIds[0];
|
|
const profile = profileId ? authStore.profiles[profileId] : undefined;
|
|
if (profile?.type !== "token") {
|
|
return { githubToken: "", hasProfile };
|
|
}
|
|
const directToken = profile.token?.trim() ?? "";
|
|
if (directToken) {
|
|
return { githubToken: directToken, hasProfile };
|
|
}
|
|
const tokenRef = coerceSecretRef(profile.tokenRef);
|
|
if (tokenRef?.source === "env" && tokenRef.id.trim()) {
|
|
return {
|
|
githubToken: (params.env[tokenRef.id] ?? process.env[tokenRef.id] ?? "").trim(),
|
|
hasProfile,
|
|
};
|
|
}
|
|
|
|
if (tokenRef && params.config) {
|
|
try {
|
|
const resolved = await resolveRequiredConfiguredSecretRefInputString({
|
|
config: params.config,
|
|
env: params.env,
|
|
value: profile.tokenRef,
|
|
path: `providers.github-copilot.authProfiles.${profileId ?? "default"}.tokenRef`,
|
|
});
|
|
return {
|
|
githubToken: resolved?.trim() ?? "",
|
|
hasProfile,
|
|
};
|
|
} catch {
|
|
return { githubToken: "", hasProfile };
|
|
}
|
|
}
|
|
|
|
return { githubToken: "", hasProfile };
|
|
}
|