Skip to content

Commit ba0c7cc

Browse files
committed
Add warnings to FGA check / query response
1 parent 17e86c6 commit ba0c7cc

File tree

4 files changed

+113
-4
lines changed

4 files changed

+113
-4
lines changed

tests/test_fga.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,89 @@ def test_get_resource_401(self, mock_http_client_with_response):
101101
self.fga.get_resource(resource_type="test", resource_id="test")
102102

103103

104+
class TestWarnings:
105+
@pytest.fixture(autouse=True)
106+
def setup(self, sync_http_client_for_test):
107+
self.http_client = sync_http_client_for_test
108+
self.fga = FGA(http_client=self.http_client)
109+
110+
@pytest.fixture
111+
def mock_check_warning_response(self):
112+
return {
113+
"result": "authorized",
114+
"is_implicit": True,
115+
"warnings": [
116+
{
117+
"code": "missing_context_keys",
118+
"message": "Missing context keys",
119+
"keys": ["key1", "key2"],
120+
}
121+
],
122+
}
123+
124+
@pytest.fixture
125+
def mock_query_warning_response(self):
126+
return {
127+
"object": "list",
128+
"data": [
129+
{
130+
"resource_type": "user",
131+
"resource_id": "richard",
132+
"relation": "member",
133+
"warrant": {
134+
"resource_type": "role",
135+
"resource_id": "developer",
136+
"relation": "member",
137+
"subject": {"resource_type": "user", "resource_id": "richard"},
138+
},
139+
"is_implicit": True,
140+
}
141+
],
142+
"list_metadata": {},
143+
"warnings": [
144+
{
145+
"code": "missing_context_keys",
146+
"message": "Missing context keys",
147+
"keys": ["key1", "key2"],
148+
}
149+
],
150+
}
151+
152+
def test_check_with_warning(
153+
self, mock_check_warning_response, mock_http_client_with_response
154+
):
155+
mock_http_client_with_response(
156+
self.http_client, mock_check_warning_response, 200
157+
)
158+
159+
response = self.fga.check(
160+
op="any_of",
161+
checks=[
162+
WarrantCheckInput(
163+
resource_type="schedule",
164+
resource_id="schedule-A1",
165+
relation="viewer",
166+
subject=SubjectInput(resource_type="user", resource_id="user-A"),
167+
)
168+
],
169+
)
170+
assert response.dict(exclude_none=True) == mock_check_warning_response
171+
172+
def test_query_with_warning(
173+
self, mock_query_warning_response, mock_http_client_with_response
174+
):
175+
mock_http_client_with_response(
176+
self.http_client, mock_query_warning_response, 200
177+
)
178+
179+
response = self.fga.query(
180+
q="select member of type user for permission:view-docs",
181+
order="asc",
182+
warrant_token="warrant_token",
183+
)
184+
assert response.dict(exclude_none=True) == mock_query_warning_response
185+
186+
104187
class TestFGA:
105188
@pytest.fixture(autouse=True)
106189
def setup(self, sync_http_client_for_test):

workos/fga.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
WarrantWrite,
1111
WarrantWriteOperation,
1212
WriteWarrantResponse,
13-
WarrantQueryResult,
13+
WarrantQueryResult, FGAWarning,
1414
)
1515
from workos.types.fga.list_filters import (
1616
AuthorizationResourceListFilters,
@@ -45,9 +45,11 @@
4545

4646
WarrantListResource = WorkOSListResource[Warrant, WarrantListFilters, ListMetadata]
4747

48-
WarrantQueryListResource = WorkOSListResource[
49-
WarrantQueryResult, WarrantQueryListFilters, ListMetadata
50-
]
48+
49+
class WarrantQueryListResource(WorkOSListResource[
50+
WarrantQueryResult, WarrantQueryListFilters, ListMetadata
51+
]):
52+
warnings: Optional[Sequence[FGAWarning]] = None
5153

5254

5355
class FGAModule(Protocol):
@@ -641,5 +643,6 @@ def query(
641643
return WarrantQueryListResource(
642644
list_method=self.query,
643645
list_args=list_params,
646+
warnings=response.get("warnings"),
644647
**ListPage[WarrantQueryResult](**response).model_dump(),
645648
)

workos/types/fga/check.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from workos.types.workos_model import WorkOSModel
44
from workos.typing.literals import LiteralOrUntyped
55

6+
from .warnings import FGAWarning
67
from .warrant import Subject, SubjectInput
78

89
CheckOperation = Literal["any_of", "all_of", "batch"]
@@ -44,6 +45,7 @@ class CheckResponse(WorkOSModel):
4445
result: LiteralOrUntyped[CheckResult]
4546
is_implicit: bool
4647
debug_info: Optional[DebugInfo] = None
48+
warnings: Optional[Sequence[FGAWarning]] = None
4749

4850
def authorized(self) -> bool:
4951
return self.result == "authorized"

workos/types/fga/warnings.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from typing import Sequence, Union, Literal, Annotated
2+
3+
from pydantic import Field
4+
5+
from workos.types.workos_model import WorkOSModel
6+
7+
8+
class FGABaseWarning(WorkOSModel):
9+
code: str
10+
message: str
11+
12+
13+
class MissingContextKeysWarning(FGABaseWarning):
14+
code: Literal["missing_context_keys"]
15+
keys: Sequence[str]
16+
17+
18+
FGAWarning = Annotated[
19+
Union[MissingContextKeysWarning, FGABaseWarning],
20+
Field(discriminator='type')
21+
]

0 commit comments

Comments
 (0)