fix(plugins): reject malformed channel registrations

This commit is contained in:
Vincent Koc
2026-04-28 21:23:07 -07:00
parent 8d58ad4c15
commit 24adf2c8e6
3 changed files with 36 additions and 0 deletions

View File

@@ -241,6 +241,7 @@ function assertInstalled() {
const expectedErrorMessages = new Set([
"only bundled plugins can register agent tool result middleware",
'channel "kitchen-sink-channel-probe" registration missing required config helpers',
"cli registration missing explicit commands metadata",
"only bundled plugins can register Codex app-server extension factories",
"http route registration missing or invalid auth: /kitchen-sink/http-route",

View File

@@ -114,4 +114,26 @@ describe("normalizeRegisteredChannelPlugin", () => {
'channel "demo" meta.id mismatch ("other-demo"); using registered channel id',
]);
});
it("rejects runtime channel registrations without required config helpers", () => {
const { diagnostics, pushDiagnostic } = collectDiagnostics();
const normalized = normalizeRegisteredChannelPlugin({
pluginId: "demo-plugin",
source: "/tmp/demo/index.ts",
plugin: createChannelPlugin({
id: "broken-channel",
config: undefined as never,
}),
pushDiagnostic,
});
expect(normalized).toBeNull();
expect(diagnostics).toEqual([
expect.objectContaining({
level: "error",
message: 'channel "broken-channel" registration missing required config helpers',
}),
]);
});
});

View File

@@ -50,6 +50,19 @@ export function normalizeRegisteredChannelPlugin(params: {
});
return null;
}
if (
typeof params.plugin.config?.listAccountIds !== "function" ||
typeof params.plugin.config?.resolveAccount !== "function"
) {
pushPluginValidationDiagnostic({
level: "error",
pluginId: params.pluginId,
source: params.source,
message: `channel "${id}" registration missing required config helpers`,
pushDiagnostic: params.pushDiagnostic,
});
return null;
}
const rawMeta = params.plugin.meta as Partial<ChannelMeta> | undefined;
const rawMetaId = normalizeOptionalString(rawMeta?.id);