Files
moltbot/src/commands/models/list.auth-overview.ts
Josh Avant 36d2ae2a22 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)
2026-03-10 23:55:10 +00:00

160 lines
5.2 KiB
TypeScript

import { formatRemainingShort } from "../../agents/auth-health.js";
import {
type AuthProfileStore,
listProfilesForProvider,
resolveAuthProfileDisplayLabel,
resolveAuthStorePathForDisplay,
resolveProfileUnusableUntilForDisplay,
} from "../../agents/auth-profiles.js";
import { isNonSecretApiKeyMarker } from "../../agents/model-auth-markers.js";
import {
getCustomProviderApiKey,
resolveEnvApiKey,
resolveUsableCustomProviderApiKey,
} from "../../agents/model-auth.js";
import type { OpenClawConfig } from "../../config/config.js";
import { shortenHomePath } from "../../utils.js";
import { maskApiKey } from "./list.format.js";
import type { ProviderAuthOverview } from "./list.types.js";
function formatMarkerOrSecret(value: string): string {
return isNonSecretApiKeyMarker(value, { includeEnvVarName: false })
? `marker(${value.trim()})`
: maskApiKey(value);
}
function formatProfileSecretLabel(params: {
value: string | undefined;
ref: { source: string; id: string } | undefined;
kind: "api-key" | "token";
}): string {
const value = typeof params.value === "string" ? params.value.trim() : "";
if (value) {
const display = formatMarkerOrSecret(value);
return params.kind === "token" ? `token:${display}` : display;
}
if (params.ref) {
const refLabel = `ref(${params.ref.source}:${params.ref.id})`;
return params.kind === "token" ? `token:${refLabel}` : refLabel;
}
return params.kind === "token" ? "token:missing" : "missing";
}
export function resolveProviderAuthOverview(params: {
provider: string;
cfg: OpenClawConfig;
store: AuthProfileStore;
modelsPath: string;
}): ProviderAuthOverview {
const { provider, cfg, store } = params;
const now = Date.now();
const profiles = listProfilesForProvider(store, provider);
const withUnusableSuffix = (base: string, profileId: string) => {
const unusableUntil = resolveProfileUnusableUntilForDisplay(store, profileId);
if (!unusableUntil || now >= unusableUntil) {
return base;
}
const stats = store.usageStats?.[profileId];
const kind =
typeof stats?.disabledUntil === "number" && now < stats.disabledUntil
? `disabled${stats.disabledReason ? `:${stats.disabledReason}` : ""}`
: "cooldown";
const remaining = formatRemainingShort(unusableUntil - now);
return `${base} [${kind} ${remaining}]`;
};
const labels = profiles.map((profileId) => {
const profile = store.profiles[profileId];
if (!profile) {
return `${profileId}=missing`;
}
if (profile.type === "api_key") {
return withUnusableSuffix(
`${profileId}=${formatProfileSecretLabel({
value: profile.key,
ref: profile.keyRef,
kind: "api-key",
})}`,
profileId,
);
}
if (profile.type === "token") {
return withUnusableSuffix(
`${profileId}=${formatProfileSecretLabel({
value: profile.token,
ref: profile.tokenRef,
kind: "token",
})}`,
profileId,
);
}
const display = resolveAuthProfileDisplayLabel({ cfg, store, profileId });
const suffix =
display === profileId
? ""
: display.startsWith(profileId)
? display.slice(profileId.length).trim()
: `(${display})`;
const base = `${profileId}=OAuth${suffix ? ` ${suffix}` : ""}`;
return withUnusableSuffix(base, profileId);
});
const oauthCount = profiles.filter((id) => store.profiles[id]?.type === "oauth").length;
const tokenCount = profiles.filter((id) => store.profiles[id]?.type === "token").length;
const apiKeyCount = profiles.filter((id) => store.profiles[id]?.type === "api_key").length;
const envKey = resolveEnvApiKey(provider);
const customKey = getCustomProviderApiKey(cfg, provider);
const usableCustomKey = resolveUsableCustomProviderApiKey({ cfg, provider });
const effective: ProviderAuthOverview["effective"] = (() => {
if (profiles.length > 0) {
return {
kind: "profiles",
detail: shortenHomePath(resolveAuthStorePathForDisplay()),
};
}
if (envKey) {
const isOAuthEnv =
envKey.source.includes("OAUTH_TOKEN") || envKey.source.toLowerCase().includes("oauth");
return {
kind: "env",
detail: isOAuthEnv ? "OAuth (env)" : maskApiKey(envKey.apiKey),
};
}
if (usableCustomKey) {
return { kind: "models.json", detail: formatMarkerOrSecret(usableCustomKey.apiKey) };
}
return { kind: "missing", detail: "missing" };
})();
return {
provider,
effective,
profiles: {
count: profiles.length,
oauth: oauthCount,
token: tokenCount,
apiKey: apiKeyCount,
labels,
},
...(envKey
? {
env: {
value:
envKey.source.includes("OAUTH_TOKEN") || envKey.source.toLowerCase().includes("oauth")
? "OAuth (env)"
: maskApiKey(envKey.apiKey),
source: envKey.source,
},
}
: {}),
...(customKey
? {
modelsJson: {
value: formatMarkerOrSecret(customKey),
source: `models.json: ${shortenHomePath(params.modelsPath)}`,
},
}
: {}),
};
}