mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-14 08:00:28 +00:00
fix(plugins): guard model suppression metadata
This commit is contained in:
@@ -23,6 +23,38 @@ function createMetadataSnapshot(plugins: Record<string, unknown>[]) {
|
||||
};
|
||||
}
|
||||
|
||||
function createRawMetadataSnapshot(plugins: Record<string, unknown>[]) {
|
||||
return {
|
||||
index: { plugins: [] },
|
||||
diagnostics: [],
|
||||
plugins,
|
||||
};
|
||||
}
|
||||
|
||||
function poisonedAvailabilityPlugin(): Record<string, unknown> {
|
||||
return Object.defineProperty({ id: "poisoned-availability" }, "origin", {
|
||||
get() {
|
||||
throw new Error("model suppression availability exploded");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function poisonedModelCatalogPlugin(): Record<string, unknown> {
|
||||
return Object.defineProperty(
|
||||
{
|
||||
id: "poisoned-model-catalog",
|
||||
origin: "bundled",
|
||||
providers: ["poisoned-model-catalog"],
|
||||
},
|
||||
"modelCatalog",
|
||||
{
|
||||
get() {
|
||||
throw new Error("model suppression catalog exploded");
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
describe("manifest model suppression", () => {
|
||||
beforeEach(() => {
|
||||
mocks.loadPluginMetadataSnapshot.mockReset();
|
||||
@@ -106,6 +138,63 @@ describe("manifest model suppression", () => {
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("skips unreadable manifest model suppression plugin metadata", () => {
|
||||
mocks.loadPluginMetadataSnapshot.mockReturnValue(
|
||||
createRawMetadataSnapshot([
|
||||
{
|
||||
id: "openai",
|
||||
origin: "bundled",
|
||||
providers: ["openai"],
|
||||
modelCatalog: {
|
||||
aliases: {
|
||||
"azure-openai-responses": {
|
||||
provider: "openai",
|
||||
},
|
||||
},
|
||||
suppressions: [
|
||||
{
|
||||
provider: "azure-openai-responses",
|
||||
model: "gpt-5.3-codex-spark",
|
||||
reason: "Use openai/gpt-5.5.",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
poisonedAvailabilityPlugin(),
|
||||
poisonedModelCatalogPlugin(),
|
||||
{
|
||||
id: "qwen",
|
||||
origin: "bundled",
|
||||
providers: ["qwen"],
|
||||
modelCatalog: {
|
||||
suppressions: [
|
||||
{
|
||||
provider: "qwen",
|
||||
model: "qwen3.6-plus",
|
||||
reason: "Use qwen/qwen3.5-plus.",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
expect(
|
||||
resolveManifestBuiltInModelSuppression({
|
||||
provider: "azure-openai-responses",
|
||||
id: "gpt-5.3-codex-spark",
|
||||
env: process.env,
|
||||
})?.suppress,
|
||||
).toBe(true);
|
||||
expect(
|
||||
resolveManifestBuiltInModelSuppression({
|
||||
provider: "qwen",
|
||||
id: "qwen3.6-plus",
|
||||
env: process.env,
|
||||
})?.suppress,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("reads planned manifest suppressions fresh per lookup", () => {
|
||||
const config = { plugins: { entries: { openai: { enabled: true } } } };
|
||||
|
||||
|
||||
@@ -10,6 +10,36 @@ import {
|
||||
loadManifestMetadataSnapshot,
|
||||
} from "./manifest-contract-eligibility.js";
|
||||
|
||||
type ManifestModelCatalogSuppressionPlugin = Parameters<
|
||||
typeof planManifestModelCatalogSuppressions
|
||||
>[0]["registry"]["plugins"][number];
|
||||
type ManifestMetadataSnapshot = ReturnType<typeof loadManifestMetadataSnapshot>;
|
||||
|
||||
function readAvailableManifestModelCatalogSuppressionPlugin(params: {
|
||||
snapshot: ManifestMetadataSnapshot;
|
||||
plugin: ManifestMetadataSnapshot["plugins"][number];
|
||||
config?: OpenClawConfig;
|
||||
}): ManifestModelCatalogSuppressionPlugin | undefined {
|
||||
try {
|
||||
if (
|
||||
!isManifestPluginAvailableForControlPlane({
|
||||
snapshot: params.snapshot,
|
||||
plugin: params.plugin,
|
||||
config: params.config,
|
||||
})
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
id: params.plugin.id,
|
||||
providers: params.plugin.providers,
|
||||
modelCatalog: params.plugin.modelCatalog,
|
||||
};
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function listManifestModelCatalogSuppressions(params: {
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
@@ -20,15 +50,17 @@ function listManifestModelCatalogSuppressions(params: {
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
const plugins = snapshot.plugins.flatMap((plugin) => {
|
||||
const readable = readAvailableManifestModelCatalogSuppressionPlugin({
|
||||
snapshot,
|
||||
plugin,
|
||||
config: params.config,
|
||||
});
|
||||
return readable ? [readable] : [];
|
||||
});
|
||||
const registry = {
|
||||
diagnostics: snapshot.diagnostics,
|
||||
plugins: snapshot.plugins.filter((plugin) =>
|
||||
isManifestPluginAvailableForControlPlane({
|
||||
snapshot,
|
||||
plugin,
|
||||
config: params.config,
|
||||
}),
|
||||
),
|
||||
plugins,
|
||||
};
|
||||
const planned = planManifestModelCatalogSuppressions({ registry });
|
||||
return planned.suppressions;
|
||||
|
||||
Reference in New Issue
Block a user