Skip to content

Commit 4ff198a

Browse files
authored
feat(query): row access policy support rbac (#19064)
1 parent cd130fd commit 4ff198a

File tree

30 files changed

+815
-38
lines changed

30 files changed

+815
-38
lines changed

src/meta/app/src/principal/ownership_object.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ pub enum OwnershipObject {
7474
MaskingPolicy {
7575
policy_id: u64,
7676
},
77+
78+
RowAccessPolicy {
79+
policy_id: u64,
80+
},
7781
}
7882

7983
impl OwnershipObject {
@@ -109,6 +113,9 @@ impl fmt::Display for OwnershipObject {
109113
OwnershipObject::MaskingPolicy { policy_id } => {
110114
write!(f, "MASKING POLICY {policy_id}")
111115
}
116+
OwnershipObject::RowAccessPolicy { policy_id } => {
117+
write!(f, "ROW ACCESS POLICY {policy_id}")
118+
}
112119
}
113120
}
114121
}
@@ -157,6 +164,9 @@ impl KeyCodec for OwnershipObject {
157164
OwnershipObject::MaskingPolicy { policy_id } => {
158165
b.push_raw("masking-policy-by-id").push_u64(*policy_id)
159166
}
167+
OwnershipObject::RowAccessPolicy { policy_id } => {
168+
b.push_raw("row-access-policy-by-id").push_u64(*policy_id)
169+
}
160170
}
161171
}
162172

@@ -223,9 +233,13 @@ impl KeyCodec for OwnershipObject {
223233
let policy_id = p.next_u64()?;
224234
Ok(OwnershipObject::MaskingPolicy { policy_id })
225235
}
236+
"row-access-policy-by-id" => {
237+
let policy_id = p.next_u64()?;
238+
Ok(OwnershipObject::RowAccessPolicy { policy_id })
239+
}
226240
_ => Err(kvapi::KeyError::InvalidSegment {
227241
i: p.index(),
228-
expect: "database-by-id|database-by-catalog-id|table-by-id|table-by-catalog-id|stage-by-name|udf-by-name|warehouse-by-id|connection-by-name|masking-policy-by-id"
242+
expect: "database-by-id|database-by-catalog-id|table-by-id|table-by-catalog-id|stage-by-name|udf-by-name|warehouse-by-id|connection-by-name|masking-policy-by-id|row-access-policy-by-id"
229243
.to_string(),
230244
got: q.to_string(),
231245
}),

src/meta/app/src/principal/user_grant.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub enum GrantObject {
6464
Sequence(String),
6565
Procedure(u64),
6666
MaskingPolicy(u64),
67+
RowAccessPolicy(u64),
6768
}
6869

6970
impl GrantObject {
@@ -101,6 +102,7 @@ impl GrantObject {
101102
(GrantObject::Sequence(s), GrantObject::Sequence(rs)) => s == rs,
102103
(GrantObject::Procedure(p), GrantObject::Procedure(rp)) => p == rp,
103104
(GrantObject::MaskingPolicy(lp), GrantObject::MaskingPolicy(rp)) => lp == rp,
105+
(GrantObject::RowAccessPolicy(lp), GrantObject::RowAccessPolicy(rp)) => lp == rp,
104106
_ => false,
105107
}
106108
}
@@ -136,6 +138,9 @@ impl GrantObject {
136138
GrantObject::MaskingPolicy(_) => {
137139
UserPrivilegeSet::available_privileges_on_masking_policy(available_ownership)
138140
}
141+
GrantObject::RowAccessPolicy(_) => {
142+
UserPrivilegeSet::available_privileges_on_row_access_policy(available_ownership)
143+
}
139144
}
140145
}
141146

@@ -148,6 +153,7 @@ impl GrantObject {
148153
| GrantObject::Sequence(_)
149154
| GrantObject::Procedure(_)
150155
| GrantObject::MaskingPolicy(_)
156+
| GrantObject::RowAccessPolicy(_)
151157
| GrantObject::Connection(_) => None,
152158
GrantObject::Database(cat, _) | GrantObject::DatabaseById(cat, _) => Some(cat.clone()),
153159
GrantObject::Table(cat, _, _) | GrantObject::TableById(cat, _, _) => Some(cat.clone()),
@@ -174,6 +180,9 @@ impl fmt::Display for GrantObject {
174180
GrantObject::Sequence(s) => write!(f, "SEQUENCE {s}"),
175181
GrantObject::Procedure(p) => write!(f, "PROCEDURE {p}"),
176182
GrantObject::MaskingPolicy(policy_id) => write!(f, "MASKING POLICY {policy_id}"),
183+
GrantObject::RowAccessPolicy(policy_id) => {
184+
write!(f, "ROW ACCESS POLICY {policy_id}")
185+
}
177186
}
178187
}
179188
}

src/meta/app/src/principal/user_privilege.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ pub enum UserPrivilegeType {
9292
ApplyMaskingPolicy = 1 << 28,
9393
// Privilege to Create Masking Policy.
9494
CreateMaskingPolicy = 1 << 29,
95+
// Privilege to Apply Row Access Policy.
96+
ApplyRowAccessPolicy = 1 << 30,
97+
// Privilege to Create Row Access Policy.
98+
CreateRowAccessPolicy = 1 << 31,
9599
// Discard Privilege Type
96100
Set = 1 << 4,
97101
CreateDataMask = 1 << 16,
@@ -119,6 +123,8 @@ impl Display for UserPrivilegeType {
119123
UserPrivilegeType::CreateDataMask => "CREATE DATAMASK",
120124
UserPrivilegeType::CreateMaskingPolicy => "CREATE MASKING POLICY",
121125
UserPrivilegeType::ApplyMaskingPolicy => "APPLY MASKING POLICY",
126+
UserPrivilegeType::CreateRowAccessPolicy => "CREATE ROW ACCESS POLICY",
127+
UserPrivilegeType::ApplyRowAccessPolicy => "APPLY ROW ACCESS POLICY",
122128
UserPrivilegeType::Ownership => "OWNERSHIP",
123129
UserPrivilegeType::Read => "Read",
124130
UserPrivilegeType::Write => "Write",
@@ -164,6 +170,12 @@ impl From<databend_common_ast::ast::UserPrivilegeType> for UserPrivilegeType {
164170
databend_common_ast::ast::UserPrivilegeType::ApplyMaskingPolicy => {
165171
UserPrivilegeType::ApplyMaskingPolicy
166172
}
173+
databend_common_ast::ast::UserPrivilegeType::CreateRowAccessPolicy => {
174+
UserPrivilegeType::CreateRowAccessPolicy
175+
}
176+
databend_common_ast::ast::UserPrivilegeType::ApplyRowAccessPolicy => {
177+
UserPrivilegeType::ApplyRowAccessPolicy
178+
}
167179
databend_common_ast::ast::UserPrivilegeType::Ownership => UserPrivilegeType::Ownership,
168180
databend_common_ast::ast::UserPrivilegeType::Read => UserPrivilegeType::Read,
169181
databend_common_ast::ast::UserPrivilegeType::Write => UserPrivilegeType::Write,
@@ -228,15 +240,17 @@ impl UserPrivilegeSet {
228240
let connection_privs_without_ownership = Self::available_privileges_on_connection(false);
229241
let seq_privs_without_ownership = Self::available_privileges_on_sequence(false);
230242
let mask_privs = Self::available_privileges_on_masking_policy(false);
231-
let privs = make_bitflags!(UserPrivilegeType::{ Usage | Super | CreateUser | DropUser | CreateRole | DropRole | CreateDatabase | Grant | CreateDataMask | CreateMaskingPolicy | CreateWarehouse | CreateConnection | CreateSequence | CreateProcedure });
243+
let row_access_privs = Self::available_privileges_on_row_access_policy(false);
244+
let privs = make_bitflags!(UserPrivilegeType::{ Usage | Super | CreateUser | DropUser | CreateRole | DropRole | CreateDatabase | Grant | CreateDataMask | CreateMaskingPolicy | CreateRowAccessPolicy | CreateWarehouse | CreateConnection | CreateSequence | CreateProcedure });
232245
(database_privs.privileges
233246
| privs
234247
| stage_privs_without_ownership.privileges
235248
| wh_privs_without_ownership.privileges
236249
| connection_privs_without_ownership.privileges
237250
| seq_privs_without_ownership.privileges
238251
| udf_privs_without_ownership.privileges
239-
| mask_privs.privileges)
252+
| mask_privs.privileges
253+
| row_access_privs.privileges)
240254
.into()
241255
}
242256

@@ -315,6 +329,14 @@ impl UserPrivilegeSet {
315329
}
316330
}
317331

332+
pub fn available_privileges_on_row_access_policy(available_ownership: bool) -> Self {
333+
if available_ownership {
334+
make_bitflags!(UserPrivilegeType::{ ApplyRowAccessPolicy | Ownership }).into()
335+
} else {
336+
make_bitflags!(UserPrivilegeType::{ ApplyRowAccessPolicy }).into()
337+
}
338+
}
339+
318340
pub fn set_privilege(&mut self, privilege: UserPrivilegeType) {
319341
self.privileges |= privilege;
320342
}

src/meta/proto-conv/src/ownership_from_to_protobuf_impl.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ impl FromToProto for mt::principal::OwnershipObject {
103103
pb::ownership_object::Object::MaskingPolicy(
104104
pb::ownership_object::OwnershipMaskingPolicyObject { policy_id },
105105
) => Ok(mt::principal::OwnershipObject::MaskingPolicy { policy_id }),
106+
pb::ownership_object::Object::RowAccessPolicy(
107+
pb::ownership_object::OwnershipRowAccessPolicyObject { policy_id },
108+
) => Ok(mt::principal::OwnershipObject::RowAccessPolicy { policy_id }),
106109
}
107110
}
108111

@@ -171,6 +174,13 @@ impl FromToProto for mt::principal::OwnershipObject {
171174
},
172175
))
173176
}
177+
mt::principal::OwnershipObject::RowAccessPolicy { policy_id } => {
178+
Some(pb::ownership_object::Object::RowAccessPolicy(
179+
pb::ownership_object::OwnershipRowAccessPolicyObject {
180+
policy_id: *policy_id,
181+
},
182+
))
183+
}
174184
};
175185
Ok(pb::OwnershipObject {
176186
ver: VER,

src/meta/proto-conv/src/user_from_to_protobuf_impl.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ impl FromToProto for mt::principal::GrantObject {
206206
pb::grant_object::Object::Maskingpolicy(
207207
pb::grant_object::GrantMaskingPolicyObject { policy_id },
208208
) => Ok(mt::principal::GrantObject::MaskingPolicy(policy_id)),
209+
pb::grant_object::Object::RowAccessPolicy(
210+
pb::grant_object::GrantRowAccessPolicyObject { policy_id },
211+
) => Ok(mt::principal::GrantObject::RowAccessPolicy(policy_id)),
209212
}
210213
}
211214

@@ -273,6 +276,13 @@ impl FromToProto for mt::principal::GrantObject {
273276
},
274277
))
275278
}
279+
mt::principal::GrantObject::RowAccessPolicy(policy_id) => {
280+
Some(pb::grant_object::Object::RowAccessPolicy(
281+
pb::grant_object::GrantRowAccessPolicyObject {
282+
policy_id: *policy_id,
283+
},
284+
))
285+
}
276286
};
277287
Ok(pb::GrantObject {
278288
ver: VER,

src/meta/proto-conv/src/util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ const META_CHANGE_LOG: &[(u64, &str)] = &[
190190
(158, "2025-10-22: Add: Server UDTF"),
191191
(159, "2025-11-18: Add: Grant/OwnershipMaskingPolicyObject and masking policy privileges"),
192192
(160, "2025-11-27: Add: udf.proto/UserDefinedFunction add update_on field"),
193+
(161, "2025-12-04: Add: Grant/OwnershipRowAccessPolicyObject and row access policy privileges"),
193194
// Dear developer:
194195
// If you're gonna add a new metadata version, you'll have to add a test for it.
195196
// You could just copy an existing test file(e.g., `../tests/it/v024_table_meta.rs`)

src/meta/proto-conv/tests/it/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,4 @@ mod v157_type_timestamp_tz;
152152
mod v158_udtf_server;
153153
mod v159_grant_object_masking_policy;
154154
mod v160_udf_update_on;
155+
mod v161_grant_object_row_access_policy;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2023 Datafuse Labs.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use std::collections::HashSet;
16+
17+
use chrono::DateTime;
18+
use chrono::Utc;
19+
use databend_common_meta_app as mt;
20+
use databend_common_meta_app::principal::OwnershipInfo;
21+
use databend_common_meta_app::principal::OwnershipObject;
22+
use databend_common_meta_app::principal::UserGrantSet;
23+
use databend_common_meta_app::principal::UserPrivilegeType;
24+
use enumflags2::make_bitflags;
25+
use fastrace::func_name;
26+
27+
use crate::common;
28+
29+
#[test]
30+
fn test_decode_v161_grant_object() -> anyhow::Result<()> {
31+
let role_info_v161 = vec![
32+
10, 8, 114, 97, 112, 95, 114, 111, 108, 101, 18, 61, 10, 24, 10, 9, 10, 0, 160, 6, 161, 1,
33+
168, 6, 24, 16, 128, 128, 128, 128, 8, 160, 6, 161, 1, 168, 6, 24, 10, 26, 10, 11, 106, 2,
34+
8, 7, 160, 6, 161, 1, 168, 6, 24, 16, 128, 128, 128, 128, 4, 160, 6, 161, 1, 168, 6, 24,
35+
160, 6, 161, 1, 168, 6, 24, 26, 23, 49, 57, 55, 48, 45, 48, 49, 45, 48, 49, 32, 48, 48, 58,
36+
48, 48, 58, 48, 48, 32, 85, 84, 67, 34, 23, 49, 57, 55, 48, 45, 48, 49, 45, 48, 49, 32, 48,
37+
48, 58, 48, 48, 58, 48, 48, 32, 85, 84, 67, 160, 6, 161, 1, 168, 6, 24,
38+
];
39+
40+
let want = || mt::principal::RoleInfo {
41+
name: "rap_role".to_string(),
42+
comment: None,
43+
grants: UserGrantSet::new(
44+
vec![
45+
mt::principal::GrantEntry::new(
46+
mt::principal::GrantObject::Global,
47+
make_bitflags!(UserPrivilegeType::{CreateRowAccessPolicy}),
48+
),
49+
mt::principal::GrantEntry::new(
50+
mt::principal::GrantObject::RowAccessPolicy(7),
51+
make_bitflags!(UserPrivilegeType::{ApplyRowAccessPolicy}),
52+
),
53+
],
54+
HashSet::new(),
55+
),
56+
created_on: DateTime::<Utc>::default(),
57+
update_on: DateTime::<Utc>::default(),
58+
};
59+
60+
common::test_pb_from_to(func_name!(), want())?;
61+
common::test_load_old(func_name!(), role_info_v161.as_slice(), 161, want())?;
62+
63+
Ok(())
64+
}
65+
66+
#[test]
67+
fn test_decode_v161_row_access_policy_ownership() -> anyhow::Result<()> {
68+
let ownership_info_v161 = vec![
69+
10, 10, 111, 119, 110, 101, 114, 95, 114, 111, 108, 101, 18, 11, 82, 2, 8, 42, 160, 6, 161,
70+
1, 168, 6, 24, 160, 6, 161, 1, 168, 6, 24,
71+
];
72+
73+
let want = || OwnershipInfo {
74+
role: "owner_role".to_string(),
75+
object: OwnershipObject::RowAccessPolicy { policy_id: 42 },
76+
};
77+
78+
common::test_pb_from_to(func_name!(), want())?;
79+
common::test_load_old(func_name!(), ownership_info_v161.as_slice(), 161, want())?;
80+
81+
Ok(())
82+
}

src/meta/protos/proto/ownership.proto

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ message OwnershipObject {
6666
uint64 policy_id = 1;
6767
}
6868

69+
message OwnershipRowAccessPolicyObject {
70+
uint64 policy_id = 1;
71+
}
72+
6973
oneof object {
7074
OwnershipDatabaseObject database = 1;
7175
OwnershipTableObject table = 2;
@@ -76,5 +80,6 @@ message OwnershipObject {
7680
OwnershipSequenceObject sequence = 7;
7781
OwnershipProcedureObject procedure = 8;
7882
OwnershipMaskingPolicyObject masking_policy = 9;
83+
OwnershipRowAccessPolicyObject row_access_policy = 10;
7984
}
8085
}

src/meta/protos/proto/user.proto

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ message GrantObject {
9797
uint64 policy_id = 1;
9898
}
9999

100+
message GrantRowAccessPolicyObject {
101+
uint64 policy_id = 1;
102+
}
103+
100104
oneof object {
101105
GrantGlobalObject global = 1;
102106
GrantDatabaseObject database = 2;
@@ -110,6 +114,7 @@ message GrantObject {
110114
GrantSequenceObject sequence = 10;
111115
GrantProcedureObject procedure = 11;
112116
GrantMaskingPolicyObject maskingpolicy = 12;
117+
GrantRowAccessPolicyObject row_access_policy = 13;
113118
}
114119
}
115120

0 commit comments

Comments
 (0)