From 24adf2c8e64d85d71902995140f12a2c5422784c Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 28 Apr 2026 21:23:07 -0700 Subject: [PATCH] fix(plugins): reject malformed channel registrations --- .../lib/kitchen-sink-plugin/assertions.mjs | 1 + src/plugins/channel-validation.test.ts | 22 +++++++++++++++++++ src/plugins/channel-validation.ts | 13 +++++++++++ 3 files changed, 36 insertions(+) diff --git a/scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs b/scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs index 336d7257f35..7cdfea2cb7b 100644 --- a/scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs +++ b/scripts/e2e/lib/kitchen-sink-plugin/assertions.mjs @@ -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", diff --git a/src/plugins/channel-validation.test.ts b/src/plugins/channel-validation.test.ts index d238cdce54e..cc9e6f32120 100644 --- a/src/plugins/channel-validation.test.ts +++ b/src/plugins/channel-validation.test.ts @@ -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', + }), + ]); + }); }); diff --git a/src/plugins/channel-validation.ts b/src/plugins/channel-validation.ts index 678421d4c07..a320f253c35 100644 --- a/src/plugins/channel-validation.ts +++ b/src/plugins/channel-validation.ts @@ -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 | undefined; const rawMetaId = normalizeOptionalString(rawMeta?.id);