infisicalsdk 1.0.3__tar.gz → 1.0.4__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.

Potentially problematic release.


This version of infisicalsdk might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: infisicalsdk
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Infisical API Client
5
5
  Home-page: https://github.com/Infisical/python-sdk-official
6
6
  Author: Infisical
@@ -2,18 +2,18 @@
2
2
 
3
3
  The Infisical SDK provides a convenient way to interact with the Infisical API.
4
4
 
5
- ### Migrating to version 1.0.2 or above
5
+ ### Migrating to version 1.0.3 or above
6
6
 
7
- We have recently rolled out our first stable version of the SDK, version `1.0.2` and above.
7
+ We have recently rolled out our first stable version of the SDK, version `1.0.3` and above.
8
8
 
9
- The 1.0.2 version comes with a few key changes that may change how you're using the SDK.
9
+ The 1.0.3 version comes with a few key changes that may change how you're using the SDK.
10
10
  1. **Removal of `rest`**: The SDK no longer exposes the entire Infisical API. This was nessecary as we have moved away from using an OpenAPI generator approach. We aim to add support for more API resources in the near future. If you have any specific requests, please [open an issue](https://github.com/Infisical/python-sdk-official/issues).
11
11
 
12
- 2. **New response types**: The 1.0.2 release uses return types that differ from the older versions. The new return types such as `BaseSecret`, are all exported from the Infisical SDK.
12
+ 2. **New response types**: The 1.0.3 release uses return types that differ from the older versions. The new return types such as `BaseSecret`, are all exported from the Infisical SDK.
13
13
 
14
14
  3. **Property renaming**: Some properties on the responses have been slightly renamed. An example of this would be that the `secret_key` property on the `get_secret_by_name()` method, that has been renamed to `secretKey`.
15
15
 
16
- With this in mind, you're ready to upgrade your SDK version to `1.0.2` or above.
16
+ With this in mind, you're ready to upgrade your SDK version to `1.0.3` or above.
17
17
 
18
18
  You can refer to our [legacy documentation](https://github.com/Infisical/python-sdk-official/tree/9b0403938ee5ae599d42c5f1fdf9158671a15606?tab=readme-ov-file#infisical-python-sdk) if need be.
19
19
 
@@ -36,10 +36,13 @@ from infisical_sdk import InfisicalSDKClient
36
36
  client = InfisicalSDKClient(host="https://app.infisical.com")
37
37
 
38
38
  # Authenticate (example using Universal Auth)
39
- client.auth.universal_auth.login(client_id="your_client_id", client_secret="your_client_secret")
39
+ client.auth.universal_auth.login(
40
+ client_id="<machine-identity-client-id>",
41
+ client_secret="<machine-identity-client-secret>"
42
+ )
40
43
 
41
44
  # Use the SDK to interact with Infisical
42
- secrets = client.secrets.list_secrets(project_id="your_project_id", environment_slug="dev", secret_path="/")
45
+ secrets = client.secrets.list_secrets(project_id="<project-id>", environment_slug="dev", secret_path="/")
43
46
  ```
44
47
 
45
48
  ## Core Methods
@@ -56,13 +59,16 @@ The `Auth` component provides methods for authentication:
56
59
  #### Universal Auth
57
60
 
58
61
  ```python
59
- response = client.auth.universal_auth.login(client_id="your_client_id", client_secret="your_client_secret")
62
+ response = client.auth.universal_auth.login(
63
+ client_id="<machine-identity-client-id>",
64
+ client_secret="<machine-identity-client-secret>"
65
+ )
60
66
  ```
61
67
 
62
68
  #### AWS Auth
63
69
 
64
70
  ```python
65
- response = client.auth.aws_auth.login(identity_id="your_identity_id")
71
+ response = client.auth.aws_auth.login(identity_id="<machine-identity-id>")
66
72
  ```
67
73
 
68
74
  ### `secrets`
@@ -73,7 +79,7 @@ This sub-class handles operations related to secrets:
73
79
 
74
80
  ```python
75
81
  secrets = client.secrets.list_secrets(
76
- project_id="your_project_id",
82
+ project_id="<project-id>",
77
83
  environment_slug="dev",
78
84
  secret_path="/",
79
85
  expand_secret_references=True,
@@ -100,7 +106,7 @@ secrets = client.secrets.list_secrets(
100
106
  ```python
101
107
  new_secret = client.secrets.create_secret_by_name(
102
108
  secret_name="NEW_SECRET",
103
- project_id="your_project_id",
109
+ project_id="<project-id>",
104
110
  secret_path="/",
105
111
  environment_slug="dev",
106
112
  secret_value="secret_value",
@@ -130,7 +136,7 @@ new_secret = client.secrets.create_secret_by_name(
130
136
  ```python
131
137
  updated_secret = client.secrets.update_secret_by_name(
132
138
  current_secret_name="EXISTING_SECRET",
133
- project_id="your_project_id",
139
+ project_id="<project-id>",
134
140
  secret_path="/",
135
141
  environment_slug="dev",
136
142
  secret_value="new_secret_value",
@@ -162,7 +168,7 @@ updated_secret = client.secrets.update_secret_by_name(
162
168
  ```python
163
169
  secret = client.secrets.get_secret_by_name(
164
170
  secret_name="EXISTING_SECRET",
165
- project_id="your_project_id",
171
+ project_id="<project-id>",
166
172
  environment_slug="dev",
167
173
  secret_path="/",
168
174
  expand_secret_references=True,
@@ -188,7 +194,7 @@ secret = client.secrets.get_secret_by_name(
188
194
  ```python
189
195
  deleted_secret = client.secrets.delete_secret_by_name(
190
196
  secret_name="EXISTING_SECRET",
191
- project_id="your_project_id",
197
+ project_id="<project-id>",
192
198
  environment_slug="dev",
193
199
  secret_path="/"
194
200
  )
@@ -202,3 +208,147 @@ deleted_secret = client.secrets.delete_secret_by_name(
202
208
 
203
209
  **Returns:**
204
210
  - `BaseSecret`: The response after deleting the secret.
211
+
212
+ ### `kms`
213
+
214
+ This sub-class handles KMS related operations:
215
+
216
+ #### List KMS Keys
217
+
218
+ ```python
219
+ kms_keys = client.kms.list_keys(
220
+ project_id="<project-id>",
221
+ offset=0, # Optional
222
+ limit=100, # Optional
223
+ order_by=KmsKeysOrderBy.NAME, # Optional
224
+ order_direction=OrderDirection.ASC, # Optional
225
+ search=None # Optional
226
+ )
227
+ ```
228
+
229
+ **Parameters:**
230
+ - `project_id` (str): The ID of your project.
231
+ - `offset` (int, optional): The offset to paginate from.
232
+ - `limit` (int, optional): The page size for paginating.
233
+ - `order_by` (KmsKeysOrderBy, optional): The key property to order the list response by.
234
+ - `order_direction` (OrderDirection, optional): The direction to order the list response in.
235
+ - `search` (str, optional): The text value to filter key names by.
236
+
237
+ **Returns:**
238
+ - `ListKmsKeysResponse`: The response containing the list of KMS keys.
239
+
240
+ #### Get KMS Key by ID
241
+
242
+ ```python
243
+ kms_key = client.kms.get_key_by_id(
244
+ key_id="<key-id>"
245
+ )
246
+ ```
247
+
248
+ **Parameters:**
249
+ - `key_id` (str): The ID of the key to retrieve.
250
+
251
+ **Returns:**
252
+ - `KmsKey`: The specified key.
253
+
254
+ #### Get KMS Key by Name
255
+
256
+ ```python
257
+ kms_key = client.kms.get_key_by_name(
258
+ key_name="my-key",
259
+ project_id="<project-id>"
260
+ )
261
+ ```
262
+
263
+ **Parameters:**
264
+ - `key_name` (str): The name of the key to retrieve.
265
+ - `project_id` (str): The ID of your project.
266
+
267
+ **Returns:**
268
+ - `KmsKey`: The specified key.
269
+
270
+ #### Create KMS Key
271
+
272
+ ```python
273
+ kms_key = client.kms.create_key(
274
+ name="my-key",
275
+ project_id="<project-id>",
276
+ encryption_algorithm=SymmetricEncryption.AES_GCM_256,
277
+ description=None # Optional
278
+ )
279
+ ```
280
+
281
+ **Parameters:**
282
+ - `name` (str): The name of the key (must be slug-friendly).
283
+ - `project_id` (str): The ID of your project.
284
+ - `encryption_algorithm` (SymmetricEncryption): The encryption alogrithm this key should use.
285
+ - `description` (str, optional): A description of your key.
286
+
287
+ **Returns:**
288
+ - `KmsKey`: The newly created key.
289
+
290
+ #### Update KMS Key
291
+
292
+ ```python
293
+ updated_key = client.kms.update_key(
294
+ key_id="<key-id>",
295
+ name="my-updated-key", # Optional
296
+ description="Updated description", # Optional
297
+ is_disabled=True # Optional
298
+ )
299
+ ```
300
+
301
+ **Parameters:**
302
+ - `key_id` (str): The ID of the key to be updated.
303
+ - `name` (str, optional): The updated name of the key (must be slug-friendly).
304
+ - `description` (str): The updated description of the key.
305
+ - `is_disabled` (str): The flag to disable operations with this key.
306
+
307
+ **Returns:**
308
+ - `KmsKey`: The updated key.
309
+
310
+ #### Delete KMS Key
311
+
312
+ ```python
313
+ deleted_key = client.kms.delete_key(
314
+ key_id="<key-id>"
315
+ )
316
+ ```
317
+
318
+ **Parameters:**
319
+ - `key_id` (str): The ID of the key to be deleted.
320
+
321
+ **Returns:**
322
+ - `KmsKey`: The deleted key.
323
+
324
+ #### Encrypt Data with KMS Key
325
+
326
+ ```python
327
+ encrypted_data = client.kms.encrypt_data(
328
+ key_id="<key-id>",
329
+ base64EncodedPlaintext="TXkgc2VjcmV0IG1lc3NhZ2U=" # must be base64 encoded
330
+ )
331
+ ```
332
+
333
+ **Parameters:**
334
+ - `key_id` (str): The ID of the key to encrypt the data with.
335
+ - `base64EncodedPlaintext` (str): The plaintext data to encrypt (must be base64 encoded).
336
+
337
+ **Returns:**
338
+ - `str`: The encrypted ciphertext.
339
+
340
+ #### Decrypte Data with KMS Key
341
+
342
+ ```python
343
+ decrypted_data = client.kms.decrypt_data(
344
+ key_id="<key-id>",
345
+ ciphertext="Aq96Ry7sMH3k/ogaIB5MiSfH+LblQRBu69lcJe0GfIvI48ZvbWY+9JulyoQYdjAx"
346
+ )
347
+ ```
348
+
349
+ **Parameters:**
350
+ - `key_id` (str): The ID of the key to decrypt the data with.
351
+ - `ciphertext` (str): The ciphertext returned from the encrypt operation.
352
+
353
+ **Returns:**
354
+ - `str`: The base64 encoded plaintext.
@@ -112,7 +112,7 @@ class SingleSecretResponse(BaseModel):
112
112
  secret: BaseSecret
113
113
 
114
114
  @classmethod
115
- def from_dict(cls, data: Dict) -> 'ListSecretsResponse':
115
+ def from_dict(cls, data: Dict) -> 'SingleSecretResponse':
116
116
  return cls(
117
117
  secret=BaseSecret.from_dict(data['secret']),
118
118
  )
@@ -125,3 +125,71 @@ class MachineIdentityLoginResponse(BaseModel):
125
125
  expiresIn: int
126
126
  accessTokenMaxTTL: int
127
127
  tokenType: str
128
+
129
+
130
+ class SymmetricEncryption(str, Enum):
131
+ AES_GCM_256 = "aes-256-gcm"
132
+ AES_GCM_128 = "aes-128-gcm"
133
+
134
+
135
+ class OrderDirection(str, Enum):
136
+ ASC = "asc"
137
+ DESC = "desc"
138
+
139
+
140
+ class KmsKeysOrderBy(str, Enum):
141
+ NAME = "name"
142
+
143
+
144
+ @dataclass
145
+ class KmsKey(BaseModel):
146
+ """Infisical KMS Key"""
147
+ id: str
148
+ description: str
149
+ isDisabled: bool
150
+ orgId: str
151
+ name: str
152
+ createdAt: str
153
+ updatedAt: str
154
+ projectId: str
155
+ version: int
156
+ encryptionAlgorithm: SymmetricEncryption
157
+
158
+
159
+ @dataclass
160
+ class ListKmsKeysResponse(BaseModel):
161
+ """Complete response model for Kms Keys API"""
162
+ keys: List[KmsKey]
163
+ totalCount: int
164
+
165
+ @classmethod
166
+ def from_dict(cls, data: Dict) -> 'ListKmsKeysResponse':
167
+ """Create model from dictionary with camelCase keys, handling nested objects"""
168
+ return cls(
169
+ keys=[KmsKey.from_dict(key) for key in data['keys']],
170
+ totalCount=data['totalCount']
171
+ )
172
+
173
+
174
+ @dataclass
175
+ class SingleKmsKeyResponse(BaseModel):
176
+ """Response model for get/create/update/delete API"""
177
+ key: KmsKey
178
+
179
+ @classmethod
180
+ def from_dict(cls, data: Dict) -> 'SingleKmsKeyResponse':
181
+ return cls(
182
+ key=KmsKey.from_dict(data['key']),
183
+ )
184
+
185
+
186
+ @dataclass
187
+ class KmsKeyEncryptDataResponse(BaseModel):
188
+ """Response model for encrypt data API"""
189
+ ciphertext: str
190
+
191
+
192
+ @dataclass
193
+ class KmsKeyDecryptDataResponse(BaseModel):
194
+ """Response model for decrypt data API"""
195
+ plaintext: str
@@ -12,8 +12,11 @@ from botocore.awsrequest import AWSRequest
12
12
  from botocore.exceptions import NoCredentialsError
13
13
 
14
14
  from .infisical_requests import InfisicalRequests
15
- from .api_types import ListSecretsResponse, MachineIdentityLoginResponse
16
- from .api_types import SingleSecretResponse, BaseSecret
15
+
16
+ from .api_types import ListSecretsResponse, SingleSecretResponse, BaseSecret
17
+ from .api_types import SymmetricEncryption, KmsKeysOrderBy, OrderDirection
18
+ from .api_types import ListKmsKeysResponse, SingleKmsKeyResponse, MachineIdentityLoginResponse
19
+ from .api_types import KmsKey, KmsKeyEncryptDataResponse, KmsKeyDecryptDataResponse
17
20
 
18
21
 
19
22
  class InfisicalSDKClient:
@@ -25,6 +28,7 @@ class InfisicalSDKClient:
25
28
 
26
29
  self.auth = Auth(self)
27
30
  self.secrets = V3RawSecrets(self)
31
+ self.kms = KMS(self)
28
32
 
29
33
  def set_token(self, token: str):
30
34
  """
@@ -219,7 +223,7 @@ class V3RawSecrets:
219
223
  }
220
224
 
221
225
  if tag_filters:
222
- params["tag_slugs"] = ",".join(tag_filters)
226
+ params["tagSlugs"] = ",".join(tag_filters)
223
227
 
224
228
  result = self.client.api.get(
225
229
  path="/api/v3/secrets/raw",
@@ -307,7 +311,7 @@ class V3RawSecrets:
307
311
  "secretPath": secret_path,
308
312
  "secretValue": secret_value,
309
313
  "secretComment": secret_comment,
310
- "new_secret_name": new_secret_name,
314
+ "newSecretName": new_secret_name,
311
315
  "tagIds": None,
312
316
  "skipMultilineEncoding": skip_multiline_encoding,
313
317
  "type": "shared",
@@ -343,3 +347,175 @@ class V3RawSecrets:
343
347
  )
344
348
 
345
349
  return result.data.secret
350
+
351
+
352
+ class KMS:
353
+ def __init__(self, client: InfisicalSDKClient) -> None:
354
+ self.client = client
355
+
356
+ def list_keys(
357
+ self,
358
+ project_id: str,
359
+ offset: int = 0,
360
+ limit: int = 100,
361
+ order_by: KmsKeysOrderBy = KmsKeysOrderBy.NAME,
362
+ order_direction: OrderDirection = OrderDirection.ASC,
363
+ search: str = None) -> ListKmsKeysResponse:
364
+
365
+ params = {
366
+ "projectId": project_id,
367
+ "search": search,
368
+ "offset": offset,
369
+ "limit": limit,
370
+ "orderBy": order_by,
371
+ "orderDirection": order_direction,
372
+ }
373
+
374
+ result = self.client.api.get(
375
+ path="/api/v1/kms/keys",
376
+ params=params,
377
+ model=ListKmsKeysResponse
378
+ )
379
+
380
+ return result.data
381
+
382
+ def get_key_by_id(
383
+ self,
384
+ key_id: str) -> KmsKey:
385
+
386
+ result = self.client.api.get(
387
+ path=f"/api/v1/kms/keys/{key_id}",
388
+ model=SingleKmsKeyResponse
389
+ )
390
+
391
+ return result.data.key
392
+
393
+ def get_key_by_name(
394
+ self,
395
+ key_name: str,
396
+ project_id: str) -> KmsKey:
397
+
398
+ params = {
399
+ "projectId": project_id,
400
+ }
401
+
402
+ result = self.client.api.get(
403
+ path=f"/api/v1/kms/keys/key-name/{key_name}",
404
+ params=params,
405
+ model=SingleKmsKeyResponse
406
+ )
407
+
408
+ return result.data.key
409
+
410
+ def create_key(
411
+ self,
412
+ name: str,
413
+ project_id: str,
414
+ encryption_algorithm: SymmetricEncryption,
415
+ description: str = None) -> KmsKey:
416
+
417
+ request_body = {
418
+ "name": name,
419
+ "projectId": project_id,
420
+ "encryptionAlgorithm": encryption_algorithm,
421
+ "description": description,
422
+ }
423
+
424
+ result = self.client.api.post(
425
+ path="/api/v1/kms/keys",
426
+ json=request_body,
427
+ model=SingleKmsKeyResponse
428
+ )
429
+
430
+ return result.data.key
431
+
432
+ def update_key(
433
+ self,
434
+ key_id: str,
435
+ name: str = None,
436
+ is_disabled: bool = None,
437
+ description: str = None) -> KmsKey:
438
+
439
+ request_body = {
440
+ "name": name,
441
+ "isDisabled": is_disabled,
442
+ "description": description,
443
+ }
444
+
445
+ result = self.client.api.patch(
446
+ path=f"/api/v1/kms/keys/{key_id}",
447
+ json=request_body,
448
+ model=SingleKmsKeyResponse
449
+ )
450
+
451
+ return result.data.key
452
+
453
+ def delete_key(
454
+ self,
455
+ key_id: str) -> KmsKey:
456
+
457
+ result = self.client.api.delete(
458
+ path=f"/api/v1/kms/keys/{key_id}",
459
+ json={},
460
+ model=SingleKmsKeyResponse
461
+ )
462
+
463
+ return result.data.key
464
+
465
+ def encrypt_data(
466
+ self,
467
+ key_id: str,
468
+ base64EncodedPlaintext: str) -> str:
469
+ """
470
+ Encrypt data with the specified KMS key.
471
+
472
+ :param key_id: The ID of the key to decrypt the ciphertext with
473
+ :type key_id: str
474
+ :param base64EncodedPlaintext: The base64 encoded plaintext to encrypt
475
+ :type plaintext: str
476
+
477
+
478
+ :return: The encrypted base64 encoded plaintext (ciphertext)
479
+ :rtype: str
480
+ """
481
+
482
+ request_body = {
483
+ "plaintext": base64EncodedPlaintext
484
+ }
485
+
486
+ result = self.client.api.post(
487
+ path=f"/api/v1/kms/keys/{key_id}/encrypt",
488
+ json=request_body,
489
+ model=KmsKeyEncryptDataResponse
490
+ )
491
+
492
+ return result.data.ciphertext
493
+
494
+ def decrypt_data(
495
+ self,
496
+ key_id: str,
497
+ ciphertext: str) -> str:
498
+ """
499
+ Decrypt data with the specified KMS key.
500
+
501
+ :param key_id: The ID of the key to decrypt the ciphertext with
502
+ :type key_id: str
503
+ :param ciphertext: The encrypted base64 plaintext to decrypt
504
+ :type ciphertext: str
505
+
506
+
507
+ :return: The base64 encoded plaintext
508
+ :rtype: str
509
+ """
510
+
511
+ request_body = {
512
+ "ciphertext": ciphertext
513
+ }
514
+
515
+ result = self.client.api.post(
516
+ path=f"/api/v1/kms/keys/{key_id}/decrypt",
517
+ json=request_body,
518
+ model=KmsKeyDecryptDataResponse
519
+ )
520
+
521
+ return result.data.plaintext
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, Generic, Optional, TypeVar
1
+ from typing import Any, Dict, Generic, Optional, TypeVar, Type
2
2
  from urllib.parse import urljoin
3
3
  import requests
4
4
  from dataclasses import dataclass
@@ -90,7 +90,7 @@ class InfisicalRequests:
90
90
  def get(
91
91
  self,
92
92
  path: str,
93
- model: type[T],
93
+ model: Type[T],
94
94
  params: Optional[Dict[str, Any]] = None
95
95
  ) -> APIResponse[T]:
96
96
 
@@ -116,7 +116,7 @@ class InfisicalRequests:
116
116
  def post(
117
117
  self,
118
118
  path: str,
119
- model: type[T],
119
+ model: Type[T],
120
120
  json: Optional[Dict[str, Any]] = None
121
121
  ) -> APIResponse[T]:
122
122
 
@@ -140,7 +140,7 @@ class InfisicalRequests:
140
140
  def patch(
141
141
  self,
142
142
  path: str,
143
- model: type[T],
143
+ model: Type[T],
144
144
  json: Optional[Dict[str, Any]] = None
145
145
  ) -> APIResponse[T]:
146
146
 
@@ -164,7 +164,7 @@ class InfisicalRequests:
164
164
  def delete(
165
165
  self,
166
166
  path: str,
167
- model: type[T],
167
+ model: Type[T],
168
168
  json: Optional[Dict[str, Any]] = None
169
169
  ) -> APIResponse[T]:
170
170
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: infisicalsdk
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Infisical API Client
5
5
  Home-page: https://github.com/Infisical/python-sdk-official
6
6
  Author: Infisical
@@ -15,8 +15,8 @@ from setuptools import setup, find_packages # noqa: H301
15
15
  # prerequisite: setuptools
16
16
  # http://pypi.python.org/pypi/setuptools
17
17
  NAME = "infisicalsdk"
18
- VERSION = "1.0.3"
19
- PYTHON_REQUIRES = ">=3.7"
18
+ VERSION = "1.0.4"
19
+ PYTHON_REQUIRES = ">=3.8"
20
20
  REQUIRES = [
21
21
  "urllib3 >= 1.25.3, < 2.1.0",
22
22
  "python-dateutil",
File without changes