fix(plugins): preserve bundled allowlist edges

This commit is contained in:
Peter Steinberger
2026-05-04 23:35:20 +01:00
parent fdbfabf9f9
commit 40e0844133
5 changed files with 65 additions and 6 deletions

View File

@@ -1,4 +1,4 @@
02987f4cecb64a98170b61c925fd7b16a22b276abfb261f9281b42f613ded923 config-baseline.json
de5a6f65ef09dc23453a2e12512e41c133c941519e0ebef7f2946e4a24265d17 config-baseline.core.json
2566cb33c48abf3884d44cc605e3fe23ee3dc3e998c29fe86dfe773faf58cb52 config-baseline.json
eab2f8a9af31910e26874209330d10ca46afd910cba88beda8a48fe6b9831159 config-baseline.core.json
cd7c0c7fb1435bc7e59099e9ac334462d5ad444016e9ab4512aae63a238f78dc config-baseline.channel.json
9832b30a696930a3da7efccf38073137571e1b66cae84e54d747b733fdafcc54 config-baseline.plugin.json

View File

@@ -132,6 +132,27 @@ describe("implicit provider plugin allowlist compatibility", () => {
).toEqual(["openrouter"]);
});
it("does not re-enable plugins when allowlist mode rejects every compat plugin", () => {
const config = withBundledPluginEnablementCompat({
config: {
plugins: {
enabled: false,
allow: ["openrouter"],
bundledDiscovery: "allowlist",
},
},
pluginIds: ["kilocode", "moonshot"],
});
expect(config).toEqual({
plugins: {
enabled: false,
allow: ["openrouter"],
bundledDiscovery: "allowlist",
},
});
});
it("still honors explicit plugin denies over compat allowlist injection", () => {
const config = withBundledPluginEnablementCompat({
config: withBundledPluginAllowlistCompat({

View File

@@ -46,14 +46,16 @@ export function withBundledPluginEnablementCompat(params: {
const allow = params.config?.plugins?.allow;
const allowSet =
!useCompatDiscovery && Array.isArray(allow) && allow.length > 0 ? new Set(allow) : undefined;
let hasEligiblePlugin = false;
let changed = false;
const nextEntries: Record<string, PluginEntryConfig> = { ...existingEntries };
for (const pluginId of params.pluginIds) {
if (existingEntries[pluginId] !== undefined) {
if (allowSet && !allowSet.has(pluginId)) {
continue;
}
if (allowSet && !allowSet.has(pluginId)) {
hasEligiblePlugin = true;
if (existingEntries[pluginId] !== undefined) {
continue;
}
nextEntries[pluginId] = { enabled: true };
@@ -61,7 +63,7 @@ export function withBundledPluginEnablementCompat(params: {
}
if (!changed) {
if (!forcePluginsEnabled) {
if (!forcePluginsEnabled || !hasEligiblePlugin) {
return params.config;
}
}

View File

@@ -152,4 +152,37 @@ describe("web provider public artifact manifest fallback", () => {
pluginId: "fallback-fetch",
});
});
it("matches bundled web-search candidates through provider alias allowlist entries", () => {
mocks.resolveBundledExplicitWebSearchProvidersFromPublicArtifacts.mockReturnValueOnce(null);
mocks.loadPluginMetadataSnapshot.mockReturnValueOnce({
diagnostics: [],
plugins: [
{
id: "google",
origin: "bundled",
rootDir: "/tmp/google",
contracts: { webSearchProviders: ["gemini"] },
},
],
});
mocks.loadBundledWebSearchProviderEntriesFromDir.mockReturnValueOnce([
{ id: "gemini", pluginId: "google" },
]);
const providers = resolveBundledWebSearchProvidersFromPublicArtifacts({
config: {
plugins: {
allow: ["google-gemini-cli"],
bundledDiscovery: "allowlist",
},
},
});
expect(providers).toEqual([{ id: "gemini", pluginId: "google" }]);
expect(mocks.loadBundledWebSearchProviderEntriesFromDir).toHaveBeenCalledWith({
dirName: "google",
pluginId: "google",
});
});
});

View File

@@ -1,4 +1,5 @@
import path from "node:path";
import { normalizePluginId } from "./config-state.js";
import type { PluginLoadOptions } from "./loader.js";
import { loadManifestMetadataSnapshot } from "./manifest-contract-eligibility.js";
import type { PluginManifestRecord } from "./manifest-registry.js";
@@ -38,7 +39,9 @@ function filterAllowlistedBundledPluginIds(
) {
return [...pluginIds];
}
const allowedPluginIds = new Set(allow.map((pluginId) => pluginId.trim()).filter(Boolean));
const allowedPluginIds = new Set(
allow.map((pluginId) => normalizePluginId(pluginId)).filter(Boolean),
);
return pluginIds.filter((pluginId) => allowedPluginIds.has(pluginId));
}