fix(doris): fall back to current user grants

This commit is contained in:
t8y2 2026-07-24 14:10:52 +08:00
parent 7a0dbf3fb7
commit 959943315f
No known key found for this signature in database
4 changed files with 41 additions and 0 deletions

View File

@ -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");
});
});

View File

@ -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`");

View File

@ -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,

View File

@ -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');");