opa-python-client 2.0.0__tar.gz → 2.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/PKG-INFO +9 -3
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/README.md +6 -1
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/__init__.py +1 -1
- opa_python_client-2.0.2/opa_client/base.py +147 -0
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/opa.py +13 -97
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/pyproject.toml +2 -2
- opa_python_client-2.0.0/opa_client/base.py +0 -286
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/LICENCE.md +0 -0
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/errors.py +0 -0
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/opa_async.py +0 -0
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/test/__init__.py +0 -0
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/test/test_async_client.py +0 -0
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/test/test_integaration_opa.py +0 -0
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/test/test_opa.py +0 -0
- {opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/test/test_opa_client.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: opa-python-client
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Client for connection to the OPA service
|
|
5
5
|
Home-page: https://github.com/Turall/OPA-python-client
|
|
6
6
|
License: MIT
|
|
7
7
|
Author: Tural Muradov
|
|
8
|
-
Author-email:
|
|
8
|
+
Author-email: tural.muradoov@gmail.com
|
|
9
9
|
Requires-Python: >=3.9,<4.0
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
20
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
21
|
Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
|
|
21
22
|
Requires-Dist: aiohttp[speedups] (>=3.10.9,<4.0.0)
|
|
@@ -25,6 +26,11 @@ Description-Content-Type: text/markdown
|
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
# OpaClient - Open Policy Agent Python Client
|
|
29
|
+
[](https://raw.githubusercontent.com/Turall/OPA-python-client/master/LICENSE)
|
|
30
|
+
[](https://github.com/Turall/OPA-python-client/stargazers)
|
|
31
|
+
[](https://github.com/Turall/OPA-python-client/network)
|
|
32
|
+
[](https://github.com/Turall/OPA-python-client/issues)
|
|
33
|
+
[](https://pepy.tech/project/opa-python-client)
|
|
28
34
|
|
|
29
35
|
OpaClient is a Python client library designed to interact with the [Open Policy Agent (OPA)](https://www.openpolicyagent.org/). It supports both **synchronous** and **asynchronous** requests, making it easy to manage policies, data, and evaluate rules in OPA servers.
|
|
30
36
|
|
|
@@ -42,7 +48,7 @@ OpaClient is a Python client library designed to interact with the [Open Policy
|
|
|
42
48
|
You can install the OpaClient package via `pip`:
|
|
43
49
|
|
|
44
50
|
```bash
|
|
45
|
-
pip install
|
|
51
|
+
pip install opa-python-client
|
|
46
52
|
```
|
|
47
53
|
|
|
48
54
|
## Quick Start
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
# OpaClient - Open Policy Agent Python Client
|
|
3
|
+
[](https://raw.githubusercontent.com/Turall/OPA-python-client/master/LICENSE)
|
|
4
|
+
[](https://github.com/Turall/OPA-python-client/stargazers)
|
|
5
|
+
[](https://github.com/Turall/OPA-python-client/network)
|
|
6
|
+
[](https://github.com/Turall/OPA-python-client/issues)
|
|
7
|
+
[](https://pepy.tech/project/opa-python-client)
|
|
3
8
|
|
|
4
9
|
OpaClient is a Python client library designed to interact with the [Open Policy Agent (OPA)](https://www.openpolicyagent.org/). It supports both **synchronous** and **asynchronous** requests, making it easy to manage policies, data, and evaluate rules in OPA servers.
|
|
5
10
|
|
|
@@ -17,7 +22,7 @@ OpaClient is a Python client library designed to interact with the [Open Policy
|
|
|
17
22
|
You can install the OpaClient package via `pip`:
|
|
18
23
|
|
|
19
24
|
```bash
|
|
20
|
-
pip install
|
|
25
|
+
pip install opa-python-client
|
|
21
26
|
```
|
|
22
27
|
|
|
23
28
|
## Quick Start
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Dict, Optional, Union
|
|
3
|
+
from urllib.parse import urlencode
|
|
4
|
+
|
|
5
|
+
from .errors import (
|
|
6
|
+
FileError,
|
|
7
|
+
PathNotFoundError,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseClient:
|
|
12
|
+
"""
|
|
13
|
+
Base class for OpaClient implementations.
|
|
14
|
+
|
|
15
|
+
This class contains common logic shared between synchronous and asynchronous clients.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
host: str = "localhost",
|
|
21
|
+
port: int = 8181,
|
|
22
|
+
version: str = "v1",
|
|
23
|
+
ssl: bool = False,
|
|
24
|
+
cert: Optional[Union[str, tuple]] = None,
|
|
25
|
+
headers: Optional[dict] = None,
|
|
26
|
+
timeout: float = 1.5,
|
|
27
|
+
):
|
|
28
|
+
if not isinstance(port, int):
|
|
29
|
+
raise TypeError("The port must be an integer")
|
|
30
|
+
|
|
31
|
+
self.host = host.strip()
|
|
32
|
+
self.port = port
|
|
33
|
+
self.version = version
|
|
34
|
+
self.ssl = ssl
|
|
35
|
+
self.cert = cert
|
|
36
|
+
self.timeout = timeout
|
|
37
|
+
|
|
38
|
+
self.schema = "https://" if ssl else "http://"
|
|
39
|
+
self.root_url = f"{self.schema}{self.host}:{self.port}/{self.version}"
|
|
40
|
+
|
|
41
|
+
self.headers = headers
|
|
42
|
+
|
|
43
|
+
self._session = None # Will be initialized in the subclass
|
|
44
|
+
self.retries = 2
|
|
45
|
+
self.timeout = 1.5
|
|
46
|
+
|
|
47
|
+
def _build_url(
|
|
48
|
+
self, path: str, query_params: Dict[str, str] = None
|
|
49
|
+
) -> str:
|
|
50
|
+
url = f"{self.root_url}/{path.lstrip('/')}"
|
|
51
|
+
if query_params:
|
|
52
|
+
url = f"{url}?{urlencode(query_params)}"
|
|
53
|
+
return url
|
|
54
|
+
|
|
55
|
+
def _load_policy_from_file(self, filepath: str) -> str:
|
|
56
|
+
if not os.path.isfile(filepath):
|
|
57
|
+
raise FileError(f"'{filepath}' is not a valid file")
|
|
58
|
+
with open(filepath, "r", encoding="utf-8") as file:
|
|
59
|
+
return file.read()
|
|
60
|
+
|
|
61
|
+
def _save_policy_to_file(
|
|
62
|
+
self, policy_raw: str, path: Optional[str], filename: str
|
|
63
|
+
) -> bool:
|
|
64
|
+
full_path = os.path.join(path or "", filename)
|
|
65
|
+
try:
|
|
66
|
+
with open(full_path, "w", encoding="utf-8") as file:
|
|
67
|
+
file.write(policy_raw)
|
|
68
|
+
return True
|
|
69
|
+
except OSError as e:
|
|
70
|
+
raise PathNotFoundError(f"Failed to write to '{full_path}'") from e
|
|
71
|
+
|
|
72
|
+
# Abstract methods to be implemented in subclasses
|
|
73
|
+
def close_connection(self):
|
|
74
|
+
raise NotImplementedError
|
|
75
|
+
|
|
76
|
+
def check_connection(self) -> str:
|
|
77
|
+
raise NotImplementedError
|
|
78
|
+
|
|
79
|
+
def _init_session(self):
|
|
80
|
+
raise NotImplementedError
|
|
81
|
+
|
|
82
|
+
def check_health(
|
|
83
|
+
self, query: Dict[str, bool] = None, diagnostic_url: str = None
|
|
84
|
+
) -> bool:
|
|
85
|
+
raise NotImplementedError
|
|
86
|
+
|
|
87
|
+
def get_policies_list(self) -> list:
|
|
88
|
+
raise NotImplementedError
|
|
89
|
+
|
|
90
|
+
def get_policies_info(self) -> dict:
|
|
91
|
+
raise NotImplementedError
|
|
92
|
+
|
|
93
|
+
def update_policy_from_string(
|
|
94
|
+
self, new_policy: str, endpoint: str
|
|
95
|
+
) -> bool:
|
|
96
|
+
raise NotImplementedError
|
|
97
|
+
|
|
98
|
+
def update_policy_from_file(self, filepath: str, endpoint: str) -> bool:
|
|
99
|
+
raise NotImplementedError
|
|
100
|
+
|
|
101
|
+
def update_policy_from_url(self, url: str, endpoint: str) -> bool:
|
|
102
|
+
raise NotImplementedError
|
|
103
|
+
|
|
104
|
+
def update_or_create_data(self, new_data: dict, endpoint: str) -> bool:
|
|
105
|
+
raise NotImplementedError
|
|
106
|
+
|
|
107
|
+
def get_data(
|
|
108
|
+
self, data_name: str = "", query_params: Dict[str, bool] = None
|
|
109
|
+
) -> dict:
|
|
110
|
+
raise NotImplementedError
|
|
111
|
+
|
|
112
|
+
def policy_to_file(
|
|
113
|
+
self,
|
|
114
|
+
policy_name: str,
|
|
115
|
+
path: Optional[str] = None,
|
|
116
|
+
filename: str = "opa_policy.rego",
|
|
117
|
+
) -> bool:
|
|
118
|
+
raise NotImplementedError
|
|
119
|
+
|
|
120
|
+
def get_policy(self, policy_name: str) -> dict:
|
|
121
|
+
raise NotImplementedError
|
|
122
|
+
|
|
123
|
+
def delete_policy(self, policy_name: str) -> bool:
|
|
124
|
+
raise NotImplementedError
|
|
125
|
+
|
|
126
|
+
def delete_data(self, data_name: str) -> bool:
|
|
127
|
+
raise NotImplementedError
|
|
128
|
+
|
|
129
|
+
def check_permission(
|
|
130
|
+
self,
|
|
131
|
+
input_data: dict,
|
|
132
|
+
policy_name: str,
|
|
133
|
+
rule_name: str,
|
|
134
|
+
query_params: Dict[str, bool] = None,
|
|
135
|
+
) -> dict:
|
|
136
|
+
raise NotImplementedError
|
|
137
|
+
|
|
138
|
+
def query_rule(
|
|
139
|
+
self,
|
|
140
|
+
input_data: dict,
|
|
141
|
+
package_path: str,
|
|
142
|
+
rule_name: Optional[str] = None,
|
|
143
|
+
) -> dict:
|
|
144
|
+
raise NotImplementedError
|
|
145
|
+
|
|
146
|
+
def ad_hoc_query(self, query: str, input_data: dict = None) -> dict:
|
|
147
|
+
raise NotImplementedError
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import os
|
|
3
2
|
import threading
|
|
4
3
|
from typing import Dict, Optional
|
|
@@ -10,15 +9,15 @@ from urllib3.util.retry import Retry
|
|
|
10
9
|
|
|
11
10
|
from .base import BaseClient
|
|
12
11
|
from .errors import (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
CheckPermissionError,
|
|
13
|
+
ConnectionsError,
|
|
14
|
+
DeleteDataError,
|
|
15
|
+
DeletePolicyError,
|
|
16
|
+
FileError,
|
|
17
|
+
PathNotFoundError,
|
|
18
|
+
PolicyNotFoundError,
|
|
19
|
+
RegoParseError,
|
|
20
|
+
TypeException,
|
|
22
21
|
)
|
|
23
22
|
|
|
24
23
|
|
|
@@ -202,7 +201,7 @@ class OpaClient(BaseClient):
|
|
|
202
201
|
bool: True if the policy was successfully updated.
|
|
203
202
|
"""
|
|
204
203
|
if not os.path.isfile(filepath):
|
|
205
|
-
raise FileError(f"'{filepath}' is not a valid file")
|
|
204
|
+
raise FileError("file_not_found",f"'{filepath}' is not a valid file")
|
|
206
205
|
|
|
207
206
|
with open(filepath, "r", encoding="utf-8") as file:
|
|
208
207
|
policy_str = file.read()
|
|
@@ -300,7 +299,7 @@ class OpaClient(BaseClient):
|
|
|
300
299
|
policy_raw = policy.get("result", {}).get("raw", "")
|
|
301
300
|
|
|
302
301
|
if not policy_raw:
|
|
303
|
-
raise PolicyNotFoundError("Policy content is empty")
|
|
302
|
+
raise PolicyNotFoundError("resource_not_found", "Policy content is empty")
|
|
304
303
|
|
|
305
304
|
full_path = os.path.join(path or "", filename)
|
|
306
305
|
|
|
@@ -309,7 +308,7 @@ class OpaClient(BaseClient):
|
|
|
309
308
|
file.write(policy_raw)
|
|
310
309
|
return True
|
|
311
310
|
except OSError as e:
|
|
312
|
-
raise PathNotFoundError(f"Failed to write to '{full_path}'") from e
|
|
311
|
+
raise PathNotFoundError("path_not_found", f"Failed to write to '{full_path}'") from e
|
|
313
312
|
|
|
314
313
|
def get_policy(self, policy_name: str) -> dict:
|
|
315
314
|
"""
|
|
@@ -395,7 +394,7 @@ class OpaClient(BaseClient):
|
|
|
395
394
|
|
|
396
395
|
if rule_name not in rules:
|
|
397
396
|
raise CheckPermissionError(
|
|
398
|
-
f"Rule '{rule_name}' not found in policy '{policy_name}'"
|
|
397
|
+
"resource_not_found", f"Rule '{rule_name}' not found in policy '{policy_name}'"
|
|
399
398
|
)
|
|
400
399
|
|
|
401
400
|
url = f"{self.root_url}/{package_path}/{rule_name}"
|
|
@@ -456,89 +455,6 @@ class OpaClient(BaseClient):
|
|
|
456
455
|
response.raise_for_status()
|
|
457
456
|
return response.json()
|
|
458
457
|
|
|
459
|
-
# # Property methods for read-only access to certain attributes
|
|
460
|
-
# @property
|
|
461
|
-
# def host(self) -> str:
|
|
462
|
-
# return self._host
|
|
463
|
-
|
|
464
|
-
# @host.setter
|
|
465
|
-
# def host(self, value: str):
|
|
466
|
-
# self._host = value
|
|
467
|
-
|
|
468
|
-
# @property
|
|
469
|
-
# def port(self) -> int:
|
|
470
|
-
# return self._port
|
|
471
|
-
|
|
472
|
-
# @port.setter
|
|
473
|
-
# def port(self, value: int):
|
|
474
|
-
# if not isinstance(value, int):
|
|
475
|
-
# raise TypeError('Port must be an integer')
|
|
476
|
-
# self._port = value
|
|
477
|
-
|
|
478
|
-
# @property
|
|
479
|
-
# def version(self) -> str:
|
|
480
|
-
# return self._version
|
|
481
|
-
|
|
482
|
-
# @version.setter
|
|
483
|
-
# def version(self, value: str):
|
|
484
|
-
# self._version = value
|
|
485
|
-
|
|
486
|
-
# @property
|
|
487
|
-
# def schema(self) -> str:
|
|
488
|
-
# return self._schema
|
|
489
|
-
|
|
490
|
-
# @schema.setter
|
|
491
|
-
# def schema(self, value: str):
|
|
492
|
-
# self._schema = value
|
|
493
|
-
|
|
494
|
-
# @property
|
|
495
|
-
# def root_url(self) -> str:
|
|
496
|
-
# return self._root_url
|
|
497
|
-
|
|
498
|
-
# @root_url.setter
|
|
499
|
-
# def root_url(self, value: str):
|
|
500
|
-
# self._root_url = value
|
|
501
|
-
|
|
502
|
-
# @property
|
|
503
|
-
# def ssl(self) -> bool:
|
|
504
|
-
# return self._ssl
|
|
505
|
-
|
|
506
|
-
# @ssl.setter
|
|
507
|
-
# def ssl(self, value: bool):
|
|
508
|
-
# self._ssl = value
|
|
509
|
-
|
|
510
|
-
# @property
|
|
511
|
-
# def cert(self) -> Optional[str]:
|
|
512
|
-
# return self._cert
|
|
513
|
-
|
|
514
|
-
# @cert.setter
|
|
515
|
-
# def cert(self, value: Optional[str]):
|
|
516
|
-
# self._cert = value
|
|
517
|
-
|
|
518
|
-
# @property
|
|
519
|
-
# def headers(self) -> dict:
|
|
520
|
-
# return self._headers
|
|
521
|
-
|
|
522
|
-
# @headers.setter
|
|
523
|
-
# def headers(self, value: dict):
|
|
524
|
-
# self._headers = value
|
|
525
|
-
|
|
526
|
-
# @property
|
|
527
|
-
# def retries(self) -> int:
|
|
528
|
-
# return self._retries
|
|
529
|
-
|
|
530
|
-
# @retries.setter
|
|
531
|
-
# def retries(self, value: int):
|
|
532
|
-
# self._retries = value
|
|
533
|
-
|
|
534
|
-
# @property
|
|
535
|
-
# def timeout(self) -> float:
|
|
536
|
-
# return self._timeout
|
|
537
|
-
|
|
538
|
-
# @timeout.setter
|
|
539
|
-
# def timeout(self, value: float):
|
|
540
|
-
# self._timeout = value
|
|
541
|
-
|
|
542
458
|
|
|
543
459
|
# Example usage:
|
|
544
460
|
if __name__ == "__main__":
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "opa-python-client"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.2"
|
|
4
4
|
description = "Client for connection to the OPA service"
|
|
5
|
-
authors = ["Tural Muradov <
|
|
5
|
+
authors = ["Tural Muradov <tural.muradoov@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
homepage = "https://github.com/Turall/OPA-python-client"
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from typing import Dict, Optional, Union
|
|
3
|
-
from urllib.parse import urlencode
|
|
4
|
-
|
|
5
|
-
from .errors import (
|
|
6
|
-
FileError,
|
|
7
|
-
PathNotFoundError,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class BaseClient:
|
|
12
|
-
"""
|
|
13
|
-
Base class for OpaClient implementations.
|
|
14
|
-
|
|
15
|
-
This class contains common logic shared between synchronous and asynchronous clients.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
def __init__(
|
|
19
|
-
self,
|
|
20
|
-
host: str = "localhost",
|
|
21
|
-
port: int = 8181,
|
|
22
|
-
version: str = "v1",
|
|
23
|
-
ssl: bool = False,
|
|
24
|
-
cert: Optional[Union[str, tuple]] = None,
|
|
25
|
-
headers: Optional[dict] = None,
|
|
26
|
-
timeout: float = 1.5,
|
|
27
|
-
):
|
|
28
|
-
if not isinstance(port, int):
|
|
29
|
-
raise TypeError("The port must be an integer")
|
|
30
|
-
|
|
31
|
-
self.host = host.strip()
|
|
32
|
-
self.port = port
|
|
33
|
-
self.version = version
|
|
34
|
-
self.ssl = ssl
|
|
35
|
-
self.cert = cert
|
|
36
|
-
self.timeout = timeout
|
|
37
|
-
|
|
38
|
-
self.schema = "https://" if ssl else "http://"
|
|
39
|
-
self.root_url = f"{self.schema}{self.host}:{self.port}/{self.version}"
|
|
40
|
-
|
|
41
|
-
self.headers = headers
|
|
42
|
-
|
|
43
|
-
self._session = None # Will be initialized in the subclass
|
|
44
|
-
self.retries = 2
|
|
45
|
-
self.timeout = 1.5
|
|
46
|
-
|
|
47
|
-
def _build_url(
|
|
48
|
-
self, path: str, query_params: Dict[str, str] = None
|
|
49
|
-
) -> str:
|
|
50
|
-
url = f"{self.root_url}/{path.lstrip('/')}"
|
|
51
|
-
if query_params:
|
|
52
|
-
url = f"{url}?{urlencode(query_params)}"
|
|
53
|
-
return url
|
|
54
|
-
|
|
55
|
-
def _load_policy_from_file(self, filepath: str) -> str:
|
|
56
|
-
if not os.path.isfile(filepath):
|
|
57
|
-
raise FileError(f"'{filepath}' is not a valid file")
|
|
58
|
-
with open(filepath, "r", encoding="utf-8") as file:
|
|
59
|
-
return file.read()
|
|
60
|
-
|
|
61
|
-
def _save_policy_to_file(
|
|
62
|
-
self, policy_raw: str, path: Optional[str], filename: str
|
|
63
|
-
) -> bool:
|
|
64
|
-
full_path = os.path.join(path or "", filename)
|
|
65
|
-
try:
|
|
66
|
-
with open(full_path, "w", encoding="utf-8") as file:
|
|
67
|
-
file.write(policy_raw)
|
|
68
|
-
return True
|
|
69
|
-
except OSError as e:
|
|
70
|
-
raise PathNotFoundError(f"Failed to write to '{full_path}'") from e
|
|
71
|
-
|
|
72
|
-
# Abstract methods to be implemented in subclasses
|
|
73
|
-
def close_connection(self):
|
|
74
|
-
raise NotImplementedError
|
|
75
|
-
|
|
76
|
-
def check_connection(self) -> str:
|
|
77
|
-
raise NotImplementedError
|
|
78
|
-
|
|
79
|
-
def _init_session(self):
|
|
80
|
-
raise NotImplementedError
|
|
81
|
-
|
|
82
|
-
def check_health(
|
|
83
|
-
self, query: Dict[str, bool] = None, diagnostic_url: str = None
|
|
84
|
-
) -> bool:
|
|
85
|
-
raise NotImplementedError
|
|
86
|
-
|
|
87
|
-
def get_policies_list(self) -> list:
|
|
88
|
-
raise NotImplementedError
|
|
89
|
-
|
|
90
|
-
def get_policies_info(self) -> dict:
|
|
91
|
-
raise NotImplementedError
|
|
92
|
-
|
|
93
|
-
def update_policy_from_string(
|
|
94
|
-
self, new_policy: str, endpoint: str
|
|
95
|
-
) -> bool:
|
|
96
|
-
raise NotImplementedError
|
|
97
|
-
|
|
98
|
-
def update_policy_from_file(self, filepath: str, endpoint: str) -> bool:
|
|
99
|
-
raise NotImplementedError
|
|
100
|
-
|
|
101
|
-
def update_policy_from_url(self, url: str, endpoint: str) -> bool:
|
|
102
|
-
raise NotImplementedError
|
|
103
|
-
|
|
104
|
-
def update_or_create_data(self, new_data: dict, endpoint: str) -> bool:
|
|
105
|
-
raise NotImplementedError
|
|
106
|
-
|
|
107
|
-
def get_data(
|
|
108
|
-
self, data_name: str = "", query_params: Dict[str, bool] = None
|
|
109
|
-
) -> dict:
|
|
110
|
-
raise NotImplementedError
|
|
111
|
-
|
|
112
|
-
def policy_to_file(
|
|
113
|
-
self,
|
|
114
|
-
policy_name: str,
|
|
115
|
-
path: Optional[str] = None,
|
|
116
|
-
filename: str = "opa_policy.rego",
|
|
117
|
-
) -> bool:
|
|
118
|
-
raise NotImplementedError
|
|
119
|
-
|
|
120
|
-
def get_policy(self, policy_name: str) -> dict:
|
|
121
|
-
raise NotImplementedError
|
|
122
|
-
|
|
123
|
-
def delete_policy(self, policy_name: str) -> bool:
|
|
124
|
-
raise NotImplementedError
|
|
125
|
-
|
|
126
|
-
def delete_data(self, data_name: str) -> bool:
|
|
127
|
-
raise NotImplementedError
|
|
128
|
-
|
|
129
|
-
def check_permission(
|
|
130
|
-
self,
|
|
131
|
-
input_data: dict,
|
|
132
|
-
policy_name: str,
|
|
133
|
-
rule_name: str,
|
|
134
|
-
query_params: Dict[str, bool] = None,
|
|
135
|
-
) -> dict:
|
|
136
|
-
raise NotImplementedError
|
|
137
|
-
|
|
138
|
-
def query_rule(
|
|
139
|
-
self,
|
|
140
|
-
input_data: dict,
|
|
141
|
-
package_path: str,
|
|
142
|
-
rule_name: Optional[str] = None,
|
|
143
|
-
) -> dict:
|
|
144
|
-
raise NotImplementedError
|
|
145
|
-
|
|
146
|
-
def ad_hoc_query(self, query: str, input_data: dict = None) -> dict:
|
|
147
|
-
raise NotImplementedError
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
# class OpaClient(BaseOpaClient):
|
|
151
|
-
# """
|
|
152
|
-
# Synchronous OpaClient implementation using requests.
|
|
153
|
-
# """
|
|
154
|
-
|
|
155
|
-
# def __init__(self, *args, **kwargs):
|
|
156
|
-
# super().__init__(*args, **kwargs)
|
|
157
|
-
|
|
158
|
-
# self._init_session()
|
|
159
|
-
|
|
160
|
-
# def _init_session(self):
|
|
161
|
-
# self._session = requests.Session()
|
|
162
|
-
# self._session.headers.update(self.headers)
|
|
163
|
-
|
|
164
|
-
# if self.ssl:
|
|
165
|
-
# self._session.verify = self.cert if self.cert else True
|
|
166
|
-
|
|
167
|
-
# # Optionally, configure retries and other session parameters
|
|
168
|
-
|
|
169
|
-
# def close_connection(self):
|
|
170
|
-
# if self._session:
|
|
171
|
-
# self._session.close()
|
|
172
|
-
# self._session = None
|
|
173
|
-
|
|
174
|
-
# def check_connection(self) -> str:
|
|
175
|
-
# url = self._build_url('policies/')
|
|
176
|
-
# try:
|
|
177
|
-
# response = self._session.get(url, timeout=self.timeout)
|
|
178
|
-
# response.raise_for_status()
|
|
179
|
-
# return "Yes, I'm here :)"
|
|
180
|
-
# except requests.exceptions.RequestException as e:
|
|
181
|
-
# raise ConnectionsError('Service unreachable', 'Check config and try again') from e
|
|
182
|
-
|
|
183
|
-
# # Implement other synchronous methods similarly
|
|
184
|
-
# # For example:
|
|
185
|
-
# def get_policies_list(self) -> list:
|
|
186
|
-
# url = self._build_url('policies/')
|
|
187
|
-
# response = self._session.get(url, timeout=self.timeout)
|
|
188
|
-
# response.raise_for_status()
|
|
189
|
-
# policies = response.json().get('result', [])
|
|
190
|
-
# return [policy.get('id') for policy in policies if policy.get('id')]
|
|
191
|
-
|
|
192
|
-
# # ... Rest of synchronous methods ...
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
# class AsyncOpaClient(BaseOpaClient):
|
|
196
|
-
# """
|
|
197
|
-
# Asynchronous OpaClient implementation using aiohttp.
|
|
198
|
-
# """
|
|
199
|
-
|
|
200
|
-
# async def __aenter__(self):
|
|
201
|
-
# await self._init_session()
|
|
202
|
-
# return self
|
|
203
|
-
|
|
204
|
-
# async def __aexit__(self, exc_type, exc_value, traceback):
|
|
205
|
-
# await self.close_connection()
|
|
206
|
-
|
|
207
|
-
# async def _init_session(self):
|
|
208
|
-
# ssl_context = None
|
|
209
|
-
|
|
210
|
-
# if self.ssl:
|
|
211
|
-
# ssl_context = ssl.create_default_context()
|
|
212
|
-
# if self.cert:
|
|
213
|
-
# if isinstance(self.cert, tuple):
|
|
214
|
-
# ssl_context.load_cert_chain(*self.cert)
|
|
215
|
-
# else:
|
|
216
|
-
# ssl_context.load_cert_chain(self.cert)
|
|
217
|
-
# else:
|
|
218
|
-
# ssl_context.load_default_certs()
|
|
219
|
-
|
|
220
|
-
# connector = aiohttp.TCPConnector(ssl=ssl_context)
|
|
221
|
-
|
|
222
|
-
# self._session = aiohttp.ClientSession(
|
|
223
|
-
# headers=self.headers,
|
|
224
|
-
# connector=connector,
|
|
225
|
-
# timeout=aiohttp.ClientTimeout(total=self.timeout),
|
|
226
|
-
# )
|
|
227
|
-
|
|
228
|
-
# async def close_connection(self):
|
|
229
|
-
# if self._session and not self._session.closed:
|
|
230
|
-
# await self._session.close()
|
|
231
|
-
# self._session = None
|
|
232
|
-
|
|
233
|
-
# async def check_connection(self) -> str:
|
|
234
|
-
# url = self._build_url('policies/')
|
|
235
|
-
# try:
|
|
236
|
-
# async with self._session.get(url) as response:
|
|
237
|
-
# if response.status == 200:
|
|
238
|
-
# return "Yes, I'm here :)"
|
|
239
|
-
# else:
|
|
240
|
-
# raise ConnectionsError('Service unreachable', 'Check config and try again')
|
|
241
|
-
# except Exception as e:
|
|
242
|
-
# raise ConnectionsError('Service unreachable', 'Check config and try again') from e
|
|
243
|
-
|
|
244
|
-
# # Implement other asynchronous methods similarly
|
|
245
|
-
# # For example:
|
|
246
|
-
# async def get_policies_list(self) -> list:
|
|
247
|
-
# url = self._build_url('policies/')
|
|
248
|
-
# async with self._session.get(url) as response:
|
|
249
|
-
# response.raise_for_status()
|
|
250
|
-
# policies = await response.json()
|
|
251
|
-
# result = policies.get('result', [])
|
|
252
|
-
# return [policy.get('id') for policy in result if policy.get('id')]
|
|
253
|
-
|
|
254
|
-
# # ... Rest of asynchronous methods ...
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
# # Example usage:
|
|
258
|
-
|
|
259
|
-
# # Synchronous client
|
|
260
|
-
# def sync_example():
|
|
261
|
-
# client = OpaClient(host='localhost', port=8181)
|
|
262
|
-
# try:
|
|
263
|
-
# result = client.check_connection()
|
|
264
|
-
# print(result)
|
|
265
|
-
# policies = client.get_policies_list()
|
|
266
|
-
# print("Policies:", policies)
|
|
267
|
-
# finally:
|
|
268
|
-
# client.close_connection()
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
# # Asynchronous client
|
|
272
|
-
# async def async_example():
|
|
273
|
-
# async with AsyncOpaClient(host='localhost', port=8181) as client:
|
|
274
|
-
# result = await client.check_connection()
|
|
275
|
-
# print(result)
|
|
276
|
-
# policies = await client.get_policies_list()
|
|
277
|
-
# print("Policies:", policies)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
# if __name__ == '__main__':
|
|
281
|
-
# # Run synchronous example
|
|
282
|
-
# sync_example()
|
|
283
|
-
|
|
284
|
-
# # Run asynchronous example
|
|
285
|
-
# import asyncio
|
|
286
|
-
# asyncio.run(async_example())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{opa_python_client-2.0.0 → opa_python_client-2.0.2}/opa_client/test/test_integaration_opa.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|