Skip to content

Commit f53e112

Browse files
authored
Add role private attribute (#714)
1 parent 366b4b4 commit f53e112

File tree

3 files changed

+129
-4
lines changed

3 files changed

+129
-4
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -975,16 +975,18 @@ descope_client.mgmt.role.create(
975975
name="My Role",
976976
description="Optional description to briefly explain what this role allows.",
977977
permission_names=["My Updated Permission"],
978-
tenant_id="Optionally scope this role for this specific tenant. If left empty, the role will be available to all tenants."
978+
tenant_id="Optionally scope this role for this specific tenant. If left empty, the role will be available to all tenants.",
979+
private=False # Optional, marks this role as private role
979980
)
980981

981982
# Update will override all fields as is. Use carefully.
982983
descope_client.mgmt.role.update(
983984
name="My Role",
984985
new_name="My Updated Role",
985986
description="A revised description",
986-
permission_names=["My Updated Permission", "Another Permission"]
987-
tenant_id="The tenant ID to which this role is associated, leave empty, if role is a global one"
987+
permission_names=["My Updated Permission", "Another Permission"],
988+
tenant_id="The tenant ID to which this role is associated, leave empty, if role is a global one",
989+
private=True # Optional, marks this role as private role
988990
)
989991

990992
# Role deletion cannot be undone. Use carefully.

descope/management/role.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def create(
1414
permission_names: Optional[List[str]] = None,
1515
tenant_id: Optional[str] = None,
1616
default: Optional[bool] = None,
17+
private: Optional[bool] = None,
1718
):
1819
"""
1920
Create a new role.
@@ -24,6 +25,7 @@ def create(
2425
permission_names (List[str]): Optional list of names of permissions this role grants.
2526
tenant_id (str): Optional tenant ID to create the role in.
2627
default (bool): Optional marks this role as default role.
28+
private (bool): Optional marks this role as private role.
2729
2830
Raise:
2931
AuthException: raised if creation operation fails
@@ -38,6 +40,7 @@ def create(
3840
"permissionNames": permission_names,
3941
"tenantId": tenant_id,
4042
"default": default,
43+
"private": private,
4144
},
4245
)
4346

@@ -49,6 +52,7 @@ def update(
4952
permission_names: Optional[List[str]] = None,
5053
tenant_id: Optional[str] = None,
5154
default: Optional[bool] = None,
55+
private: Optional[bool] = None,
5256
):
5357
"""
5458
Update an existing role with the given various fields. IMPORTANT: All parameters are used as overrides
@@ -61,6 +65,7 @@ def update(
6165
permission_names (List[str]): Optional list of names of permissions this role grants.
6266
tenant_id (str): Optional tenant ID to update the role in.
6367
default (bool): Optional marks this role as default role.
68+
private (bool): Optional marks this role as private role.
6469
6570
Raise:
6671
AuthException: raised if update operation fails
@@ -75,6 +80,7 @@ def update(
7580
"permissionNames": permission_names,
7681
"tenantId": tenant_id,
7782
"default": default,
83+
"private": private,
7884
},
7985
)
8086

tests/management/test_role.py

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def test_create(self):
4545
with patch("requests.post") as mock_post:
4646
mock_post.return_value.ok = True
4747
self.assertIsNone(
48-
client.mgmt.role.create("R1", "Something", ["P1"], "t1", True)
48+
client.mgmt.role.create("R1", "Something", ["P1"], "t1", True, False)
4949
)
5050
mock_post.assert_called_with(
5151
f"{common.DEFAULT_BASE_URL}{MgmtV1.role_create_path}",
@@ -61,6 +61,7 @@ def test_create(self):
6161
"permissionNames": ["P1"],
6262
"tenantId": "t1",
6363
"default": True,
64+
"private": False,
6465
},
6566
allow_redirects=False,
6667
verify=True,
@@ -96,6 +97,7 @@ def test_update(self):
9697
["P1", "P2"],
9798
"t1",
9899
True,
100+
False,
99101
)
100102
)
101103
mock_post.assert_called_with(
@@ -113,6 +115,7 @@ def test_update(self):
113115
"permissionNames": ["P1", "P2"],
114116
"tenantId": "t1",
115117
"default": True,
118+
"private": False,
116119
},
117120
allow_redirects=False,
118121
verify=True,
@@ -264,3 +267,117 @@ def test_search(self):
264267
verify=True,
265268
timeout=DEFAULT_TIMEOUT_SECONDS,
266269
)
270+
271+
def test_create_with_private_true(self):
272+
client = DescopeClient(
273+
self.dummy_project_id,
274+
self.public_key_dict,
275+
False,
276+
self.dummy_management_key,
277+
)
278+
279+
# Test private=True
280+
with patch("requests.post") as mock_post:
281+
mock_post.return_value.ok = True
282+
self.assertIsNone(
283+
client.mgmt.role.create(
284+
"PrivateRole", "Private role", ["P1"], "t1", False, True
285+
)
286+
)
287+
mock_post.assert_called_with(
288+
f"{common.DEFAULT_BASE_URL}{MgmtV1.role_create_path}",
289+
headers={
290+
**common.default_headers,
291+
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
292+
"x-descope-project-id": self.dummy_project_id,
293+
},
294+
params=None,
295+
json={
296+
"name": "PrivateRole",
297+
"description": "Private role",
298+
"permissionNames": ["P1"],
299+
"tenantId": "t1",
300+
"default": False,
301+
"private": True,
302+
},
303+
allow_redirects=False,
304+
verify=True,
305+
timeout=DEFAULT_TIMEOUT_SECONDS,
306+
)
307+
308+
def test_update_with_private_true(self):
309+
client = DescopeClient(
310+
self.dummy_project_id,
311+
self.public_key_dict,
312+
False,
313+
self.dummy_management_key,
314+
)
315+
316+
# Test private=True
317+
with patch("requests.post") as mock_post:
318+
mock_post.return_value.ok = True
319+
self.assertIsNone(
320+
client.mgmt.role.update(
321+
"role",
322+
"updated-role",
323+
"Updated private role",
324+
["P1", "P2"],
325+
"t1",
326+
False,
327+
True,
328+
)
329+
)
330+
mock_post.assert_called_with(
331+
f"{common.DEFAULT_BASE_URL}{MgmtV1.role_update_path}",
332+
headers={
333+
**common.default_headers,
334+
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
335+
"x-descope-project-id": self.dummy_project_id,
336+
},
337+
params=None,
338+
json={
339+
"name": "role",
340+
"newName": "updated-role",
341+
"description": "Updated private role",
342+
"permissionNames": ["P1", "P2"],
343+
"tenantId": "t1",
344+
"default": False,
345+
"private": True,
346+
},
347+
allow_redirects=False,
348+
verify=True,
349+
timeout=DEFAULT_TIMEOUT_SECONDS,
350+
)
351+
352+
def test_create_without_private_parameter(self):
353+
client = DescopeClient(
354+
self.dummy_project_id,
355+
self.public_key_dict,
356+
False,
357+
self.dummy_management_key,
358+
)
359+
360+
# Test without private parameter (should be None)
361+
with patch("requests.post") as mock_post:
362+
mock_post.return_value.ok = True
363+
self.assertIsNone(client.mgmt.role.create("SimpleRole", "Simple role"))
364+
mock_post.assert_called_with(
365+
f"{common.DEFAULT_BASE_URL}{MgmtV1.role_create_path}",
366+
headers={
367+
**common.default_headers,
368+
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
369+
"x-descope-project-id": self.dummy_project_id,
370+
},
371+
params=None,
372+
json={
373+
"name": "SimpleRole",
374+
"description": "Simple role",
375+
"permissionNames": [],
376+
"tenantId": None,
377+
"default": None,
378+
"private": None,
379+
},
380+
allow_redirects=False,
381+
verify=True,
382+
timeout=DEFAULT_TIMEOUT_SECONDS,
383+
)

0 commit comments

Comments
 (0)