




























@@ -1,4 +1,8 @@
1+import fs from "node:fs/promises";
2+import os from "node:os";
3+import path from "node:path";
14import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
5+import { withEnvAsync } from "../test-utils/env.js";
2637let modelsListCommand: typeof import("./models/list.list-command.js").modelsListCommand;
48let loadModelRegistry: typeof import("./models/list.registry.js").loadModelRegistry;
@@ -333,6 +337,35 @@ describe("models list/status", () => {
333337modelRegistryState.available = available ? [ZAI_MODEL, OPENAI_MODEL] : [];
334338}
335339340+async function writeWorkspaceAuthEvidencePlugin(workspaceDir: string) {
341+const pluginDir = path.join(workspaceDir, ".openclaw", "extensions", "workspace-cloud");
342+await fs.mkdir(pluginDir, { recursive: true });
343+await fs.writeFile(path.join(pluginDir, "index.ts"), "export default {}\n", "utf8");
344+await fs.writeFile(
345+path.join(pluginDir, "openclaw.plugin.json"),
346+JSON.stringify({
347+id: "workspace-cloud",
348+configSchema: { type: "object" },
349+setup: {
350+providers: [
351+{
352+id: "workspace-cloud",
353+authEvidence: [
354+{
355+type: "local-file-with-env",
356+fileEnvVar: "WORKSPACE_CLOUD_CREDENTIALS",
357+credentialMarker: "workspace-cloud-local-credentials",
358+source: "workspace cloud credentials",
359+},
360+],
361+},
362+],
363+},
364+}),
365+"utf8",
366+);
367+}
368+336369beforeAll(async () => {
337370({ modelsListCommand } = await import("./models/list.list-command.js"));
338371({ loadModelRegistry, toModelRow } = await import("./models/list.registry.js"));
@@ -410,6 +443,67 @@ describe("models list/status", () => {
410443expect(payload.models[0]?.available).toBe(false);
411444});
412445446+it("models list uses trusted workspace plugin auth evidence for configured rows", async () => {
447+const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-models-list-auth-"));
448+const workspaceDir = path.join(tempRoot, "workspace");
449+const bundledDir = path.join(tempRoot, "bundled");
450+const stateDir = path.join(tempRoot, "state");
451+const credentialsPath = path.join(tempRoot, "credentials.json");
452+await fs.mkdir(bundledDir, { recursive: true });
453+await fs.mkdir(stateDir, { recursive: true });
454+await fs.writeFile(credentialsPath, "{}", "utf8");
455+await writeWorkspaceAuthEvidencePlugin(workspaceDir);
456+getRuntimeConfig.mockReturnValue({
457+agents: {
458+defaults: {
459+workspace: workspaceDir,
460+model: "workspace-cloud/model-a",
461+},
462+},
463+plugins: { allow: ["workspace-cloud"] },
464+models: {
465+providers: {
466+"workspace-cloud": {
467+baseUrl: "https://workspace-cloud.example/v1",
468+api: "openai-responses",
469+models: [
470+{
471+id: "model-a",
472+name: "Workspace Cloud Model A",
473+input: ["text"],
474+contextWindow: 8192,
475+maxTokens: 4096,
476+cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
477+},
478+],
479+},
480+},
481+},
482+});
483+const runtime = makeRuntime();
484+485+try {
486+await withEnvAsync(
487+{
488+OPENCLAW_BUNDLED_PLUGINS_DIR: bundledDir,
489+OPENCLAW_STATE_DIR: stateDir,
490+WORKSPACE_CLOUD_CREDENTIALS: credentialsPath,
491+},
492+() => modelsListCommand({ all: true, provider: "workspace-cloud", json: true }, runtime),
493+);
494+} finally {
495+await fs.rm(tempRoot, { recursive: true, force: true });
496+}
497+498+const payload = parseJsonLog(runtime);
499+expect(payload.models).toEqual([
500+expect.objectContaining({
501+key: "workspace-cloud/model-a",
502+available: true,
503+}),
504+]);
505+});
506+413507it("models list all includes unauthenticated provider catalog rows", async () => {
414508setDefaultZaiRegistry({ available: false });
415509hasProviderStaticCatalogForFilter.mockResolvedValueOnce(true);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。