mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-08 01:57:31 +01:00
Fix plugin key route resolution
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
a8cb1427d1
commit
380438a8c1
2 files changed
+46
-20
No files matched your search
@@ -224,6 +224,46 @@ describe.sequential("plugin install and upgrade authz", () => {
|
||||
expect(mockLifecycle.disable).not.toHaveBeenCalled();
|
||||
}, 20_000);
|
||||
|
||||
it("resolves plugin keys without probing the UUID id column for core plugin actions", async () => {
|
||||
const pluginKey = "paperclipqa.hello-plugin";
|
||||
const plugin = {
|
||||
id: pluginId,
|
||||
pluginKey,
|
||||
version: "1.0.0",
|
||||
status: "ready",
|
||||
};
|
||||
mockRegistry.getById.mockImplementation(() => {
|
||||
throw new Error("getById should not be called for plugin keys");
|
||||
});
|
||||
mockRegistry.getByKey.mockResolvedValue(plugin);
|
||||
mockLifecycle.unload.mockResolvedValue(plugin);
|
||||
mockLifecycle.enable.mockResolvedValue(plugin);
|
||||
mockLifecycle.disable.mockResolvedValue(plugin);
|
||||
|
||||
const { app } = await createApp({
|
||||
type: "board",
|
||||
userId: "admin-1",
|
||||
source: "session",
|
||||
isInstanceAdmin: true,
|
||||
companyIds: [companyA],
|
||||
});
|
||||
|
||||
const inspectRes = await request(app).get(`/api/plugins/${pluginKey}`);
|
||||
const disableRes = await request(app).post(`/api/plugins/${pluginKey}/disable`).send({});
|
||||
const enableRes = await request(app).post(`/api/plugins/${pluginKey}/enable`).send({});
|
||||
const uninstallRes = await request(app).delete(`/api/plugins/${pluginKey}?purge=true`);
|
||||
|
||||
expect(inspectRes.status).toBe(200);
|
||||
expect(disableRes.status).toBe(200);
|
||||
expect(enableRes.status).toBe(200);
|
||||
expect(uninstallRes.status).toBe(200);
|
||||
expect(mockRegistry.getById).not.toHaveBeenCalled();
|
||||
expect(mockRegistry.getByKey).toHaveBeenCalledWith(pluginKey);
|
||||
expect(mockLifecycle.disable).toHaveBeenCalledWith(pluginId, undefined);
|
||||
expect(mockLifecycle.enable).toHaveBeenCalledWith(pluginId);
|
||||
expect(mockLifecycle.unload).toHaveBeenCalledWith(pluginId, true);
|
||||
}, 20_000);
|
||||
|
||||
it("rejects plugin config saves that contain secret refs even for instance admins", async () => {
|
||||
readyPlugin();
|
||||
|
||||
|
||||
@@ -199,9 +199,9 @@ function listBundledPluginExamples(): AvailablePluginExample[] {
|
||||
*
|
||||
* Lookup order:
|
||||
* - UUID-like IDs: getById first, then getByKey.
|
||||
* - Scoped package keys (e.g. "@scope/name"): getByKey only, never getById.
|
||||
* - Other non-UUID IDs: try getById first (test/memory registries may allow this),
|
||||
* then fallback to getByKey. Any UUID parse error from getById is ignored.
|
||||
* - All non-UUID values: getByKey only, never getById. The persisted plugin
|
||||
* ID column is a PostgreSQL UUID, so probing it with keys such as
|
||||
* "acme.plugin" raises a database cast error before a key lookup can happen.
|
||||
*
|
||||
* @param registry - The plugin registry service instance
|
||||
* @param pluginId - Either a database UUID or plugin key (manifest id)
|
||||
@@ -212,27 +212,13 @@ async function resolvePlugin(
|
||||
pluginId: string,
|
||||
) {
|
||||
const isUuid = UUID_REGEX.test(pluginId);
|
||||
const isScopedPackageKey = pluginId.startsWith("@") || pluginId.includes("/");
|
||||
|
||||
// Scoped package IDs are valid plugin keys but invalid UUIDs.
|
||||
// Skip getById() entirely to avoid Postgres uuid parse errors.
|
||||
if (isScopedPackageKey && !isUuid) {
|
||||
if (!isUuid) {
|
||||
return registry.getByKey(pluginId);
|
||||
}
|
||||
|
||||
try {
|
||||
const byId = await registry.getById(pluginId);
|
||||
if (byId) return byId;
|
||||
} catch (error) {
|
||||
const maybeCode =
|
||||
typeof error === "object" && error !== null && "code" in error
|
||||
? (error as { code?: unknown }).code
|
||||
: undefined;
|
||||
// Ignore invalid UUID cast errors and continue with key lookup.
|
||||
if (maybeCode !== "22P02") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const byId = await registry.getById(pluginId);
|
||||
if (byId) return byId;
|
||||
|
||||
return registry.getByKey(pluginId);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user