opensecureconf-client 1.0.1__tar.gz → 1.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensecureconf-client
3
- Version: 1.0.1
3
+ Version: 1.0.2
4
4
  Summary: Python client library for OpenSecureConf encrypted configuration management API
5
5
  Author-email: Alessandro Pioli <alessandro.pioli+apioli-pypi@gmail.com>
6
6
  Maintainer-email: Alessandro Pioli <alessandro.pioli+apioli-pypi@gmail.com>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opensecureconf-client
3
- Version: 1.0.1
3
+ Version: 1.0.2
4
4
  Summary: Python client library for OpenSecureConf encrypted configuration management API
5
5
  Author-email: Alessandro Pioli <alessandro.pioli+apioli-pypi@gmail.com>
6
6
  Maintainer-email: Alessandro Pioli <alessandro.pioli+apioli-pypi@gmail.com>
@@ -5,29 +5,26 @@ A Python client library for interacting with the OpenSecureConf API,
5
5
  which provides encrypted configuration management with multithreading support.
6
6
  """
7
7
 
8
+ from typing import Any, Dict, List, Optional
9
+
8
10
  import requests
9
- from typing import Optional, Dict, Any, List
10
- from requests.exceptions import RequestException, HTTPError, ConnectionError, Timeout
11
+ from requests.exceptions import Timeout
11
12
 
12
13
 
13
14
  class OpenSecureConfError(Exception):
14
15
  """Base exception for OpenSecureConf client errors."""
15
- pass
16
16
 
17
17
 
18
18
  class AuthenticationError(OpenSecureConfError):
19
19
  """Raised when authentication fails (invalid or missing user key)."""
20
- pass
21
20
 
22
21
 
23
22
  class ConfigurationNotFoundError(OpenSecureConfError):
24
23
  """Raised when a requested configuration key does not exist."""
25
- pass
26
24
 
27
25
 
28
26
  class ConfigurationExistsError(OpenSecureConfError):
29
27
  """Raised when attempting to create a configuration that already exists."""
30
- pass
31
28
 
32
29
 
33
30
  class OpenSecureConfClient:
@@ -40,12 +37,14 @@ class OpenSecureConfClient:
40
37
  Attributes:
41
38
  base_url (str): The base URL of the OpenSecureConf API server.
42
39
  user_key (str): The encryption key used for authentication and encryption/decryption.
40
+ api_key (Optional[str]): Optional API key for additional authentication.
43
41
  timeout (int): Request timeout in seconds.
44
42
 
45
43
  Example:
46
44
  >>> client = OpenSecureConfClient(
47
45
  ... base_url="http://localhost:9000",
48
- ... user_key="my-secret-key-123"
46
+ ... user_key="my-secret-key-123",
47
+ ... api_key="optional-api-key"
49
48
  ... )
50
49
  >>> config = client.create("database", {"host": "localhost", "port": 5432})
51
50
  >>> print(config["value"])
@@ -56,6 +55,7 @@ class OpenSecureConfClient:
56
55
  self,
57
56
  base_url: str,
58
57
  user_key: str,
58
+ api_key: Optional[str] = None,
59
59
  timeout: int = 30,
60
60
  verify_ssl: bool = True
61
61
  ):
@@ -65,6 +65,7 @@ class OpenSecureConfClient:
65
65
  Args:
66
66
  base_url: The base URL of the OpenSecureConf API (e.g., "http://localhost:9000")
67
67
  user_key: User encryption key for authentication (minimum 8 characters)
68
+ api_key: Optional API key for additional authentication
68
69
  timeout: Request timeout in seconds (default: 30)
69
70
  verify_ssl: Whether to verify SSL certificates (default: True)
70
71
 
@@ -76,20 +77,24 @@ class OpenSecureConfClient:
76
77
 
77
78
  self.base_url = base_url.rstrip("/")
78
79
  self.user_key = user_key
80
+ self.api_key = api_key
79
81
  self.timeout = timeout
80
82
  self.verify_ssl = verify_ssl
81
83
  self._session = requests.Session()
82
- self._session.headers.update({
83
- "x-user-key": self.user_key,
84
+
85
+ # Setup headers
86
+ headers = {
87
+ "x-user-key": self.user_key,
84
88
  "Content-Type": "application/json"
85
- })
89
+ }
86
90
 
87
- def _make_request(
88
- self,
89
- method: str,
90
- endpoint: str,
91
- **kwargs
92
- ) -> Any:
91
+ # Add X-API-Key header if api_key is provided
92
+ if self.api_key:
93
+ headers["X-API-Key"] = self.api_key
94
+
95
+ self._session.headers.update(headers)
96
+
97
+ def _make_request(self, method: str, endpoint: str, **kwargs) -> Any:
93
98
  """
94
99
  Make an HTTP request to the API with error handling.
95
100
 
@@ -116,17 +121,21 @@ class OpenSecureConfClient:
116
121
  response = self._session.request(method, url, **kwargs)
117
122
 
118
123
  if response.status_code == 401:
119
- raise AuthenticationError("Authentication failed: invalid or missing user key")
120
- elif response.status_code == 404:
124
+ raise AuthenticationError(
125
+ "Authentication failed: invalid or missing user key"
126
+ )
127
+ if response.status_code == 404:
121
128
  raise ConfigurationNotFoundError("Configuration not found")
122
- elif response.status_code == 400:
129
+ if response.status_code == 400:
123
130
  error_detail = response.json().get("detail", "Bad request")
124
131
  if "already exists" in error_detail.lower():
125
132
  raise ConfigurationExistsError(error_detail)
126
133
  raise OpenSecureConfError(f"Bad request: {error_detail}")
127
- elif response.status_code >= 400:
134
+ if response.status_code >= 400:
128
135
  error_detail = response.json().get("detail", "Unknown error")
129
- raise OpenSecureConfError(f"API error ({response.status_code}): {error_detail}")
136
+ raise OpenSecureConfError(
137
+ f"API error ({response.status_code}): {error_detail}"
138
+ )
130
139
 
131
140
  if response.status_code == 204 or not response.content:
132
141
  return None
@@ -134,9 +143,11 @@ class OpenSecureConfClient:
134
143
  return response.json()
135
144
 
136
145
  except (ConnectionError, Timeout) as e:
137
- raise ConnectionError(f"Failed to connect to {self.base_url}: {str(e)}")
146
+ raise ConnectionError(
147
+ f"Failed to connect to {self.base_url}: {str(e)}"
148
+ ) from e
138
149
  except ValueError as e:
139
- raise OpenSecureConfError(f"Invalid JSON response: {str(e)}")
150
+ raise OpenSecureConfError(f"Invalid JSON response: {str(e)}") from e
140
151
 
141
152
  def get_service_info(self) -> Dict[str, Any]:
142
153
  """
@@ -153,10 +164,7 @@ class OpenSecureConfClient:
153
164
  return self._make_request("GET", "/")
154
165
 
155
166
  def create(
156
- self,
157
- key: str,
158
- value: Dict[str, Any],
159
- category: Optional[str] = None
167
+ self, key: str, value: Dict[str, Any], category: Optional[str] = None
160
168
  ) -> Dict[str, Any]:
161
169
  """
162
170
  Create a new encrypted configuration entry.
@@ -187,11 +195,7 @@ class OpenSecureConfClient:
187
195
  if not key or len(key) > 255:
188
196
  raise ValueError("Key must be between 1 and 255 characters")
189
197
 
190
- payload = {
191
- "key": key,
192
- "value": value,
193
- "category": category
194
- }
198
+ payload = {"key": key, "value": value, "category": category}
195
199
 
196
200
  return self._make_request("POST", "/configs", json=payload)
197
201
 
@@ -216,10 +220,7 @@ class OpenSecureConfClient:
216
220
  return self._make_request("GET", f"/configs/{key}")
217
221
 
218
222
  def update(
219
- self,
220
- key: str,
221
- value: Dict[str, Any],
222
- category: Optional[str] = None
223
+ self, key: str, value: Dict[str, Any], category: Optional[str] = None
223
224
  ) -> Dict[str, Any]:
224
225
  """
225
226
  Update an existing configuration entry with new encrypted value.
@@ -241,10 +242,7 @@ class OpenSecureConfClient:
241
242
  ... value={"host": "db.example.com", "port": 5432}
242
243
  ... )
243
244
  """
244
- payload = {
245
- "value": value,
246
- "category": category
247
- }
245
+ payload = {"value": value, "category": category}
248
246
 
249
247
  return self._make_request("PUT", f"/configs/{key}", json=payload)
250
248
 
@@ -312,5 +310,5 @@ __all__ = [
312
310
  "OpenSecureConfError",
313
311
  "AuthenticationError",
314
312
  "ConfigurationNotFoundError",
315
- "ConfigurationExistsError"
313
+ "ConfigurationExistsError",
316
314
  ]
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opensecureconf-client"
7
- version = "1.0.1"
7
+ version = "1.0.2"
8
8
  description = "Python client library for OpenSecureConf encrypted configuration management API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -2,6 +2,7 @@
2
2
  Setup script for backward compatibility.
3
3
  Modern projects should use pyproject.toml instead.
4
4
  """
5
+
5
6
  from setuptools import setup
6
7
 
7
8
  setup()