mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 15:50:20 +00:00
follow-up: align ingress, atomic paths, and channel tests with credential semantics (#33733)
Merged via squash.
Prepared head SHA: c290c2ab6a
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
Reviewed-by: @joshavant
This commit is contained in:
@@ -211,9 +211,8 @@ export function registerTriggerHandlingUsageSummaryCases(params: {
|
||||
);
|
||||
const text = Array.isArray(res) ? res[0]?.text : res?.text;
|
||||
expect(text).toContain("api-key");
|
||||
expect(text).toMatch(/\u2026|\.{3}/);
|
||||
expect(text).toContain("sk-tes");
|
||||
expect(text).toContain("abcdef");
|
||||
expect(text).not.toContain("sk-test");
|
||||
expect(text).not.toContain("abcdef");
|
||||
expect(text).not.toContain("1234567890abcdef");
|
||||
expect(text).toContain("(anthropic:work)");
|
||||
expect(text).not.toContain("mixed");
|
||||
|
||||
114
src/auto-reply/reply/directive-handling.auth.test.ts
Normal file
114
src/auto-reply/reply/directive-handling.auth.test.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { AuthProfileStore } from "../../agents/auth-profiles.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
|
||||
let mockStore: AuthProfileStore;
|
||||
let mockOrder: string[];
|
||||
|
||||
vi.mock("../../agents/auth-health.js", () => ({
|
||||
formatRemainingShort: () => "1h",
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/auth-profiles.js", () => ({
|
||||
isProfileInCooldown: () => false,
|
||||
resolveAuthProfileDisplayLabel: ({ profileId }: { profileId: string }) => profileId,
|
||||
resolveAuthStorePathForDisplay: () => "/tmp/auth-profiles.json",
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/model-selection.js", () => ({
|
||||
findNormalizedProviderValue: (
|
||||
values: Record<string, unknown> | undefined,
|
||||
provider: string,
|
||||
): unknown => {
|
||||
if (!values) {
|
||||
return undefined;
|
||||
}
|
||||
return Object.entries(values).find(
|
||||
([key]) => key.toLowerCase() === provider.toLowerCase(),
|
||||
)?.[1];
|
||||
},
|
||||
normalizeProviderId: (provider: string) => provider.trim().toLowerCase(),
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/model-auth.js", () => ({
|
||||
ensureAuthProfileStore: () => mockStore,
|
||||
getCustomProviderApiKey: () => undefined,
|
||||
resolveAuthProfileOrder: () => mockOrder,
|
||||
resolveEnvApiKey: () => null,
|
||||
}));
|
||||
|
||||
const { resolveAuthLabel } = await import("./directive-handling.auth.js");
|
||||
|
||||
describe("resolveAuthLabel ref-aware labels", () => {
|
||||
beforeEach(() => {
|
||||
mockStore = {
|
||||
version: 1,
|
||||
profiles: {},
|
||||
};
|
||||
mockOrder = [];
|
||||
});
|
||||
|
||||
it("shows api-key (ref) for keyRef-only profiles in compact mode", async () => {
|
||||
mockStore.profiles = {
|
||||
"openai:default": {
|
||||
type: "api_key",
|
||||
provider: "openai",
|
||||
keyRef: { source: "env", provider: "default", id: "OPENAI_API_KEY" },
|
||||
},
|
||||
};
|
||||
mockOrder = ["openai:default"];
|
||||
|
||||
const result = await resolveAuthLabel(
|
||||
"openai",
|
||||
{} as OpenClawConfig,
|
||||
"/tmp/models.json",
|
||||
undefined,
|
||||
"compact",
|
||||
);
|
||||
|
||||
expect(result.label).toBe("openai:default api-key (ref)");
|
||||
});
|
||||
|
||||
it("shows token (ref) for tokenRef-only profiles in compact mode", async () => {
|
||||
mockStore.profiles = {
|
||||
"github-copilot:default": {
|
||||
type: "token",
|
||||
provider: "github-copilot",
|
||||
tokenRef: { source: "env", provider: "default", id: "GITHUB_TOKEN" },
|
||||
},
|
||||
};
|
||||
mockOrder = ["github-copilot:default"];
|
||||
|
||||
const result = await resolveAuthLabel(
|
||||
"github-copilot",
|
||||
{} as OpenClawConfig,
|
||||
"/tmp/models.json",
|
||||
undefined,
|
||||
"compact",
|
||||
);
|
||||
|
||||
expect(result.label).toBe("github-copilot:default token (ref)");
|
||||
});
|
||||
|
||||
it("uses token:ref instead of token:missing in verbose mode", async () => {
|
||||
mockStore.profiles = {
|
||||
"github-copilot:default": {
|
||||
type: "token",
|
||||
provider: "github-copilot",
|
||||
tokenRef: { source: "env", provider: "default", id: "GITHUB_TOKEN" },
|
||||
},
|
||||
};
|
||||
mockOrder = ["github-copilot:default"];
|
||||
|
||||
const result = await resolveAuthLabel(
|
||||
"github-copilot",
|
||||
{} as OpenClawConfig,
|
||||
"/tmp/models.json",
|
||||
undefined,
|
||||
"verbose",
|
||||
);
|
||||
|
||||
expect(result.label).toContain("github-copilot:default=token:ref");
|
||||
expect(result.label).not.toContain("token:missing");
|
||||
});
|
||||
});
|
||||
@@ -12,11 +12,27 @@ import {
|
||||
} from "../../agents/model-auth.js";
|
||||
import { findNormalizedProviderValue, normalizeProviderId } from "../../agents/model-selection.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { coerceSecretRef } from "../../config/types.secrets.js";
|
||||
import { shortenHomePath } from "../../utils.js";
|
||||
import { maskApiKey } from "../../utils/mask-api-key.js";
|
||||
|
||||
export type ModelAuthDetailMode = "compact" | "verbose";
|
||||
|
||||
function resolveStoredCredentialLabel(params: {
|
||||
value: unknown;
|
||||
refValue: unknown;
|
||||
mode: ModelAuthDetailMode;
|
||||
}): string {
|
||||
const masked = maskApiKey(typeof params.value === "string" ? params.value : "");
|
||||
if (masked !== "missing") {
|
||||
return masked;
|
||||
}
|
||||
if (coerceSecretRef(params.refValue)) {
|
||||
return params.mode === "compact" ? "(ref)" : "ref";
|
||||
}
|
||||
return "missing";
|
||||
}
|
||||
|
||||
export const resolveAuthLabel = async (
|
||||
provider: string,
|
||||
cfg: OpenClawConfig,
|
||||
@@ -57,12 +73,22 @@ export const resolveAuthLabel = async (
|
||||
}
|
||||
|
||||
if (profile.type === "api_key") {
|
||||
const keyLabel = resolveStoredCredentialLabel({
|
||||
value: profile.key,
|
||||
refValue: profile.keyRef,
|
||||
mode,
|
||||
});
|
||||
return {
|
||||
label: `${profileId} api-key ${maskApiKey(profile.key ?? "")}${more}`,
|
||||
label: `${profileId} api-key ${keyLabel}${more}`,
|
||||
source: "",
|
||||
};
|
||||
}
|
||||
if (profile.type === "token") {
|
||||
const tokenLabel = resolveStoredCredentialLabel({
|
||||
value: profile.token,
|
||||
refValue: profile.tokenRef,
|
||||
mode,
|
||||
});
|
||||
const exp =
|
||||
typeof profile.expires === "number" &&
|
||||
Number.isFinite(profile.expires) &&
|
||||
@@ -72,7 +98,7 @@ export const resolveAuthLabel = async (
|
||||
: ` exp ${formatUntil(profile.expires)}`
|
||||
: "";
|
||||
return {
|
||||
label: `${profileId} token ${maskApiKey(profile.token)}${exp}${more}`,
|
||||
label: `${profileId} token ${tokenLabel}${exp}${more}`,
|
||||
source: "",
|
||||
};
|
||||
}
|
||||
@@ -118,10 +144,20 @@ export const resolveAuthLabel = async (
|
||||
return `${profileId}=missing${suffix}`;
|
||||
}
|
||||
if (profile.type === "api_key") {
|
||||
const keyLabel = resolveStoredCredentialLabel({
|
||||
value: profile.key,
|
||||
refValue: profile.keyRef,
|
||||
mode,
|
||||
});
|
||||
const suffix = flags.length > 0 ? ` (${flags.join(", ")})` : "";
|
||||
return `${profileId}=${maskApiKey(profile.key ?? "")}${suffix}`;
|
||||
return `${profileId}=${keyLabel}${suffix}`;
|
||||
}
|
||||
if (profile.type === "token") {
|
||||
const tokenLabel = resolveStoredCredentialLabel({
|
||||
value: profile.token,
|
||||
refValue: profile.tokenRef,
|
||||
mode,
|
||||
});
|
||||
if (
|
||||
typeof profile.expires === "number" &&
|
||||
Number.isFinite(profile.expires) &&
|
||||
@@ -130,7 +166,7 @@ export const resolveAuthLabel = async (
|
||||
flags.push(profile.expires <= now ? "expired" : `exp ${formatUntil(profile.expires)}`);
|
||||
}
|
||||
const suffix = flags.length > 0 ? ` (${flags.join(", ")})` : "";
|
||||
return `${profileId}=token:${maskApiKey(profile.token)}${suffix}`;
|
||||
return `${profileId}=token:${tokenLabel}${suffix}`;
|
||||
}
|
||||
const display = resolveAuthProfileDisplayLabel({
|
||||
cfg,
|
||||
|
||||
Reference in New Issue
Block a user