mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-24 13:04:28 +00:00
SecretRef: harden custom/provider secret persistence and reuse (#42554)
* Models: gate custom provider keys by usable secret semantics * Config: project runtime writes onto source snapshot * Models: prevent stale apiKey preservation for marker-managed providers * Runner: strip SecretRef marker headers from resolved models * Secrets: scan active agent models.json path in audit * Config: guard runtime-source projection for unrelated configs * Extensions: fix onboarding type errors in CI * Tests: align setup helper account-enabled expectation * Secrets audit: harden models.json file reads * fix: harden SecretRef custom/provider secret persistence (#42554) (thanks @joshavant)
This commit is contained in:
committed by
Peter Steinberger
parent
20237358d9
commit
36d2ae2a22
@@ -18,7 +18,11 @@ import {
|
||||
resolveAuthStorePathForDisplay,
|
||||
} from "./auth-profiles.js";
|
||||
import { PROVIDER_ENV_API_KEY_CANDIDATES } from "./model-auth-env-vars.js";
|
||||
import { OLLAMA_LOCAL_AUTH_MARKER } from "./model-auth-markers.js";
|
||||
import {
|
||||
isKnownEnvApiKeyMarker,
|
||||
isNonSecretApiKeyMarker,
|
||||
OLLAMA_LOCAL_AUTH_MARKER,
|
||||
} from "./model-auth-markers.js";
|
||||
import { normalizeProviderId } from "./model-selection.js";
|
||||
|
||||
export { ensureAuthProfileStore, resolveAuthProfileOrder } from "./auth-profiles.js";
|
||||
@@ -60,6 +64,49 @@ export function getCustomProviderApiKey(
|
||||
return normalizeOptionalSecretInput(entry?.apiKey);
|
||||
}
|
||||
|
||||
type ResolvedCustomProviderApiKey = {
|
||||
apiKey: string;
|
||||
source: string;
|
||||
};
|
||||
|
||||
export function resolveUsableCustomProviderApiKey(params: {
|
||||
cfg: OpenClawConfig | undefined;
|
||||
provider: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): ResolvedCustomProviderApiKey | null {
|
||||
const customKey = getCustomProviderApiKey(params.cfg, params.provider);
|
||||
if (!customKey) {
|
||||
return null;
|
||||
}
|
||||
if (!isNonSecretApiKeyMarker(customKey)) {
|
||||
return { apiKey: customKey, source: "models.json" };
|
||||
}
|
||||
if (!isKnownEnvApiKeyMarker(customKey)) {
|
||||
return null;
|
||||
}
|
||||
const envValue = normalizeOptionalSecretInput((params.env ?? process.env)[customKey]);
|
||||
if (!envValue) {
|
||||
return null;
|
||||
}
|
||||
const applied = new Set(getShellEnvAppliedKeys());
|
||||
return {
|
||||
apiKey: envValue,
|
||||
source: resolveEnvSourceLabel({
|
||||
applied,
|
||||
envVars: [customKey],
|
||||
label: `${customKey} (models.json marker)`,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export function hasUsableCustomProviderApiKey(
|
||||
cfg: OpenClawConfig | undefined,
|
||||
provider: string,
|
||||
env?: NodeJS.ProcessEnv,
|
||||
): boolean {
|
||||
return Boolean(resolveUsableCustomProviderApiKey({ cfg, provider, env }));
|
||||
}
|
||||
|
||||
function resolveProviderAuthOverride(
|
||||
cfg: OpenClawConfig | undefined,
|
||||
provider: string,
|
||||
@@ -238,9 +285,9 @@ export async function resolveApiKeyForProvider(params: {
|
||||
};
|
||||
}
|
||||
|
||||
const customKey = getCustomProviderApiKey(cfg, provider);
|
||||
const customKey = resolveUsableCustomProviderApiKey({ cfg, provider });
|
||||
if (customKey) {
|
||||
return { apiKey: customKey, source: "models.json", mode: "api-key" };
|
||||
return { apiKey: customKey.apiKey, source: customKey.source, mode: "api-key" };
|
||||
}
|
||||
|
||||
const syntheticLocalAuth = resolveSyntheticLocalProviderAuth({ cfg, provider });
|
||||
@@ -360,7 +407,7 @@ export function resolveModelAuthMode(
|
||||
return envKey.source.includes("OAUTH_TOKEN") ? "oauth" : "api-key";
|
||||
}
|
||||
|
||||
if (getCustomProviderApiKey(cfg, resolved)) {
|
||||
if (hasUsableCustomProviderApiKey(cfg, resolved)) {
|
||||
return "api-key";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user