2
2
"""Secrets management for AirbyteLib."""
3
3
from __future__ import annotations
4
4
5
+ import contextlib
5
6
import os
6
7
from enum import Enum , auto
7
8
from getpass import getpass
9
+ from typing import TYPE_CHECKING
10
+
11
+ from dotenv import dotenv_values
8
12
9
13
from airbyte_lib import exceptions as exc
10
14
11
15
16
+ if TYPE_CHECKING :
17
+ from collections .abc import Callable
18
+
19
+
20
+ try :
21
+ from google .colab import userdata as colab_userdata
22
+ except ImportError :
23
+ colab_userdata = None
24
+
25
+
12
26
class SecretSource (Enum ):
13
27
ENV = auto ()
28
+ DOTENV = auto ()
14
29
GOOGLE_COLAB = auto ()
15
30
ANY = auto ()
16
31
17
32
PROMPT = auto ()
18
33
19
34
20
- ALL_SOURCES = [
21
- SecretSource .ENV ,
22
- SecretSource .GOOGLE_COLAB ,
23
- ]
35
+ def _get_secret_from_env (
36
+ secret_name : str ,
37
+ ) -> str | None :
38
+ if secret_name not in os .environ :
39
+ return None
24
40
25
- try :
26
- from google .colab import userdata as colab_userdata
27
- except ImportError :
28
- colab_userdata = None
41
+ return os .environ [secret_name ]
42
+
43
+
44
+ def _get_secret_from_dotenv (
45
+ secret_name : str ,
46
+ ) -> str | None :
47
+ try :
48
+ dotenv_vars : dict [str , str | None ] = dotenv_values ()
49
+ except Exception :
50
+ # Can't locate or parse a .env file
51
+ return None
52
+
53
+ if secret_name not in dotenv_vars :
54
+ # Secret not found
55
+ return None
56
+
57
+ return dotenv_vars [secret_name ]
58
+
59
+
60
+ def _get_secret_from_colab (
61
+ secret_name : str ,
62
+ ) -> str | None :
63
+ if colab_userdata is None :
64
+ # The module doesn't exist. We probably aren't in Colab.
65
+ return None
66
+
67
+ try :
68
+ return colab_userdata .get (secret_name )
69
+ except Exception :
70
+ # Secret name not found. Continue.
71
+ return None
72
+
73
+
74
+ def _get_secret_from_prompt (
75
+ secret_name : str ,
76
+ ) -> str | None :
77
+ with contextlib .suppress (Exception ):
78
+ return getpass (f"Enter the value for secret '{ secret_name } ': " )
79
+
80
+ return None
81
+
82
+
83
+ _SOURCE_FUNCTIONS : dict [SecretSource , Callable ] = {
84
+ SecretSource .ENV : _get_secret_from_env ,
85
+ SecretSource .DOTENV : _get_secret_from_dotenv ,
86
+ SecretSource .GOOGLE_COLAB : _get_secret_from_colab ,
87
+ SecretSource .PROMPT : _get_secret_from_prompt ,
88
+ }
29
89
30
90
31
91
def get_secret (
@@ -45,8 +105,9 @@ def get_secret(
45
105
user will be prompted to enter the secret if it is not found in any of the other sources.
46
106
"""
47
107
sources = [source ] if not isinstance (source , list ) else source
108
+ all_sources = set (_SOURCE_FUNCTIONS .keys ()) - {SecretSource .PROMPT }
48
109
if SecretSource .ANY in sources :
49
- sources += [s for s in ALL_SOURCES if s not in sources ]
110
+ sources += [s for s in all_sources if s not in sources ]
50
111
sources .remove (SecretSource .ANY )
51
112
52
113
if prompt or SecretSource .PROMPT in sources :
@@ -55,32 +116,13 @@ def get_secret(
55
116
56
117
sources .append (SecretSource .PROMPT ) # Always check prompt last
57
118
58
- for s in sources :
59
- val = _get_secret_from_source (secret_name , s )
119
+ for source in sources :
120
+ fn = _SOURCE_FUNCTIONS [source ] # Get the matching function for this source
121
+ val = fn (secret_name )
60
122
if val :
61
123
return val
62
124
63
125
raise exc .AirbyteLibSecretNotFoundError (
64
126
secret_name = secret_name ,
65
127
sources = [str (s ) for s in sources ],
66
128
)
67
-
68
-
69
- def _get_secret_from_source (
70
- secret_name : str ,
71
- source : SecretSource ,
72
- ) -> str | None :
73
- if source in [SecretSource .ENV , SecretSource .ANY ] and secret_name in os .environ :
74
- return os .environ [secret_name ]
75
-
76
- if (
77
- source in [SecretSource .GOOGLE_COLAB , SecretSource .ANY ]
78
- and colab_userdata is not None
79
- and colab_userdata .get (secret_name )
80
- ):
81
- return colab_userdata .get (secret_name )
82
-
83
- if source == SecretSource .PROMPT :
84
- return getpass (f"Enter the value for secret '{ secret_name } ': " )
85
-
86
- return None
0 commit comments