11# Copyright 2022 Pangea Cyber Corporation
22# Author: Pangea Cyber Corporation
33
4- # TODO: Use `list` instead of `List`.
5- # ruff: noqa: UP006, UP035
6-
74from __future__ import annotations
85
96import enum
10- from typing import Any , Dict , List , Optional , Union
7+ from collections .abc import Mapping , Sequence
8+ from typing import Annotated , Any , Optional , Union
9+
10+ from pydantic import Field
1111
1212from pangea .config import PangeaConfig
13- from pangea .response import APIRequestModel , APIResponseModel , PangeaResponse , PangeaResponseResult
13+ from pangea .response import APIRequestModel , APIResponseModel , PangeaDateTime , PangeaResponse , PangeaResponseResult
1414from pangea .services .base import ServiceBase
1515
1616
@@ -47,20 +47,18 @@ class Resource(PangeaResponseResult):
4747
4848class Subject (PangeaResponseResult ):
4949 type : str
50- id : Optional [str ] = None
51- action : Optional [str ] = None
50+ id : Annotated [str , Field ( pattern = "^([a-zA-Z0-9_][a-zA-Z0-9/|_.@-]*)$" )]
51+ action : Annotated [ Optional [str ], Field ( pattern = "^([a-zA-Z0-9_][a-zA-Z0-9/|_]*)$" ) ] = None
5252
5353
5454class Tuple (PangeaResponseResult ):
5555 resource : Resource
56- relation : str
56+ relation : Annotated [ str , Field ( pattern = "^([a-zA-Z0-9_][a-zA-Z0-9/|_]*)$" )]
5757 subject : Subject
58- expires_at : Optional [str ] = None
58+ expires_at : Optional [PangeaDateTime ] = None
5959 """A time in ISO-8601 format"""
60-
61-
62- class TupleCreateRequest (APIRequestModel ):
63- tuples : List [Tuple ]
60+ attributes : Optional [dict [str , Any ]] = None
61+ """A JSON object of attribute data."""
6462
6563
6664class TupleCreateResult (PangeaResponseResult ):
@@ -70,92 +68,82 @@ class TupleCreateResult(PangeaResponseResult):
7068class TupleListFilter (APIRequestModel ):
7169 resource_type : Optional [str ] = None
7270 """Only records where resource type equals this value."""
73- resource_type__contains : Optional [List [str ]] = None
71+ resource_type__contains : Optional [list [str ]] = None
7472 """Only records where resource type includes each substring."""
75- resource_type__in : Optional [List [str ]] = None
73+ resource_type__in : Optional [list [str ]] = None
7674 """Only records where resource type equals one of the provided substrings."""
7775 resource_id : Optional [str ] = None
7876 """Only records where resource id equals this value."""
79- resource_id__contains : Optional [List [str ]] = None
77+ resource_id__contains : Optional [list [str ]] = None
8078 """Only records where resource id includes each substring."""
81- resource_id__in : Optional [List [str ]] = None
79+ resource_id__in : Optional [list [str ]] = None
8280 """Only records where resource id equals one of the provided substrings."""
8381 relation : Optional [str ] = None
8482 """Only records where relation equals this value."""
85- relation__contains : Optional [List [str ]] = None
83+ relation__contains : Optional [list [str ]] = None
8684 """Only records where relation includes each substring."""
87- relation__in : Optional [List [str ]] = None
85+ relation__in : Optional [list [str ]] = None
8886 """Only records where relation equals one of the provided substrings."""
8987 subject_type : Optional [str ] = None
9088 """Only records where subject type equals this value."""
91- subject_type__contains : Optional [List [str ]] = None
89+ subject_type__contains : Optional [list [str ]] = None
9290 """Only records where subject type includes each substring."""
93- subject_type__in : Optional [List [str ]] = None
91+ subject_type__in : Optional [list [str ]] = None
9492 """Only records where subject type equals one of the provided substrings."""
9593 subject_id : Optional [str ] = None
9694 """Only records where subject id equals this value."""
97- subject_id__contains : Optional [List [str ]] = None
95+ subject_id__contains : Optional [list [str ]] = None
9896 """Only records where subject id includes each substring."""
99- subject_id__in : Optional [List [str ]] = None
97+ subject_id__in : Optional [list [str ]] = None
10098 """Only records where subject id equals one of the provided substrings."""
10199 subject_action : Optional [str ] = None
102100 """Only records where subject action equals this value."""
103- subject_action__contains : Optional [List [str ]] = None
101+ subject_action__contains : Optional [list [str ]] = None
104102 """Only records where subject action includes each substring."""
105- subject_action__in : Optional [List [str ]] = None
103+ subject_action__in : Optional [list [str ]] = None
106104 """Only records where subject action equals one of the provided substrings."""
107- expires_at : Optional [str ] = None
105+ expires_at : Optional [PangeaDateTime ] = None
108106 """Only records where expires_at equals this value."""
109- expires_at__gt : Optional [str ] = None
107+ expires_at__gt : Optional [PangeaDateTime ] = None
110108 """Only records where expires_at is greater than this value."""
111- expires_at__gte : Optional [str ] = None
109+ expires_at__gte : Optional [PangeaDateTime ] = None
112110 """Only records where expires_at is greater than or equal to this value."""
113- expires_at__lt : Optional [str ] = None
111+ expires_at__lt : Optional [PangeaDateTime ] = None
114112 """Only records where expires_at is less than this value."""
115- expires_at__lte : Optional [str ] = None
113+ expires_at__lte : Optional [PangeaDateTime ] = None
116114 """Only records where expires_at is less than or equal to this value."""
117115
118116
119117class TupleListRequest (APIRequestModel ):
120- filter : Optional [Union [Dict , TupleListFilter ]] = None
118+ filter : Optional [Union [dict , TupleListFilter ]] = None
121119 size : Optional [int ] = None
122120 last : Optional [str ] = None
123121 order : Optional [ItemOrder ] = None
124122 order_by : Optional [TupleOrderBy ] = None
125123
126124
127125class TupleListResult (PangeaResponseResult ):
128- tuples : List [Tuple ]
126+ tuples : list [Tuple ]
129127 last : str
130128 count : int
131129
132130
133131class TupleDeleteRequest (APIRequestModel ):
134- tuples : List [Tuple ]
132+ tuples : list [Tuple ]
135133
136134
137135class TupleDeleteResult (PangeaResponseResult ):
138136 pass
139137
140138
141- class CheckRequest (APIRequestModel ):
142- resource : Resource
143- action : str
144- subject : Subject
145- debug : Optional [bool ] = None
146- """In the event of an allowed check, return a path that granted access."""
147- attributes : Optional [Dict [str , Any ]] = None
148- """A JSON object of attribute data."""
149-
150-
151139class DebugPath (APIResponseModel ):
152- type : str
153- id : str
140+ type : Optional [ str ] = None
141+ id : Optional [ str ] = None
154142 action : Optional [str ] = None
155143
156144
157145class Debug (APIResponseModel ):
158- path : List [DebugPath ]
146+ path : list [DebugPath ]
159147
160148
161149class CheckResult (PangeaResponseResult ):
@@ -170,23 +158,23 @@ class ListResourcesRequest(APIRequestModel):
170158 type : str
171159 action : str
172160 subject : Subject
173- attributes : Optional [Dict [str , Any ]] = None
161+ attributes : Optional [dict [str , Any ]] = None
174162
175163
176164class ListResourcesResult (PangeaResponseResult ):
177- ids : List [str ]
165+ ids : list [str ]
178166
179167
180168class ListSubjectsRequest (APIRequestModel ):
181169 resource : Resource
182170 action : str
183- attributes : Optional [Dict [str , Any ]] = None
171+ attributes : Optional [dict [str , Any ]] = None
184172 debug : Optional [bool ] = None
185173 """Return a path for each found subject"""
186174
187175
188176class ListSubjectsResult (PangeaResponseResult ):
189- subjects : List [Subject ]
177+ subjects : list [Subject ]
190178
191179
192180class AuthZ (ServiceBase ):
@@ -232,7 +220,7 @@ def __init__(
232220
233221 super ().__init__ (token , config , logger_name , config_id = config_id )
234222
235- def tuple_create (self , tuples : list [Tuple ]) -> PangeaResponse [TupleCreateResult ]:
223+ def tuple_create (self , tuples : Sequence [Tuple ]) -> PangeaResponse [TupleCreateResult ]:
236224 """Create tuples.
237225
238226 Create tuples in the AuthZ Service. The request will fail if there is no schema
@@ -261,8 +249,7 @@ def tuple_create(self, tuples: list[Tuple]) -> PangeaResponse[TupleCreateResult]
261249 )
262250 """
263251
264- input_data = TupleCreateRequest (tuples = tuples )
265- return self .request .post ("v1/tuple/create" , TupleCreateResult , data = input_data .model_dump (exclude_none = True ))
252+ return self .request .post ("v1/tuple/create" , TupleCreateResult , data = {"tuples" : tuples })
266253
267254 def tuple_list (
268255 self ,
@@ -337,8 +324,9 @@ def check(
337324 resource : Resource ,
338325 action : str ,
339326 subject : Subject ,
327+ * ,
340328 debug : bool | None = None ,
341- attributes : dict [str , Any ] | None = None ,
329+ attributes : Mapping [str , Any ] | None = None ,
342330 ) -> PangeaResponse [CheckResult ]:
343331 """Perform a check request.
344332
@@ -349,7 +337,7 @@ def check(
349337 action: The action to check.
350338 subject: The subject to check.
351339 debug: In the event of an allowed check, return a path that granted access.
352- attributes: Additional attributes for the check .
340+ attributes: A JSON object of attribute data .
353341
354342 Raises:
355343 PangeaAPIException: If an API Error happens.
@@ -368,8 +356,11 @@ def check(
368356 )
369357 """
370358
371- input_data = CheckRequest (resource = resource , action = action , subject = subject , debug = debug , attributes = attributes )
372- return self .request .post ("v1/check" , CheckResult , data = input_data .model_dump (exclude_none = True ))
359+ return self .request .post (
360+ "v1/check" ,
361+ CheckResult ,
362+ data = {"resource" : resource , "action" : action , "subject" : subject , "debug" : debug , "attributes" : attributes },
363+ )
373364
374365 def list_resources (
375366 self , type : str , action : str , subject : Subject , attributes : dict [str , Any ] | None = None
0 commit comments