@@ -389,7 +389,7 @@ describe("resolvePluginTools optional tools", () => {
389389 } ) ;
390390
391391 beforeEach ( ( ) => {
392- loadOpenClawPluginsMock . mockClear ( ) ;
392+ loadOpenClawPluginsMock . mockReset ( ) ;
393393 resolveRuntimePluginRegistryMock . mockReset ( ) ;
394394 resolveRuntimePluginRegistryMock . mockImplementation ( ( params ) =>
395395 loadOpenClawPluginsMock ( params ) ,
@@ -1185,6 +1185,217 @@ describe("resolvePluginTools optional tools", () => {
11851185 expect ( loadOpenClawPluginsMock ) . not . toHaveBeenCalled ( ) ;
11861186 } ) ;
11871187
1188+ it ( "does not let disabled bundled tool owners poison explicit runtime allowlists" , ( ) => {
1189+ const config = {
1190+ plugins : {
1191+ enabled : true ,
1192+ allow : [ "memory-core" , "memory-lancedb" ] ,
1193+ load : { paths : [ ] } ,
1194+ entries : {
1195+ "memory-core" : { enabled : true } ,
1196+ "memory-lancedb" : { enabled : false } ,
1197+ } ,
1198+ slots : { memory : "memory-core" } ,
1199+ } ,
1200+ } ;
1201+ installToolManifestSnapshots ( {
1202+ config,
1203+ plugins : [
1204+ {
1205+ id : "memory-core" ,
1206+ origin : "bundled" ,
1207+ enabledByDefault : false ,
1208+ channels : [ ] ,
1209+ providers : [ ] ,
1210+ contracts : {
1211+ tools : [ "memory_get" , "memory_search" ] ,
1212+ } ,
1213+ } ,
1214+ {
1215+ id : "memory-lancedb" ,
1216+ origin : "bundled" ,
1217+ enabledByDefault : false ,
1218+ channels : [ ] ,
1219+ providers : [ ] ,
1220+ contracts : {
1221+ tools : [ "memory_recall" ] ,
1222+ } ,
1223+ } ,
1224+ ] ,
1225+ } ) ;
1226+ const memorySearchFactory = vi . fn ( ( ) => [ makeTool ( "memory_search" ) , makeTool ( "memory_get" ) ] ) ;
1227+ const activeRegistry = {
1228+ plugins : [
1229+ { id : "memory-core" , status : "loaded" } ,
1230+ { id : "memory-lancedb" , status : "disabled" } ,
1231+ ] ,
1232+ tools : [
1233+ {
1234+ pluginId : "memory-core" ,
1235+ optional : false ,
1236+ source : "/tmp/memory-core.js" ,
1237+ names : [ "memory_search" , "memory_get" ] ,
1238+ declaredNames : [ "memory_search" , "memory_get" ] ,
1239+ factory : memorySearchFactory ,
1240+ } ,
1241+ ] ,
1242+ diagnostics : [ ] ,
1243+ } ;
1244+ setActivePluginRegistry ( activeRegistry as never , "gateway-startup" , "gateway-bindable" , "/tmp" ) ;
1245+ resolveRuntimePluginRegistryMock . mockReturnValue ( undefined ) ;
1246+
1247+ const tools = resolvePluginTools (
1248+ createResolveToolsParams ( {
1249+ context : { ...createContext ( ) , config } ,
1250+ toolAllowlist : [ "memory_recall" , "memory_search" , "memory_get" ] ,
1251+ allowGatewaySubagentBinding : true ,
1252+ } ) ,
1253+ ) ;
1254+
1255+ expectResolvedToolNames ( tools , [ "memory_search" , "memory_get" ] ) ;
1256+ expect ( memorySearchFactory ) . toHaveBeenCalledTimes ( 1 ) ;
1257+ expect ( resolveRuntimePluginRegistryMock ) . not . toHaveBeenCalled ( ) ;
1258+ expect ( loadOpenClawPluginsMock ) . not . toHaveBeenCalled ( ) ;
1259+ } ) ;
1260+
1261+ it ( "falls back from a loaded channel registry without matching tool entries" , ( ) => {
1262+ const config = {
1263+ plugins : {
1264+ enabled : true ,
1265+ allow : [ "memory-core" ] ,
1266+ load : { paths : [ ] } ,
1267+ entries : {
1268+ "memory-core" : { enabled : true } ,
1269+ } ,
1270+ slots : { memory : "memory-core" } ,
1271+ } ,
1272+ } ;
1273+ installToolManifestSnapshot ( {
1274+ config,
1275+ plugin : {
1276+ id : "memory-core" ,
1277+ origin : "bundled" ,
1278+ enabledByDefault : false ,
1279+ channels : [ ] ,
1280+ providers : [ ] ,
1281+ contracts : {
1282+ tools : [ "memory_get" , "memory_search" ] ,
1283+ } ,
1284+ } ,
1285+ } ) ;
1286+ const memorySearchFactory = vi . fn ( ( ) => [ makeTool ( "memory_search" ) , makeTool ( "memory_get" ) ] ) ;
1287+ const activeRegistry = {
1288+ plugins : [ { id : "memory-core" , status : "loaded" } ] ,
1289+ tools : [
1290+ {
1291+ pluginId : "memory-core" ,
1292+ optional : false ,
1293+ source : "/tmp/memory-core.js" ,
1294+ names : [ "memory_search" , "memory_get" ] ,
1295+ declaredNames : [ "memory_search" , "memory_get" ] ,
1296+ factory : memorySearchFactory ,
1297+ } ,
1298+ ] ,
1299+ diagnostics : [ ] ,
1300+ } ;
1301+ setActivePluginRegistry ( activeRegistry as never , "gateway-startup" , "gateway-bindable" , "/tmp" ) ;
1302+ pinActivePluginChannelRegistry ( {
1303+ plugins : [ { id : "memory-core" , status : "loaded" } ] ,
1304+ tools : [ ] ,
1305+ diagnostics : [ ] ,
1306+ } as never ) ;
1307+ resolveRuntimePluginRegistryMock . mockReturnValue ( undefined ) ;
1308+
1309+ const tools = resolvePluginTools (
1310+ createResolveToolsParams ( {
1311+ context : { ...createContext ( ) , config } ,
1312+ toolAllowlist : [ "memory_search" , "memory_get" ] ,
1313+ allowGatewaySubagentBinding : true ,
1314+ } ) ,
1315+ ) ;
1316+
1317+ expectResolvedToolNames ( tools , [ "memory_search" , "memory_get" ] ) ;
1318+ expect ( memorySearchFactory ) . toHaveBeenCalledTimes ( 1 ) ;
1319+ expect ( loadOpenClawPluginsMock ) . not . toHaveBeenCalled ( ) ;
1320+ } ) ;
1321+
1322+ it ( "loads a standalone registry when cached runtime registries lack matching tool entries" , ( ) => {
1323+ const config = {
1324+ plugins : {
1325+ enabled : true ,
1326+ allow : [ "memory-core" ] ,
1327+ load : { paths : [ ] } ,
1328+ entries : {
1329+ "memory-core" : { enabled : true } ,
1330+ } ,
1331+ slots : { memory : "memory-core" } ,
1332+ } ,
1333+ } ;
1334+ installToolManifestSnapshot ( {
1335+ config,
1336+ plugin : {
1337+ id : "memory-core" ,
1338+ origin : "bundled" ,
1339+ enabledByDefault : false ,
1340+ channels : [ ] ,
1341+ providers : [ ] ,
1342+ contracts : {
1343+ tools : [ "memory_get" , "memory_search" ] ,
1344+ } ,
1345+ } ,
1346+ } ) ;
1347+ const memorySearchFactory = vi . fn ( ( ) => [ makeTool ( "memory_search" ) , makeTool ( "memory_get" ) ] ) ;
1348+ const loadedRegistry = {
1349+ plugins : [ { id : "memory-core" , status : "loaded" } ] ,
1350+ tools : [
1351+ {
1352+ pluginId : "memory-core" ,
1353+ optional : false ,
1354+ source : "/tmp/memory-core.js" ,
1355+ names : [ "memory_search" , "memory_get" ] ,
1356+ declaredNames : [ "memory_search" , "memory_get" ] ,
1357+ factory : memorySearchFactory ,
1358+ } ,
1359+ ] ,
1360+ diagnostics : [ ] ,
1361+ } ;
1362+ setActivePluginRegistry (
1363+ {
1364+ plugins : [ { id : "memory-core" , status : "loaded" } ] ,
1365+ tools : [ ] ,
1366+ diagnostics : [ ] ,
1367+ } as never ,
1368+ "gateway-startup" ,
1369+ "gateway-bindable" ,
1370+ "/tmp" ,
1371+ ) ;
1372+ pinActivePluginChannelRegistry ( {
1373+ plugins : [ { id : "memory-core" , status : "loaded" } ] ,
1374+ tools : [ ] ,
1375+ diagnostics : [ ] ,
1376+ } as never ) ;
1377+ resolveRuntimePluginRegistryMock . mockReturnValue ( undefined ) ;
1378+ loadOpenClawPluginsMock . mockReturnValue ( loadedRegistry ) ;
1379+
1380+ const tools = resolvePluginTools (
1381+ createResolveToolsParams ( {
1382+ context : { ...createContext ( ) , config } ,
1383+ toolAllowlist : [ "memory_search" , "memory_get" ] ,
1384+ allowGatewaySubagentBinding : true ,
1385+ } ) ,
1386+ ) ;
1387+
1388+ expectResolvedToolNames ( tools , [ "memory_search" , "memory_get" ] ) ;
1389+ expect ( memorySearchFactory ) . toHaveBeenCalledTimes ( 1 ) ;
1390+ expect ( loadOpenClawPluginsMock ) . toHaveBeenCalledWith (
1391+ expect . objectContaining ( {
1392+ activate : false ,
1393+ onlyPluginIds : [ "memory-core" ] ,
1394+ toolDiscovery : true ,
1395+ } ) ,
1396+ ) ;
1397+ } ) ;
1398+
11881399 it ( "adds enabled non-startup tool plugins to the active tool runtime scope" , ( ) => {
11891400 const activeRegistry = createOptionalDemoActiveRegistry ( ) ;
11901401 setActivePluginRegistry ( activeRegistry as never , "gateway-startup" , "gateway-bindable" , "/tmp" ) ;
@@ -1207,7 +1418,18 @@ describe("resolvePluginTools optional tools", () => {
12071418 allowGatewaySubagentBinding : true ,
12081419 } ) ;
12091420
1210- expect ( resolveRuntimePluginRegistryMock ) . not . toHaveBeenCalled ( ) ;
1421+ expect ( resolveRuntimePluginRegistryMock ) . toHaveBeenCalledWith (
1422+ expect . objectContaining ( {
1423+ onlyPluginIds : expect . arrayContaining ( [ "tavily" ] ) ,
1424+ toolDiscovery : true ,
1425+ } ) ,
1426+ ) ;
1427+ expect ( loadOpenClawPluginsMock ) . toHaveBeenCalledWith (
1428+ expect . objectContaining ( {
1429+ onlyPluginIds : expect . arrayContaining ( [ "tavily" ] ) ,
1430+ toolDiscovery : true ,
1431+ } ) ,
1432+ ) ;
12111433 } ) ;
12121434
12131435 it ( "reuses the pinned gateway channel registry after provider runtime loads replace active registry" , ( ) => {
0 commit comments