From 959943315f65002ea95d02534beb15d749cb7740 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Fri, 24 Jul 2026 14:10:52 +0800 Subject: [PATCH] fix(doris): fall back to current user grants --- .../DatabaseUserAdmin.component.spec.ts | 31 +++++++++++++++++++ .../database/databaseUserAdmin.spec.ts | 2 ++ .../src/lib/database/databaseUserAdmin.ts | 6 ++++ packages/app-tests/databaseUserAdmin.test.ts | 2 ++ 4 files changed, 41 insertions(+) diff --git a/apps/desktop/src/lib/__tests__/database/DatabaseUserAdmin.component.spec.ts b/apps/desktop/src/lib/__tests__/database/DatabaseUserAdmin.component.spec.ts index b5973c3c2..d97c4b81f 100644 --- a/apps/desktop/src/lib/__tests__/database/DatabaseUserAdmin.component.spec.ts +++ b/apps/desktop/src/lib/__tests__/database/DatabaseUserAdmin.component.spec.ts @@ -110,4 +110,35 @@ describe("DatabaseUserAdmin MySQL grant loading", () => { expect(privilegeButton?.className).toContain("border-primary"); expect(grantOptionInput?.checked).toBe(true); }); + + it("falls back to the current Doris user when SHOW ALL GRANTS requires GRANT_PRIV", async () => { + const dorisConnection: ConnectionConfig = { + ...connection, + id: "doris-limited", + name: "Doris limited", + db_type: "doris", + driver_profile: "doris", + port: 9030, + username: "dbx_limited", + }; + const currentUserGrant = { + columns: ["UserIdentity", "Comment", "Password", "Roles", "GlobalPrivs", "DatabasePrivs", "TablePrivs"], + rows: [["'dbx_limited'@'%'", "", "Yes", null, null, "internal.analytics: Select_priv", null]], + }; + mocks.ensureConnected.mockResolvedValue(undefined); + mocks.executeQuery.mockRejectedValueOnce(new Error("Access denied; you need the (GRANT) privilege")); + mocks.executeQuery.mockResolvedValueOnce(currentUserGrant).mockResolvedValueOnce(currentUserGrant); + + root = document.createElement("div"); + document.body.append(root); + app = createApp(DatabaseUserAdmin, { connection: dorisConnection }); + app.mount(root); + + await vi.waitFor(() => expect(mocks.executeQuery).toHaveBeenCalledTimes(3)); + await nextTick(); + + expect(mocks.executeQuery.mock.calls.map((call) => call[2])).toEqual(["SHOW ALL GRANTS;", "SHOW GRANTS;", "SHOW GRANTS FOR 'dbx_limited'@'%';"]); + expect(root.textContent).toContain("dbx_limited@%"); + expect(root.textContent).not.toContain("Access denied"); + }); }); diff --git a/apps/desktop/src/lib/__tests__/database/databaseUserAdmin.spec.ts b/apps/desktop/src/lib/__tests__/database/databaseUserAdmin.spec.ts index 6716d6f31..157948741 100644 --- a/apps/desktop/src/lib/__tests__/database/databaseUserAdmin.spec.ts +++ b/apps/desktop/src/lib/__tests__/database/databaseUserAdmin.spec.ts @@ -59,6 +59,8 @@ describe("database user admin providers", () => { const provider = getDatabaseUserAdminProvider("doris"); expect(provider?.listUsersSql()).toBe("SHOW ALL GRANTS;"); + expect(provider?.fallbackListUsersSql?.()).toBe("SHOW GRANTS;"); + expect(provider?.parseFallbackUsers).toBe(dorisUsersResult); expect(provider?.showGrantsSql({ user: "reporter", host: "%" })).toBe("SHOW GRANTS FOR 'reporter'@'%';"); expect(provider?.alterPasswordSql?.({ user: "reporter", host: "%" }, "new'secret")).toBe("SET PASSWORD FOR 'reporter'@'%' = PASSWORD('new''secret');"); expect(dorisPrivilegeTargetSql("analytics", "daily`rollup")).toBe("`internal`.`analytics`.`daily``rollup`"); diff --git a/apps/desktop/src/lib/database/databaseUserAdmin.ts b/apps/desktop/src/lib/database/databaseUserAdmin.ts index 0b1508204..5e6aa00e9 100644 --- a/apps/desktop/src/lib/database/databaseUserAdmin.ts +++ b/apps/desktop/src/lib/database/databaseUserAdmin.ts @@ -116,6 +116,10 @@ export function dorisListUsersSql(): string { return "SHOW ALL GRANTS;"; } +export function dorisListCurrentUserSql(): string { + return "SHOW GRANTS;"; +} + export function dorisUsersResult(result: QueryResult): DatabaseUserIdentity[] { const userIndex = columnIndex(result, "UserIdentity"); if (userIndex < 0) return []; @@ -634,7 +638,9 @@ export const dorisUserAdminProvider: DatabaseUserAdminProvider = { dialect: "mysql", defaultScope: "table", listUsersSql: dorisListUsersSql, + fallbackListUsersSql: dorisListCurrentUserSql, parseUsers: dorisUsersResult, + parseFallbackUsers: dorisUsersResult, showGrantsSql: mysqlShowGrantsSql, parseGrants: dorisGrantsResult, createUserSql: mysqlCreateUserSql, diff --git a/packages/app-tests/databaseUserAdmin.test.ts b/packages/app-tests/databaseUserAdmin.test.ts index a7f1961bf..d3701f64d 100644 --- a/packages/app-tests/databaseUserAdmin.test.ts +++ b/packages/app-tests/databaseUserAdmin.test.ts @@ -265,6 +265,8 @@ test("routes Doris to a Doris 2.x user admin provider", () => { assert.ok(provider, "expected a provider for doris"); assert.equal(provider?.dialect, "mysql"); assert.equal(provider?.listUsersSql(), "SHOW ALL GRANTS;"); + assert.equal(provider?.fallbackListUsersSql?.(), "SHOW GRANTS;"); + assert.equal(provider?.parseFallbackUsers, dorisUsersResult); assert.equal(provider?.showGrantsSql({ user: "root", host: "%" }), "SHOW GRANTS FOR 'root'@'%';"); assert.equal(provider?.createUserSql?.({ user: "app", host: "%", password: "secret" }), "CREATE USER 'app'@'%' IDENTIFIED BY 'secret';"); assert.equal(dorisAlterUserPasswordSql({ user: "app", host: "%" }, "new'secret"), "SET PASSWORD FOR 'app'@'%' = PASSWORD('new''secret');");