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:
Josh Avant
2026-03-03 20:29:46 -06:00
committed by GitHub
parent 6842877b2e
commit 1c200ca7ae
36 changed files with 1130 additions and 219 deletions

View File

@@ -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");

View 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");
});
});

View File

@@ -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,