дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
fix(plugins): preserve uninstall retries and bound mock private paths (#2073)
Related #1947 Uninstall keeps a plugin registered but stopped until its private data, secrets and package are cleaned up; a failure is shown and Uninstall can be retried, also after a restart (a durable cleanup record outside the package restores the target). While cleanup is pending, enable, reload, consent, permission changes, reinstall, replacement and rollback are refused. Secret-deletion errors are reported, and cleanup never follows a symlinked ancestor outside plugin storage. The SDK mock checks private-path components and rejects traversal independently of filesystem grants. Co-authored-by: arnaud-ritti <[email protected]>
Цей коміт міститься в:
1 джерело
a2599a6f79
коміт
99102d8a40
73 files changed
+794
-49
No files matched your search
@@ -723,6 +723,44 @@ describe("PluginsPage", () => {
|
||||
expect(notes.at(-1)).toMatchObject({ title: "Uninstalled Hello" });
|
||||
});
|
||||
|
||||
it("keeps failed cleanup visible and lets Uninstall retry", async () => {
|
||||
const list = backend.list;
|
||||
const uninstall = backend.uninstall;
|
||||
let failed = false;
|
||||
vi.spyOn(backend, "list").mockImplementation(async () => {
|
||||
const snapshot = await list();
|
||||
if (failed) {
|
||||
snapshot.plugins = snapshot.plugins.map((p) =>
|
||||
p.id === "hello" ? { ...p, status: "failed", error: "Private data is locked" } : p,
|
||||
);
|
||||
}
|
||||
return snapshot;
|
||||
});
|
||||
const remove = vi.spyOn(backend, "uninstall").mockImplementation(async (id) => {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
throw new Error("Private data is locked");
|
||||
}
|
||||
await uninstall(id);
|
||||
});
|
||||
const user = userEvent.setup();
|
||||
render(<PluginsPage />);
|
||||
await screen.findByRole("heading", { level: 2 });
|
||||
await user.click(screen.getByRole("button", { name: "Uninstall…" }));
|
||||
await user.click(screen.getByRole("button", { name: "Confirm uninstall Hello" }));
|
||||
await screen.findByText("Private data is locked");
|
||||
expect(notes.at(-1)).toMatchObject({
|
||||
level: "error",
|
||||
title: "Could not uninstall Hello",
|
||||
body: "Private data is locked",
|
||||
});
|
||||
expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent("Hello");
|
||||
await user.click(screen.getByRole("button", { name: "Confirm uninstall Hello" }));
|
||||
await waitFor(() => expect(screen.getByRole("heading", { level: 2 })).not.toHaveTextContent("Hello"));
|
||||
expect(remove).toHaveBeenCalledTimes(2);
|
||||
expect(notes.at(-1)).toMatchObject({ title: "Uninstalled Hello" });
|
||||
});
|
||||
|
||||
it("shows What's New from the change notes", async () => {
|
||||
const user = userEvent.setup();
|
||||
setPluginsBackend(
|
||||
|
||||
Reference in new issue
Заблокувати користувача