Skip to content

Commit 6c46ad4

Browse files
committed
Merge branch 'dev/1.30' of https://github.com/weaviate/weaviate-python-client into poc-separate-sync-and-async
2 parents 9194da1 + f69ad26 commit 6c46ad4

3 files changed

Lines changed: 141 additions & 34 deletions

File tree

integration/test_rbac.py

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,36 @@
8484
collections_permissions=[],
8585
roles_permissions=[],
8686
data_permissions=[
87-
DataPermissionOutput(collection="*", actions={Actions.Data.CREATE})
87+
DataPermissionOutput(collection="*", tenant="*", actions={Actions.Data.CREATE})
88+
],
89+
backups_permissions=[],
90+
nodes_permissions=[],
91+
tenants_permissions=[],
92+
),
93+
),
94+
(
95+
Permissions.data(
96+
collection=["ColA", "ColB"], tenant=["tenant1", "tenant2"], create=True
97+
),
98+
Role(
99+
name="CreateDataInColsAndTenants",
100+
cluster_permissions=[],
101+
users_permissions=[],
102+
collections_permissions=[],
103+
roles_permissions=[],
104+
data_permissions=[
105+
DataPermissionOutput(
106+
collection="ColA", tenant="tenant1", actions={Actions.Data.CREATE}
107+
),
108+
DataPermissionOutput(
109+
collection="ColA", tenant="tenant2", actions={Actions.Data.CREATE}
110+
),
111+
DataPermissionOutput(
112+
collection="ColB", tenant="tenant1", actions={Actions.Data.CREATE}
113+
),
114+
DataPermissionOutput(
115+
collection="ColB", tenant="tenant2", actions={Actions.Data.CREATE}
116+
),
88117
],
89118
backups_permissions=[],
90119
nodes_permissions=[],
@@ -158,11 +187,50 @@
158187
nodes_permissions=[],
159188
tenants_permissions=[
160189
TenantsPermissionOutput(
161-
collection="*", actions={Actions.Tenants.READ, Actions.Tenants.UPDATE}
190+
collection="*",
191+
tenant="*",
192+
actions={Actions.Tenants.READ, Actions.Tenants.UPDATE},
162193
)
163194
],
164195
),
165196
),
197+
(
198+
Permissions.tenants(
199+
collection=["ColA", "ColB"], tenant=["tenant1", "tenant2"], read=True, update=True
200+
),
201+
Role(
202+
name="ReadSpecificTenantsInCols",
203+
cluster_permissions=[],
204+
users_permissions=[],
205+
collections_permissions=[],
206+
roles_permissions=[],
207+
data_permissions=[],
208+
backups_permissions=[],
209+
nodes_permissions=[],
210+
tenants_permissions=[
211+
TenantsPermissionOutput(
212+
collection="ColA",
213+
tenant="tenant1",
214+
actions={Actions.Tenants.READ, Actions.Tenants.UPDATE},
215+
),
216+
TenantsPermissionOutput(
217+
collection="ColA",
218+
tenant="tenant2",
219+
actions={Actions.Tenants.READ, Actions.Tenants.UPDATE},
220+
),
221+
TenantsPermissionOutput(
222+
collection="ColB",
223+
tenant="tenant1",
224+
actions={Actions.Tenants.READ, Actions.Tenants.UPDATE},
225+
),
226+
TenantsPermissionOutput(
227+
collection="ColB",
228+
tenant="tenant2",
229+
actions={Actions.Tenants.READ, Actions.Tenants.UPDATE},
230+
),
231+
],
232+
),
233+
),
166234
(
167235
Permissions.users(user="*", assign_and_revoke=True, read=True),
168236
Role(
@@ -198,7 +266,6 @@ def test_create_role(
198266
role = client.roles.get(expected.name)
199267
assert role is not None
200268
assert role == expected
201-
assert len(role.permissions) == 1
202269
finally:
203270
client.roles.delete(expected.name)
204271

weaviate/collections/tenants/executor.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,14 +340,35 @@ def get_by_name(
340340
_validate_input(
341341
_ValidateArgument(expected=[Union[str, Tenant]], name="tenant", value=tenant)
342342
)
343+
tenant_name = tenant.name if isinstance(tenant, Tenant) else tenant
344+
if self._connection._weaviate_version.is_lower_than(1, 28, 0):
345+
# For Weaviate versions < 1.28.0, we need to use the gRPC API
346+
# such versions don't have RBAC so the filtering issue doesn't exist therein
347+
def resp_grpc(res: Dict[str, TenantOutputType]) -> Optional[TenantOutputType]:
348+
return res.get(tenant_name)
349+
350+
return executor.execute(
351+
response_callback=resp_grpc,
352+
method=self.__get_with_grpc,
353+
tenants=[tenant_name],
354+
)
343355

344-
def resp(res: Dict[str, TenantOutputType]) -> Optional[TenantOutputType]:
345-
return res.get(tenant.name if isinstance(tenant, Tenant) else tenant)
356+
# For Weaviate versions >= 1.28.0, we need to use the REST API
357+
# as the gRPC API filters out tenants that are not accessible to the user
358+
# due to RBAC requirements
359+
def resp_rest(res: Response) -> Optional[TenantOutputType]:
360+
if res.status_code == 404:
361+
return None
362+
return Tenant(**res.json())
346363

347364
return executor.execute(
348-
response_callback=resp,
349-
method=self.get_by_names,
350-
tenants=[tenant],
365+
response_callback=resp_rest,
366+
method=self._connection.get,
367+
path=f"/schema/{self._name}/tenants/{tenant_name}",
368+
error_msg=f"Could not get tenant {tenant_name} for collection {self._name}",
369+
status_codes=_ExpectedStatusCodes(
370+
ok_in=[200, 404], error=f"Get tenant {tenant_name} for collection {self._name}"
371+
),
351372
)
352373

353374
def __update(

weaviate/rbac/models.py

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class RoleScope(str, BaseEnum):
4040

4141
class PermissionData(TypedDict):
4242
collection: str
43+
tenant: str
4344

4445

4546
class PermissionCollections(TypedDict):
@@ -220,14 +221,15 @@ def _to_weaviate(self) -> List[WeaviatePermission]:
220221

221222
class _TenantsPermission(_Permission[TenantsAction]):
222223
collection: str
224+
tenant: str
223225

224226
def _to_weaviate(self) -> List[WeaviatePermission]:
225227
return [
226228
{
227229
"action": action,
228230
"tenants": {
229231
"collection": _capitalize_first_letter(self.collection),
230-
"tenant": "*",
232+
"tenant": self.tenant,
231233
},
232234
}
233235
for action in self.actions
@@ -303,13 +305,15 @@ def _to_weaviate(self) -> List[WeaviatePermission]:
303305

304306
class _DataPermission(_Permission[DataAction]):
305307
collection: str
308+
tenant: str
306309

307310
def _to_weaviate(self) -> List[WeaviatePermission]:
308311
return [
309312
{
310313
"action": action,
311314
"data": {
312315
"collection": _capitalize_first_letter(self.collection),
316+
"tenant": self.tenant,
313317
},
314318
}
315319
for action in self.actions
@@ -428,6 +432,7 @@ def _from_weaviate_role(cls, role: WeaviateRole) -> "Role":
428432
tenants_permissions.append(
429433
TenantsPermissionOutput(
430434
collection=tenants["collection"],
435+
tenant=tenants.get("tenant", "*"),
431436
actions={TenantsAction(permission["action"])},
432437
)
433438
)
@@ -448,6 +453,7 @@ def _from_weaviate_role(cls, role: WeaviateRole) -> "Role":
448453
data_permissions.append(
449454
DataPermissionOutput(
450455
collection=data["collection"],
456+
tenant=data.get("tenant", "*"),
451457
actions={DataAction(permission["action"])},
452458
)
453459
)
@@ -576,6 +582,7 @@ class Permissions:
576582
def data(
577583
*,
578584
collection: Union[str, Sequence[str]],
585+
tenant: Union[str, Sequence[str], None] = None,
579586
create: bool = False,
580587
read: bool = False,
581588
update: bool = False,
@@ -584,20 +591,25 @@ def data(
584591
permissions: List[_Permission] = []
585592
if isinstance(collection, str):
586593
collection = [collection]
594+
if tenant is None:
595+
tenant = ["*"]
596+
if isinstance(tenant, str):
597+
tenant = [tenant]
587598
for c in collection:
588-
permission = _DataPermission(collection=c, actions=set())
589-
590-
if create:
591-
permission.actions.add(DataAction.CREATE)
592-
if read:
593-
permission.actions.add(DataAction.READ)
594-
if update:
595-
permission.actions.add(DataAction.UPDATE)
596-
if delete:
597-
permission.actions.add(DataAction.DELETE)
598-
599-
if len(permission.actions) > 0:
600-
permissions.append(permission)
599+
for t in tenant:
600+
permission = _DataPermission(collection=c, tenant=t, actions=set())
601+
602+
if create:
603+
permission.actions.add(DataAction.CREATE)
604+
if read:
605+
permission.actions.add(DataAction.READ)
606+
if update:
607+
permission.actions.add(DataAction.UPDATE)
608+
if delete:
609+
permission.actions.add(DataAction.DELETE)
610+
611+
if len(permission.actions) > 0:
612+
permissions.append(permission)
601613
return permissions
602614

603615
@staticmethod
@@ -631,6 +643,7 @@ def collections(
631643
def tenants(
632644
*,
633645
collection: Union[str, Sequence[str]],
646+
tenant: Union[str, Sequence[str], None] = None,
634647
create: bool = False,
635648
read: bool = False,
636649
update: bool = False,
@@ -639,19 +652,25 @@ def tenants(
639652
permissions: List[_Permission] = []
640653
if isinstance(collection, str):
641654
collection = [collection]
655+
if tenant is None:
656+
tenant = ["*"]
657+
if isinstance(tenant, str):
658+
tenant = [tenant]
642659
for c in collection:
643-
permission = _TenantsPermission(collection=c, actions=set())
644-
if create:
645-
permission.actions.add(TenantsAction.CREATE)
646-
if read:
647-
permission.actions.add(TenantsAction.READ)
648-
if update:
649-
permission.actions.add(TenantsAction.UPDATE)
650-
if delete:
651-
permission.actions.add(TenantsAction.DELETE)
652-
653-
if len(permission.actions) > 0:
654-
permissions.append(permission)
660+
for t in tenant:
661+
permission = _TenantsPermission(collection=c, tenant=t, actions=set())
662+
663+
if create:
664+
permission.actions.add(TenantsAction.CREATE)
665+
if read:
666+
permission.actions.add(TenantsAction.READ)
667+
if update:
668+
permission.actions.add(TenantsAction.UPDATE)
669+
if delete:
670+
permission.actions.add(TenantsAction.DELETE)
671+
672+
if len(permission.actions) > 0:
673+
permissions.append(permission)
655674

656675
return permissions
657676

0 commit comments

Comments
 (0)