airbyte.secrets.base
1# Copyright (c) 2024 Airbyte, Inc., all rights reserved. 2"""___""" 3 4from __future__ import annotations 5 6import json 7from abc import ABC, abstractmethod 8from enum import Enum 9from typing import cast 10 11from airbyte import exceptions as exc 12 13 14class SecretSourceEnum(str, Enum): 15 ENV = "env" 16 DOTENV = "dotenv" 17 GOOGLE_COLAB = "google_colab" 18 GOOGLE_GSM = "google_gsm" # Not enabled by default 19 20 PROMPT = "prompt" 21 22 23class SecretString(str): 24 """A string that represents a secret. 25 26 This class is used to mark a string as a secret. When a secret is printed, it 27 will be masked to prevent accidental exposure of sensitive information. 28 """ 29 30 __slots__ = () 31 32 def __repr__(self) -> str: 33 return "<SecretString: ****>" 34 35 def is_empty(self) -> bool: 36 """Check if the secret is an empty string.""" 37 return len(self) == 0 38 39 def is_json(self) -> bool: 40 """Check if the secret string is a valid JSON string.""" 41 try: 42 json.loads(self) 43 except (json.JSONDecodeError, Exception): 44 return False 45 46 return True 47 48 def __bool__(self) -> bool: 49 """Override the boolean value of the secret string. 50 51 Always returns `True` without inspecting contents.""" 52 return True 53 54 def parse_json(self) -> dict: 55 """Parse the secret string as JSON.""" 56 try: 57 return json.loads(self) 58 except json.JSONDecodeError as ex: 59 raise exc.PyAirbyteInputError( 60 message="Failed to parse secret as JSON.", 61 context={ 62 "Message": ex.msg, 63 "Position": ex.pos, 64 "SecretString_Length": len(self), # Debug secret blank or an unexpected format. 65 }, 66 ) from None 67 68 69class SecretManager(ABC): 70 """Abstract base class for secret managers. 71 72 Secret managers are used to retrieve secrets from a secret store. 73 74 By registering a secret manager, PyAirbyte can automatically locate and 75 retrieve secrets from the secret store when needed. This allows you to 76 securely store and access sensitive information such as API keys, passwords, 77 and other credentials without hardcoding them in your code. 78 79 To create a custom secret manager, subclass this class and implement the 80 `get_secret` method. By default, the secret manager will be automatically 81 registered as a global secret source, but will not replace any existing 82 secret sources. To customize this behavior, override the `auto_register` and 83 `replace_existing` attributes in your subclass as needed. 84 85 Note: Registered secrets managers always have priority over the default 86 secret sources such as environment variables, dotenv files, and Google Colab 87 secrets. If multiple secret managers are registered, the last one registered 88 will take priority. 89 """ 90 91 replace_existing = False 92 as_backup = False 93 94 def __init__(self) -> None: 95 """Instantiate the new secret manager.""" 96 if not hasattr(self, "name"): 97 # Default to the class name if no name is provided 98 self.name: str = self.__class__.__name__ 99 100 @abstractmethod 101 def get_secret(self, secret_name: str) -> SecretString | None: 102 """Get a named secret from the secret manager. 103 104 This method should be implemented by subclasses to retrieve secrets from 105 the secret store. If the secret is not found, the method should return `None`. 106 """ 107 ... 108 109 def __str__(self) -> str: 110 return self.name 111 112 def __eq__(self, value: object) -> bool: 113 if isinstance(value, SecretManager): 114 return self.name == value.name 115 116 if isinstance(value, str): 117 return self.name == value 118 119 if isinstance(value, SecretSourceEnum): 120 return self.name == str(value) 121 122 return super().__eq__(value) 123 124 125class SecretHandle: 126 """A handle for a secret in a secret manager. 127 128 This class is used to store a reference to a secret in a secret manager. 129 The secret is not retrieved until the `get_value()` method is called on the handle. 130 """ 131 132 def __init__( 133 self, 134 parent: SecretManager, 135 secret_name: str, 136 ) -> None: 137 """Instantiate a new secret handle.""" 138 self.parent = parent 139 self.secret_name = secret_name 140 141 def get_value(self) -> SecretString: 142 """Get the secret from the secret manager. 143 144 Subclasses can optionally override this method to provide a more optimized code path. 145 """ 146 return cast(SecretString, self.parent.get_secret(self.secret_name))
15class SecretSourceEnum(str, Enum): 16 ENV = "env" 17 DOTENV = "dotenv" 18 GOOGLE_COLAB = "google_colab" 19 GOOGLE_GSM = "google_gsm" # Not enabled by default 20 21 PROMPT = "prompt"
An enumeration.
Inherited Members
- enum.Enum
- name
- value
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
24class SecretString(str): 25 """A string that represents a secret. 26 27 This class is used to mark a string as a secret. When a secret is printed, it 28 will be masked to prevent accidental exposure of sensitive information. 29 """ 30 31 __slots__ = () 32 33 def __repr__(self) -> str: 34 return "<SecretString: ****>" 35 36 def is_empty(self) -> bool: 37 """Check if the secret is an empty string.""" 38 return len(self) == 0 39 40 def is_json(self) -> bool: 41 """Check if the secret string is a valid JSON string.""" 42 try: 43 json.loads(self) 44 except (json.JSONDecodeError, Exception): 45 return False 46 47 return True 48 49 def __bool__(self) -> bool: 50 """Override the boolean value of the secret string. 51 52 Always returns `True` without inspecting contents.""" 53 return True 54 55 def parse_json(self) -> dict: 56 """Parse the secret string as JSON.""" 57 try: 58 return json.loads(self) 59 except json.JSONDecodeError as ex: 60 raise exc.PyAirbyteInputError( 61 message="Failed to parse secret as JSON.", 62 context={ 63 "Message": ex.msg, 64 "Position": ex.pos, 65 "SecretString_Length": len(self), # Debug secret blank or an unexpected format. 66 }, 67 ) from None
A string that represents a secret.
This class is used to mark a string as a secret. When a secret is printed, it will be masked to prevent accidental exposure of sensitive information.
36 def is_empty(self) -> bool: 37 """Check if the secret is an empty string.""" 38 return len(self) == 0
Check if the secret is an empty string.
40 def is_json(self) -> bool: 41 """Check if the secret string is a valid JSON string.""" 42 try: 43 json.loads(self) 44 except (json.JSONDecodeError, Exception): 45 return False 46 47 return True
Check if the secret string is a valid JSON string.
55 def parse_json(self) -> dict: 56 """Parse the secret string as JSON.""" 57 try: 58 return json.loads(self) 59 except json.JSONDecodeError as ex: 60 raise exc.PyAirbyteInputError( 61 message="Failed to parse secret as JSON.", 62 context={ 63 "Message": ex.msg, 64 "Position": ex.pos, 65 "SecretString_Length": len(self), # Debug secret blank or an unexpected format. 66 }, 67 ) from None
Parse the secret string as JSON.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
70class SecretManager(ABC): 71 """Abstract base class for secret managers. 72 73 Secret managers are used to retrieve secrets from a secret store. 74 75 By registering a secret manager, PyAirbyte can automatically locate and 76 retrieve secrets from the secret store when needed. This allows you to 77 securely store and access sensitive information such as API keys, passwords, 78 and other credentials without hardcoding them in your code. 79 80 To create a custom secret manager, subclass this class and implement the 81 `get_secret` method. By default, the secret manager will be automatically 82 registered as a global secret source, but will not replace any existing 83 secret sources. To customize this behavior, override the `auto_register` and 84 `replace_existing` attributes in your subclass as needed. 85 86 Note: Registered secrets managers always have priority over the default 87 secret sources such as environment variables, dotenv files, and Google Colab 88 secrets. If multiple secret managers are registered, the last one registered 89 will take priority. 90 """ 91 92 replace_existing = False 93 as_backup = False 94 95 def __init__(self) -> None: 96 """Instantiate the new secret manager.""" 97 if not hasattr(self, "name"): 98 # Default to the class name if no name is provided 99 self.name: str = self.__class__.__name__ 100 101 @abstractmethod 102 def get_secret(self, secret_name: str) -> SecretString | None: 103 """Get a named secret from the secret manager. 104 105 This method should be implemented by subclasses to retrieve secrets from 106 the secret store. If the secret is not found, the method should return `None`. 107 """ 108 ... 109 110 def __str__(self) -> str: 111 return self.name 112 113 def __eq__(self, value: object) -> bool: 114 if isinstance(value, SecretManager): 115 return self.name == value.name 116 117 if isinstance(value, str): 118 return self.name == value 119 120 if isinstance(value, SecretSourceEnum): 121 return self.name == str(value) 122 123 return super().__eq__(value)
Abstract base class for secret managers.
Secret managers are used to retrieve secrets from a secret store.
By registering a secret manager, PyAirbyte can automatically locate and retrieve secrets from the secret store when needed. This allows you to securely store and access sensitive information such as API keys, passwords, and other credentials without hardcoding them in your code.
To create a custom secret manager, subclass this class and implement the
get_secret
method. By default, the secret manager will be automatically
registered as a global secret source, but will not replace any existing
secret sources. To customize this behavior, override the auto_register
and
replace_existing
attributes in your subclass as needed.
Note: Registered secrets managers always have priority over the default secret sources such as environment variables, dotenv files, and Google Colab secrets. If multiple secret managers are registered, the last one registered will take priority.
95 def __init__(self) -> None: 96 """Instantiate the new secret manager.""" 97 if not hasattr(self, "name"): 98 # Default to the class name if no name is provided 99 self.name: str = self.__class__.__name__
Instantiate the new secret manager.
101 @abstractmethod 102 def get_secret(self, secret_name: str) -> SecretString | None: 103 """Get a named secret from the secret manager. 104 105 This method should be implemented by subclasses to retrieve secrets from 106 the secret store. If the secret is not found, the method should return `None`. 107 """ 108 ...
Get a named secret from the secret manager.
This method should be implemented by subclasses to retrieve secrets from
the secret store. If the secret is not found, the method should return None
.
126class SecretHandle: 127 """A handle for a secret in a secret manager. 128 129 This class is used to store a reference to a secret in a secret manager. 130 The secret is not retrieved until the `get_value()` method is called on the handle. 131 """ 132 133 def __init__( 134 self, 135 parent: SecretManager, 136 secret_name: str, 137 ) -> None: 138 """Instantiate a new secret handle.""" 139 self.parent = parent 140 self.secret_name = secret_name 141 142 def get_value(self) -> SecretString: 143 """Get the secret from the secret manager. 144 145 Subclasses can optionally override this method to provide a more optimized code path. 146 """ 147 return cast(SecretString, self.parent.get_secret(self.secret_name))
A handle for a secret in a secret manager.
This class is used to store a reference to a secret in a secret manager.
The secret is not retrieved until the get_value()
method is called on the handle.
133 def __init__( 134 self, 135 parent: SecretManager, 136 secret_name: str, 137 ) -> None: 138 """Instantiate a new secret handle.""" 139 self.parent = parent 140 self.secret_name = secret_name
Instantiate a new secret handle.
142 def get_value(self) -> SecretString: 143 """Get the secret from the secret manager. 144 145 Subclasses can optionally override this method to provide a more optimized code path. 146 """ 147 return cast(SecretString, self.parent.get_secret(self.secret_name))
Get the secret from the secret manager.
Subclasses can optionally override this method to provide a more optimized code path.