Files
openclaw/src/agents/models-config.runtime-source-snapshot.test.ts
2026-03-13 18:38:12 +00:00

266 lines
8.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import {
clearConfigCache,
clearRuntimeConfigSnapshot,
loadConfig,
setRuntimeConfigSnapshot,
} from "../config/config.js";
import { NON_ENV_SECRETREF_MARKER } from "./model-auth-markers.js";
import {
installModelsConfigTestHooks,
withModelsTempHome as withTempHome,
} from "./models-config.e2e-harness.js";
import { ensureOpenClawModelsJson } from "./models-config.js";
import { readGeneratedModelsJson } from "./models-config.test-utils.js";
installModelsConfigTestHooks();
function createOpenAiApiKeySourceConfig(): OpenClawConfig {
return {
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
apiKey: { source: "env", provider: "default", id: "OPENAI_API_KEY" }, // pragma: allowlist secret
api: "openai-completions" as const,
models: [],
},
},
},
};
}
function createOpenAiApiKeyRuntimeConfig(): OpenClawConfig {
return {
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
apiKey: "sk-runtime-resolved", // pragma: allowlist secret
api: "openai-completions" as const,
models: [],
},
},
},
};
}
function createOpenAiHeaderSourceConfig(): OpenClawConfig {
return {
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
api: "openai-completions" as const,
headers: {
Authorization: {
source: "env",
provider: "default",
id: "OPENAI_HEADER_TOKEN", // pragma: allowlist secret
},
"X-Tenant-Token": {
source: "file",
provider: "vault",
id: "/providers/openai/tenantToken",
},
},
models: [],
},
},
},
};
}
function createOpenAiHeaderRuntimeConfig(): OpenClawConfig {
return {
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
api: "openai-completions" as const,
headers: {
Authorization: "Bearer runtime-openai-token",
"X-Tenant-Token": "runtime-tenant-token",
},
models: [],
},
},
},
};
}
function withGatewayTokenMode(config: OpenClawConfig): OpenClawConfig {
return {
...config,
gateway: {
auth: {
mode: "token",
},
},
};
}
async function withGeneratedModelsFromRuntimeSource(
params: {
sourceConfig: OpenClawConfig;
runtimeConfig: OpenClawConfig;
candidateConfig?: OpenClawConfig;
},
runAssertions: () => Promise<void>,
) {
await withTempHome(async () => {
try {
setRuntimeConfigSnapshot(params.runtimeConfig, params.sourceConfig);
await ensureOpenClawModelsJson(params.candidateConfig ?? loadConfig());
await runAssertions();
} finally {
clearRuntimeConfigSnapshot();
clearConfigCache();
}
});
}
async function expectGeneratedProviderApiKey(providerId: string, expected: string) {
const parsed = await readGeneratedModelsJson<{
providers: Record<string, { apiKey?: string }>;
}>();
expect(parsed.providers[providerId]?.apiKey).toBe(expected);
}
async function expectGeneratedOpenAiHeaderMarkers() {
const parsed = await readGeneratedModelsJson<{
providers: Record<string, { headers?: Record<string, string> }>;
}>();
expect(parsed.providers.openai?.headers?.Authorization).toBe(
"secretref-env:OPENAI_HEADER_TOKEN", // pragma: allowlist secret
);
expect(parsed.providers.openai?.headers?.["X-Tenant-Token"]).toBe(NON_ENV_SECRETREF_MARKER);
}
describe("models-config runtime source snapshot", () => {
it("uses runtime source snapshot markers when passed the active runtime config", async () => {
await withGeneratedModelsFromRuntimeSource(
{
sourceConfig: createOpenAiApiKeySourceConfig(),
runtimeConfig: createOpenAiApiKeyRuntimeConfig(),
},
async () => expectGeneratedProviderApiKey("openai", "OPENAI_API_KEY"), // pragma: allowlist secret
);
});
it("uses non-env marker from runtime source snapshot for file refs", async () => {
await withTempHome(async () => {
const sourceConfig: OpenClawConfig = {
models: {
providers: {
moonshot: {
baseUrl: "https://api.moonshot.ai/v1",
apiKey: { source: "file", provider: "vault", id: "/moonshot/apiKey" },
api: "openai-completions" as const,
models: [],
},
},
},
};
const runtimeConfig: OpenClawConfig = {
models: {
providers: {
moonshot: {
baseUrl: "https://api.moonshot.ai/v1",
apiKey: "sk-runtime-moonshot", // pragma: allowlist secret
api: "openai-completions" as const,
models: [],
},
},
},
};
try {
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
await ensureOpenClawModelsJson(loadConfig());
const parsed = await readGeneratedModelsJson<{
providers: Record<string, { apiKey?: string }>;
}>();
expect(parsed.providers.moonshot?.apiKey).toBe(NON_ENV_SECRETREF_MARKER);
} finally {
clearRuntimeConfigSnapshot();
clearConfigCache();
}
});
});
it("projects cloned runtime configs onto source snapshot when preserving provider auth", async () => {
await withTempHome(async () => {
const sourceConfig = createOpenAiApiKeySourceConfig();
const runtimeConfig = createOpenAiApiKeyRuntimeConfig();
const clonedRuntimeConfig: OpenClawConfig = {
...runtimeConfig,
agents: {
defaults: {
imageModel: "openai/gpt-image-1",
},
},
};
try {
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
await ensureOpenClawModelsJson(clonedRuntimeConfig);
await expectGeneratedProviderApiKey("openai", "OPENAI_API_KEY"); // pragma: allowlist secret
} finally {
clearRuntimeConfigSnapshot();
clearConfigCache();
}
});
});
it("uses header markers from runtime source snapshot instead of resolved runtime values", async () => {
await withGeneratedModelsFromRuntimeSource(
{
sourceConfig: createOpenAiHeaderSourceConfig(),
runtimeConfig: createOpenAiHeaderRuntimeConfig(),
},
expectGeneratedOpenAiHeaderMarkers,
);
});
it("keeps source markers when runtime projection is skipped for incompatible top-level shape", async () => {
await withTempHome(async () => {
const sourceConfig = withGatewayTokenMode(createOpenAiApiKeySourceConfig());
const runtimeConfig = withGatewayTokenMode(createOpenAiApiKeyRuntimeConfig());
const incompatibleCandidate: OpenClawConfig = {
...createOpenAiApiKeyRuntimeConfig(),
};
try {
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
await ensureOpenClawModelsJson(incompatibleCandidate);
await expectGeneratedProviderApiKey("openai", "OPENAI_API_KEY"); // pragma: allowlist secret
} finally {
clearRuntimeConfigSnapshot();
clearConfigCache();
}
});
});
it("keeps source header markers when runtime projection is skipped for incompatible top-level shape", async () => {
await withTempHome(async () => {
const sourceConfig = withGatewayTokenMode(createOpenAiHeaderSourceConfig());
const runtimeConfig = withGatewayTokenMode(createOpenAiHeaderRuntimeConfig());
const incompatibleCandidate: OpenClawConfig = {
...createOpenAiHeaderRuntimeConfig(),
};
try {
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
await ensureOpenClawModelsJson(incompatibleCandidate);
await expectGeneratedOpenAiHeaderMarkers();
} finally {
clearRuntimeConfigSnapshot();
clearConfigCache();
}
});
});
});