Merged via squash. Prepared head SHA: 4a065ef5d849273756ceb0dd241ca24ca9e621ca Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com> Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com> Reviewed-by: @joshavant
361 lines
11 KiB
TypeScript
361 lines
11 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();
|
|
|
|
describe("models-config runtime source snapshot", () => {
|
|
it("uses runtime source snapshot markers when passed the active runtime config", async () => {
|
|
await withTempHome(async () => {
|
|
const sourceConfig: OpenClawConfig = {
|
|
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: [],
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const runtimeConfig: OpenClawConfig = {
|
|
models: {
|
|
providers: {
|
|
openai: {
|
|
baseUrl: "https://api.openai.com/v1",
|
|
apiKey: "sk-runtime-resolved", // 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.openai?.apiKey).toBe("OPENAI_API_KEY"); // pragma: allowlist secret
|
|
} finally {
|
|
clearRuntimeConfigSnapshot();
|
|
clearConfigCache();
|
|
}
|
|
});
|
|
});
|
|
|
|
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: OpenClawConfig = {
|
|
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: [],
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const runtimeConfig: OpenClawConfig = {
|
|
models: {
|
|
providers: {
|
|
openai: {
|
|
baseUrl: "https://api.openai.com/v1",
|
|
apiKey: "sk-runtime-resolved", // pragma: allowlist secret
|
|
api: "openai-completions" as const,
|
|
models: [],
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const clonedRuntimeConfig: OpenClawConfig = {
|
|
...runtimeConfig,
|
|
agents: {
|
|
defaults: {
|
|
imageModel: "openai/gpt-image-1",
|
|
},
|
|
},
|
|
};
|
|
|
|
try {
|
|
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
|
|
await ensureOpenClawModelsJson(clonedRuntimeConfig);
|
|
|
|
const parsed = await readGeneratedModelsJson<{
|
|
providers: Record<string, { apiKey?: string }>;
|
|
}>();
|
|
expect(parsed.providers.openai?.apiKey).toBe("OPENAI_API_KEY"); // pragma: allowlist secret
|
|
} finally {
|
|
clearRuntimeConfigSnapshot();
|
|
clearConfigCache();
|
|
}
|
|
});
|
|
});
|
|
|
|
it("uses header markers from runtime source snapshot instead of resolved runtime values", async () => {
|
|
await withTempHome(async () => {
|
|
const sourceConfig: OpenClawConfig = {
|
|
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: [],
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const runtimeConfig: OpenClawConfig = {
|
|
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: [],
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
try {
|
|
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
|
|
await ensureOpenClawModelsJson(loadConfig());
|
|
|
|
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);
|
|
} finally {
|
|
clearRuntimeConfigSnapshot();
|
|
clearConfigCache();
|
|
}
|
|
});
|
|
});
|
|
|
|
it("keeps source markers when runtime projection is skipped for incompatible top-level shape", async () => {
|
|
await withTempHome(async () => {
|
|
const sourceConfig: OpenClawConfig = {
|
|
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: [],
|
|
},
|
|
},
|
|
},
|
|
gateway: {
|
|
auth: {
|
|
mode: "token",
|
|
},
|
|
},
|
|
};
|
|
const runtimeConfig: OpenClawConfig = {
|
|
models: {
|
|
providers: {
|
|
openai: {
|
|
baseUrl: "https://api.openai.com/v1",
|
|
apiKey: "sk-runtime-resolved", // pragma: allowlist secret
|
|
api: "openai-completions" as const,
|
|
models: [],
|
|
},
|
|
},
|
|
},
|
|
gateway: {
|
|
auth: {
|
|
mode: "token",
|
|
},
|
|
},
|
|
};
|
|
const incompatibleCandidate: OpenClawConfig = {
|
|
models: {
|
|
providers: {
|
|
openai: {
|
|
baseUrl: "https://api.openai.com/v1",
|
|
apiKey: "sk-runtime-resolved", // pragma: allowlist secret
|
|
api: "openai-completions" as const,
|
|
models: [],
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
try {
|
|
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
|
|
await ensureOpenClawModelsJson(incompatibleCandidate);
|
|
|
|
const parsed = await readGeneratedModelsJson<{
|
|
providers: Record<string, { apiKey?: string }>;
|
|
}>();
|
|
expect(parsed.providers.openai?.apiKey).toBe("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: OpenClawConfig = {
|
|
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: [],
|
|
},
|
|
},
|
|
},
|
|
gateway: {
|
|
auth: {
|
|
mode: "token",
|
|
},
|
|
},
|
|
};
|
|
const runtimeConfig: OpenClawConfig = {
|
|
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: [],
|
|
},
|
|
},
|
|
},
|
|
gateway: {
|
|
auth: {
|
|
mode: "token",
|
|
},
|
|
},
|
|
};
|
|
const incompatibleCandidate: OpenClawConfig = {
|
|
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: [],
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
try {
|
|
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
|
|
await ensureOpenClawModelsJson(incompatibleCandidate);
|
|
|
|
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);
|
|
} finally {
|
|
clearRuntimeConfigSnapshot();
|
|
clearConfigCache();
|
|
}
|
|
});
|
|
});
|
|
});
|