Skip to content

Commit b644202

Browse files
authored
Merge pull request #51 from Infisical/feature/add-dynamic-secrets-support
feat(dynamic-secrets): implement DynamicSecrets feature
2 parents bf1aaf1 + 1300c27 commit b644202

5 files changed

Lines changed: 442 additions & 2 deletions

File tree

infisical_sdk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from .client import InfisicalSDKClient # noqa
22
from .infisical_requests import InfisicalError # noqa
3-
from .api_types import SingleSecretResponse, ListSecretsResponse, BaseSecret, SymmetricEncryption # noqa
3+
from .api_types import SingleSecretResponse, ListSecretsResponse, BaseSecret, SymmetricEncryption, DynamicSecretProviders # noqa

infisical_sdk/api_types.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,105 @@ def from_dict(cls, data: Dict) -> 'SingleFolderResponse':
293293
return cls(
294294
folder=SingleFolderResponseItem.from_dict(data['folder']),
295295
)
296+
297+
class DynamicSecretProviders(str, Enum):
298+
"""Enum for dynamic secret provider types"""
299+
AWS_ELASTICACHE = "aws-elasticache"
300+
AWS_IAM = "aws-iam"
301+
AZURE_ENTRA_ID = "azure-entra-id"
302+
AZURE_SQL_DATABASE = "azure-sql-database"
303+
CASSANDRA = "cassandra"
304+
COUCHBASE = "couchbase"
305+
ELASTICSEARCH = "elastic-search"
306+
GCP_IAM = "gcp-iam"
307+
GITHUB = "github"
308+
KUBERNETES = "kubernetes"
309+
LDAP = "ldap"
310+
MONGO_ATLAS = "mongo-db-atlas"
311+
MONGODB = "mongo-db"
312+
RABBITMQ = "rabbit-mq"
313+
REDIS = "redis"
314+
SAP_ASE = "sap-ase"
315+
SAP_HANA = "sap-hana"
316+
SNOWFLAKE = "snowflake"
317+
SQL_DATABASE = "sql-database"
318+
TOTP = "totp"
319+
VERTICA = "vertica"
320+
321+
@dataclass
322+
class DynamicSecret(BaseModel):
323+
"""Infisical Dynamic Secret"""
324+
id: str
325+
name: str
326+
version: int
327+
type: str
328+
folderId: str
329+
createdAt: str
330+
updatedAt: str
331+
defaultTTL: Optional[str] = None
332+
maxTTL: Optional[str] = None
333+
status: Optional[str] = None
334+
statusDetails: Optional[str] = None
335+
usernameTemplate: Optional[str] = None
336+
metadata: Optional[List[Dict[str, str]]] = field(default_factory=list)
337+
inputs: Optional[Any] = None
338+
339+
@dataclass
340+
class SingleDynamicSecretResponse(BaseModel):
341+
"""Response model for get/create/update/delete dynamic secret API"""
342+
dynamicSecret: DynamicSecret
343+
344+
@classmethod
345+
def from_dict(cls, data: Dict) -> 'SingleDynamicSecretResponse':
346+
return cls(
347+
dynamicSecret=DynamicSecret.from_dict(data['dynamicSecret']),
348+
)
349+
350+
@dataclass
351+
class DynamicSecretLease(BaseModel):
352+
"""Infisical Dynamic Secret Lease"""
353+
id: str
354+
expireAt: str
355+
createdAt: str
356+
updatedAt: str
357+
version: int
358+
dynamicSecretId: str
359+
externalEntityId: str
360+
status: Optional[str] = None
361+
statusDetails: Optional[str] = None
362+
dynamicSecret: Optional[DynamicSecret] = None
363+
364+
@classmethod
365+
def from_dict(cls, data: Dict) -> 'DynamicSecretLease':
366+
"""Create model from dictionary with nested DynamicSecret"""
367+
lease_data = data.copy()
368+
if 'dynamicSecret' in data and data['dynamicSecret'] is not None:
369+
lease_data['dynamicSecret'] = DynamicSecret.from_dict(data['dynamicSecret'])
370+
371+
return super().from_dict(lease_data)
372+
373+
@dataclass
374+
class CreateLeaseResponse(BaseModel):
375+
"""Response model for create lease API - returns lease, dynamicSecret, and data"""
376+
lease: DynamicSecretLease
377+
dynamicSecret: DynamicSecret
378+
data: Any
379+
380+
@classmethod
381+
def from_dict(cls, data: Dict) -> 'CreateLeaseResponse':
382+
return cls(
383+
lease=DynamicSecretLease.from_dict(data['lease']),
384+
dynamicSecret=DynamicSecret.from_dict(data['dynamicSecret']),
385+
data=data.get('data', {}),
386+
)
387+
388+
@dataclass
389+
class SingleLeaseResponse(BaseModel):
390+
"""Response model for get/delete/renew lease API - returns only lease"""
391+
lease: DynamicSecretLease
392+
393+
@classmethod
394+
def from_dict(cls, data: Dict) -> 'SingleLeaseResponse':
395+
return cls(
396+
lease=DynamicSecretLease.from_dict(data['lease']),
397+
)

infisical_sdk/client.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from infisical_sdk.resources import V3RawSecrets
55
from infisical_sdk.resources import KMS
66
from infisical_sdk.resources import V2Folders
7+
from infisical_sdk.resources import DynamicSecrets
78

89
from infisical_sdk.util import SecretsCache
910

@@ -26,6 +27,7 @@ def __init__(self, host: str, token: str = None, cache_ttl: int = 60):
2627
self.secrets = V3RawSecrets(self.api, self.cache)
2728
self.kms = KMS(self.api)
2829
self.folders = V2Folders(self.api)
30+
self.dynamic_secrets = DynamicSecrets(self.api)
2931

3032
def set_token(self, token: str):
3133
"""
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .secrets import V3RawSecrets
22
from .kms import KMS
33
from .auth import Auth
4-
from .folders import V2Folders
4+
from .folders import V2Folders
5+
from .dynamic_secrets import DynamicSecrets

0 commit comments

Comments
 (0)