From 726c60521807e1f722d2c388fd34ff89e7300dff Mon Sep 17 00:00:00 2001 From: Luke Policinski Date: Fri, 2 Oct 2026 19:00:15 -0400 Subject: [PATCH] bug: expand {runtime} in plugin install paths sent to nodes --- src/game-plugins/game-plugins.service.spec.ts | 49 +++++++++++++++++++ src/game-plugins/game-plugins.service.ts | 3 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/game-plugins/game-plugins.service.spec.ts b/src/game-plugins/game-plugins.service.spec.ts index 833325d0..a4135f00 100644 --- a/src/game-plugins/game-plugins.service.spec.ts +++ b/src/game-plugins/game-plugins.service.spec.ts @@ -490,3 +490,52 @@ describe("GamePluginsService.setAutoUpdate", () => { ).toBe(true); }); }); + +describe("GamePluginsService.desiredForNode", () => { + let postgres: { query: jest.Mock }; + let service: GamePluginsService; + + beforeEach(() => { + postgres = { + query: jest.fn(async (sql: string): Promise> => { + if (sql.includes("FROM public.game_server_nodes")) { + return [{ pin_plugin_runtime: null }]; + } + if (sql.includes("FROM public.game_plugin_installs")) { + return [{ plugin_slug: "arenas", version: null }]; + } + if (sql.includes("FROM public.game_plugin_versions")) { + return [ + { + version: "1.0.0", + url: "https://example.com/K4-Arenas-v1.0.0.zip", + sha256: "abc", + layout: "plugin", + install_path: "addons/{runtime}/plugins", + }, + ]; + } + return []; + }), + }; + + service = new GamePluginsService( + { warn: jest.fn(), log: jest.fn() } as any, + {} as any, + postgres as any, + { + resolvePluginRuntime: jest.fn(async (): Promise => "swiftlys2"), + } as any, + {} as any, + { add: jest.fn(), getJob: jest.fn() } as any, + ); + }); + + // The node extracts to installPath verbatim, so an unexpanded placeholder + // lands the plugin in a literal addons/{runtime}/ that no runtime loads. + it("expands {runtime} in the install path for the node's runtime", async () => { + const { plugins } = await service.desiredForNode("node-1"); + + expect(plugins[0].installPath).toEqual("addons/swiftlys2/plugins"); + }); +}); diff --git a/src/game-plugins/game-plugins.service.ts b/src/game-plugins/game-plugins.service.ts index d1355e0b..079e30dc 100644 --- a/src/game-plugins/game-plugins.service.ts +++ b/src/game-plugins/game-plugins.service.ts @@ -608,7 +608,8 @@ export class GamePluginsService { url: resolved.url, sha256: resolved.sha256, layout: resolved.layout, - installPath: resolved.install_path, + installPath: + resolved.install_path?.replaceAll("{runtime}", runtime) ?? null, }); } catch (error) { // A plugin with no build for this runtime is not an error the node can