

















@@ -2079,6 +2079,53 @@ describe("syncPluginsForUpdateChannel", () => {
20792079});
20802080});
208120812082+it("marks official externalized bundled npm installs as trusted", async () => {
2083+resolveBundledPluginSourcesMock.mockReturnValue(new Map());
2084+installPluginFromNpmSpecMock.mockResolvedValue(
2085+createSuccessfulNpmUpdateResult({
2086+pluginId: "voice-call",
2087+targetDir: "/tmp/openclaw-plugins/voice-call",
2088+version: "0.0.2-beta.1",
2089+}),
2090+);
2091+2092+await syncPluginsForUpdateChannel({
2093+channel: "stable",
2094+externalizedBundledPluginBridges: [
2095+{
2096+bundledPluginId: "voice-call",
2097+npmSpec: "@openclaw/voice-call",
2098+channelIds: ["voice-call"],
2099+},
2100+],
2101+config: {
2102+channels: {
2103+"voice-call": {
2104+enabled: true,
2105+},
2106+},
2107+plugins: {
2108+load: { paths: [appBundledPluginRoot("voice-call")] },
2109+installs: {
2110+"voice-call": {
2111+source: "path",
2112+sourcePath: appBundledPluginRoot("voice-call"),
2113+installPath: appBundledPluginRoot("voice-call"),
2114+},
2115+},
2116+},
2117+},
2118+});
2119+2120+expect(installPluginFromNpmSpecMock).toHaveBeenCalledWith(
2121+expect.objectContaining({
2122+spec: "@openclaw/voice-call",
2123+expectedPluginId: "voice-call",
2124+trustedSourceLinkedOfficialInstall: true,
2125+}),
2126+);
2127+});
2128+20822129it("installs a ClawHub-preferred externalized bundled plugin", async () => {
20832130resolveBundledPluginSourcesMock.mockReturnValue(new Map());
20842131installPluginFromClawHubMock.mockResolvedValue(
@@ -2229,6 +2276,60 @@ describe("syncPluginsForUpdateChannel", () => {
22292276});
22302277});
223122782279+it("marks official externalized ClawHub-to-npm fallbacks as trusted", async () => {
2280+resolveBundledPluginSourcesMock.mockReturnValue(new Map());
2281+installPluginFromClawHubMock.mockResolvedValue({
2282+ok: false,
2283+code: "package_not_found",
2284+error: "Package not found on ClawHub.",
2285+});
2286+installPluginFromNpmSpecMock.mockResolvedValue(
2287+createSuccessfulNpmUpdateResult({
2288+pluginId: "voice-call",
2289+targetDir: "/tmp/openclaw-plugins/voice-call",
2290+version: "0.0.2-beta.1",
2291+}),
2292+);
2293+2294+await syncPluginsForUpdateChannel({
2295+channel: "stable",
2296+externalizedBundledPluginBridges: [
2297+{
2298+bundledPluginId: "voice-call",
2299+preferredSource: "clawhub",
2300+clawhubSpec: "clawhub:@openclaw/voice-call",
2301+npmSpec: "@openclaw/voice-call",
2302+channelIds: ["voice-call"],
2303+},
2304+],
2305+config: {
2306+channels: {
2307+"voice-call": {
2308+enabled: true,
2309+},
2310+},
2311+plugins: {
2312+load: { paths: [appBundledPluginRoot("voice-call")] },
2313+installs: {
2314+"voice-call": {
2315+source: "path",
2316+sourcePath: appBundledPluginRoot("voice-call"),
2317+installPath: appBundledPluginRoot("voice-call"),
2318+},
2319+},
2320+},
2321+},
2322+});
2323+2324+expect(installPluginFromNpmSpecMock).toHaveBeenCalledWith(
2325+expect.objectContaining({
2326+spec: "@openclaw/voice-call",
2327+expectedPluginId: "voice-call",
2328+trustedSourceLinkedOfficialInstall: true,
2329+}),
2330+);
2331+});
2332+22322333it("fails closed without npm fallback when ClawHub returns integrity drift", async () => {
22332334resolveBundledPluginSourcesMock.mockReturnValue(new Map());
22342335installPluginFromClawHubMock.mockResolvedValue({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。