feat: expose provider auth evidence lookup

This commit is contained in:
Shakker
2026-04-29 18:54:37 +01:00
parent 1d1edca92f
commit dd5b96c11d
3 changed files with 127 additions and 1 deletions

View File

@@ -1,8 +1,12 @@
import {
listKnownProviderAuthEnvVarNames,
resolveProviderAuthEvidence,
resolveProviderAuthEnvVarCandidates,
} from "../secrets/provider-env-vars.js";
import type { ProviderEnvVarLookupParams } from "../secrets/provider-env-vars.js";
import type {
ProviderAuthEvidence,
ProviderEnvVarLookupParams,
} from "../secrets/provider-env-vars.js";
export function resolveProviderEnvApiKeyCandidates(
params?: ProviderEnvVarLookupParams,
@@ -10,6 +14,12 @@ export function resolveProviderEnvApiKeyCandidates(
return resolveProviderAuthEnvVarCandidates(params);
}
export function resolveProviderEnvAuthEvidence(
params?: ProviderEnvVarLookupParams,
): Record<string, readonly ProviderAuthEvidence[]> {
return resolveProviderAuthEvidence(params);
}
export const PROVIDER_ENV_API_KEY_CANDIDATES = resolveProviderEnvApiKeyCandidates();
export function listKnownProviderEnvApiKeyNames(): string[] {

View File

@@ -6,6 +6,7 @@ import {
listKnownSecretEnvVarNames,
PROVIDER_AUTH_ENV_VAR_CANDIDATES,
PROVIDER_ENV_VARS,
resolveProviderAuthEvidence,
} from "./provider-env-vars.js";
type MockManifestRegistry = {
@@ -19,6 +20,15 @@ type MockManifestRegistry = {
providers?: Array<{
id: string;
envVars?: string[];
authEvidence?: Array<{
type: "local-file-with-env";
fileEnvVar?: string;
fallbackPaths?: string[];
requiresAnyEnv?: string[];
requiresAllEnv?: string[];
credentialMarker: string;
source?: string;
}>;
}>;
};
}>;
@@ -107,6 +117,44 @@ describe("provider env vars dynamic manifest metadata", () => {
expect(listKnownSecretEnvVarNames()).toContain("MODEL_STUDIO_API_KEY");
});
it("includes setup provider auth evidence without loading setup runtime", async () => {
pluginRegistryMocks.loadPluginManifestRegistryForPluginRegistry.mockReturnValue({
plugins: [
{
id: "external-cloud",
origin: "global",
setup: {
providers: [
{
id: "external-cloud",
authEvidence: [
{
type: "local-file-with-env",
fileEnvVar: "EXTERNAL_CLOUD_CREDENTIALS",
requiresAllEnv: ["EXTERNAL_CLOUD_PROJECT"],
credentialMarker: "external-cloud-local-credentials",
source: "external cloud credentials",
},
],
},
],
},
},
],
diagnostics: [],
});
expect(resolveProviderAuthEvidence()["external-cloud"]).toEqual([
{
type: "local-file-with-env",
fileEnvVar: "EXTERNAL_CLOUD_CREDENTIALS",
requiresAllEnv: ["EXTERNAL_CLOUD_PROJECT"],
credentialMarker: "external-cloud-local-credentials",
source: "external cloud credentials",
},
]);
});
it("appends setup provider env vars after explicit provider auth env vars", async () => {
pluginRegistryMocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
plugins: [

View File

@@ -29,6 +29,16 @@ export type ProviderEnvVarLookupParams = {
includeUntrustedWorkspacePlugins?: boolean;
};
export type ProviderAuthEvidence = {
type: "local-file-with-env";
fileEnvVar?: string;
fallbackPaths?: readonly string[];
requiresAnyEnv?: readonly string[];
requiresAllEnv?: readonly string[];
credentialMarker: string;
source?: string;
};
function isWorkspacePluginTrustedForProviderEnvVars(
plugin: PluginManifestRecord,
config: OpenClawConfig | undefined,
@@ -73,6 +83,27 @@ function appendUniqueEnvVarCandidates(
}
}
function appendUniqueAuthEvidence(
target: Record<string, ProviderAuthEvidence[]>,
providerId: string,
evidence: readonly ProviderAuthEvidence[],
) {
const normalizedProviderId = providerId.trim();
if (!normalizedProviderId || evidence.length === 0) {
return;
}
const bucket = (target[normalizedProviderId] ??= []);
const seen = new Set(bucket.map((entry) => JSON.stringify(entry)));
for (const entry of evidence) {
const key = JSON.stringify(entry);
if (seen.has(key)) {
continue;
}
seen.add(key);
bucket.push(entry);
}
}
function resolveManifestProviderAuthEnvVarCandidates(
params?: ProviderEnvVarLookupParams,
): Record<string, string[]> {
@@ -111,6 +142,37 @@ function resolveManifestProviderAuthEnvVarCandidates(
return candidates;
}
function resolveManifestProviderAuthEvidence(
params?: ProviderEnvVarLookupParams,
): Record<string, ProviderAuthEvidence[]> {
const registry = loadPluginManifestRegistryForPluginRegistry({
config: params?.config,
workspaceDir: params?.workspaceDir,
env: params?.env,
preferPersisted: false,
includeDisabled: true,
});
const evidenceByProvider: Record<string, ProviderAuthEvidence[]> = {};
for (const plugin of registry.plugins) {
if (!shouldUsePluginProviderEnvVars(plugin, params)) {
continue;
}
for (const provider of plugin.setup?.providers ?? []) {
appendUniqueAuthEvidence(evidenceByProvider, provider.id, provider.authEvidence ?? []);
}
}
const aliases = resolveProviderAuthAliasMap(params);
for (const [alias, target] of Object.entries(aliases).toSorted(([left], [right]) =>
left.localeCompare(right),
)) {
const evidence = evidenceByProvider[target];
if (evidence) {
appendUniqueAuthEvidence(evidenceByProvider, alias, evidence);
}
}
return evidenceByProvider;
}
export function resolveProviderAuthEnvVarCandidates(
params?: ProviderEnvVarLookupParams,
): Record<string, readonly string[]> {
@@ -120,6 +182,12 @@ export function resolveProviderAuthEnvVarCandidates(
};
}
export function resolveProviderAuthEvidence(
params?: ProviderEnvVarLookupParams,
): Record<string, readonly ProviderAuthEvidence[]> {
return resolveManifestProviderAuthEvidence(params);
}
export function resolveProviderEnvVars(
params?: ProviderEnvVarLookupParams,
): Record<string, readonly string[]> {