6
6
@dataclass
7
7
class GetSecretOptions :
8
8
env_name : str
9
- app_name : str
9
+ app_name : Optional [str ] = None
10
+ app_id : Optional [str ] = None
10
11
key_to_find : Optional [str ] = None
11
12
tag : Optional [str ] = None
12
13
secret_path : str = "/"
13
14
15
+ def __post_init__ (self ):
16
+ if not self .app_name and not self .app_id :
17
+ raise ValueError ("Either app_name or app_id must be provided" )
18
+
14
19
@dataclass
15
20
class GetAllSecretsOptions :
16
21
env_name : str
17
- app_name : str
22
+ app_name : Optional [str ] = None
23
+ app_id : Optional [str ] = None
18
24
tag : Optional [str ] = None
19
25
secret_path : str = "/"
20
26
27
+ def __post_init__ (self ):
28
+ if not self .app_name and not self .app_id :
29
+ raise ValueError ("Either app_name or app_id must be provided" )
30
+
21
31
@dataclass
22
32
class CreateSecretsOptions :
23
33
env_name : str
24
- app_name : str
25
34
key_value_pairs : List [Dict [str , str ]]
35
+ app_name : Optional [str ] = None
36
+ app_id : Optional [str ] = None
26
37
secret_path : str = "/"
27
38
39
+ def __post_init__ (self ):
40
+ if not self .app_name and not self .app_id :
41
+ raise ValueError ("Either app_name or app_id must be provided" )
42
+
28
43
@dataclass
29
44
class UpdateSecretOptions :
30
45
env_name : str
31
- app_name : str
32
46
key : str
33
47
value : Optional [str ] = None
48
+ app_name : Optional [str ] = None
49
+ app_id : Optional [str ] = None
34
50
secret_path : str = "/"
35
51
destination_path : Optional [str ] = None
36
52
override : bool = False
37
53
toggle_override : bool = False
38
54
55
+ def __post_init__ (self ):
56
+ if not self .app_name and not self .app_id :
57
+ raise ValueError ("Either app_name or app_id must be provided" )
58
+
39
59
@dataclass
40
60
class DeleteSecretOptions :
41
61
env_name : str
42
- app_name : str
43
62
key_to_delete : str
63
+ app_name : Optional [str ] = None
64
+ app_id : Optional [str ] = None
44
65
secret_path : str = "/"
45
66
67
+ def __post_init__ (self ):
68
+ if not self .app_name and not self .app_id :
69
+ raise ValueError ("Either app_name or app_id must be provided" )
70
+
46
71
@dataclass
47
72
class PhaseSecret :
48
73
key : str
@@ -51,49 +76,127 @@ class PhaseSecret:
51
76
path : str = "/"
52
77
tags : List [str ] = field (default_factory = list )
53
78
overridden : bool = False
79
+ application : Optional [str ] = None
80
+ environment : Optional [str ] = None
54
81
55
82
class Phase :
56
83
def __init__ (self , init = True , pss = None , host = None ):
57
84
self ._phase_io = PhaseIO (init = init , pss = pss , host = host )
58
85
86
+ def _resolve_secret_values (self , secrets : List [PhaseSecret ], env_name : str , app_name : str ) -> List [PhaseSecret ]:
87
+ """
88
+ Utility function to resolve secret references within secret values.
89
+
90
+ Args:
91
+ secrets (List[PhaseSecret]): List of secrets to process
92
+ env_name (str): Environment name for secret resolution
93
+ app_name (str): Application name for secret resolution
94
+
95
+ Returns:
96
+ List[PhaseSecret]: List of secrets with resolved values
97
+ """
98
+ # Convert PhaseSecret objects to dict format expected by resolve_all_secrets
99
+ all_secrets = [
100
+ {
101
+ 'environment' : secret .environment or env_name ,
102
+ 'path' : secret .path ,
103
+ 'key' : secret .key ,
104
+ 'value' : secret .value
105
+ }
106
+ for secret in secrets
107
+ ]
108
+
109
+ # Create new list of secrets with resolved values
110
+ resolved_secrets = []
111
+ for secret in secrets :
112
+ resolved_value = resolve_all_secrets (
113
+ value = secret .value ,
114
+ all_secrets = all_secrets ,
115
+ phase = self ._phase_io ,
116
+ current_application_name = secret .application or app_name ,
117
+ current_env_name = secret .environment or env_name
118
+ )
119
+
120
+ resolved_secrets .append (PhaseSecret (
121
+ key = secret .key ,
122
+ value = resolved_value ,
123
+ comment = secret .comment ,
124
+ path = secret .path ,
125
+ tags = secret .tags ,
126
+ overridden = secret .overridden ,
127
+ application = secret .application ,
128
+ environment = secret .environment
129
+ ))
130
+
131
+ return resolved_secrets
132
+
59
133
def get_secret (self , options : GetSecretOptions ) -> Optional [PhaseSecret ]:
60
134
secrets = self ._phase_io .get (
61
135
env_name = options .env_name ,
62
136
keys = [options .key_to_find ] if options .key_to_find else None ,
63
137
app_name = options .app_name ,
138
+ app_id = options .app_id ,
64
139
tag = options .tag ,
65
140
path = options .secret_path
66
141
)
67
142
if secrets :
68
143
secret = secrets [0 ]
69
- return PhaseSecret (
144
+ phase_secret = PhaseSecret (
70
145
key = secret ['key' ],
71
146
value = secret ['value' ],
72
147
comment = secret .get ('comment' , '' ),
73
148
path = secret .get ('path' , '/' ),
74
149
tags = secret .get ('tags' , []),
75
- overridden = secret .get ('overridden' , False )
150
+ overridden = secret .get ('overridden' , False ),
151
+ application = secret .get ('application' ),
152
+ environment = secret .get ('environment' )
153
+ )
154
+
155
+ # Resolve any secret references in the value
156
+ resolved_secrets = self ._resolve_secret_values (
157
+ [phase_secret ],
158
+ options .env_name ,
159
+ secret .get ('application' , options .app_name )
76
160
)
161
+
162
+ return resolved_secrets [0 ] if resolved_secrets else None
77
163
return None
78
164
79
165
def get_all_secrets (self , options : GetAllSecretsOptions ) -> List [PhaseSecret ]:
80
166
secrets = self ._phase_io .get (
81
167
env_name = options .env_name ,
82
168
app_name = options .app_name ,
169
+ app_id = options .app_id ,
83
170
tag = options .tag ,
84
171
path = options .secret_path
85
172
)
86
- return [
173
+
174
+ if not secrets :
175
+ return []
176
+
177
+ # Get the application name from the first secret
178
+ app_name = secrets [0 ].get ('application' , options .app_name )
179
+
180
+ phase_secrets = [
87
181
PhaseSecret (
88
182
key = secret ['key' ],
89
183
value = secret ['value' ],
90
184
comment = secret .get ('comment' , '' ),
91
185
path = secret .get ('path' , '/' ),
92
186
tags = secret .get ('tags' , []),
93
- overridden = secret .get ('overridden' , False )
187
+ overridden = secret .get ('overridden' , False ),
188
+ application = secret .get ('application' ),
189
+ environment = secret .get ('environment' )
94
190
)
95
191
for secret in secrets
96
192
]
193
+
194
+ # Resolve any secret references in the values
195
+ return self ._resolve_secret_values (
196
+ phase_secrets ,
197
+ options .env_name ,
198
+ app_name
199
+ )
97
200
98
201
def create_secrets (self , options : CreateSecretsOptions ) -> str :
99
202
# Convert the list of dictionaries to a list of tuples
@@ -103,6 +206,7 @@ def create_secrets(self, options: CreateSecretsOptions) -> str:
103
206
key_value_pairs = key_value_tuples ,
104
207
env_name = options .env_name ,
105
208
app_name = options .app_name ,
209
+ app_id = options .app_id ,
106
210
path = options .secret_path
107
211
)
108
212
return "Success" if response .status_code == 200 else f"Error: { response .status_code } "
@@ -113,6 +217,7 @@ def update_secret(self, options: UpdateSecretOptions) -> str:
113
217
key = options .key ,
114
218
value = options .value ,
115
219
app_name = options .app_name ,
220
+ app_id = options .app_id ,
116
221
source_path = options .secret_path ,
117
222
destination_path = options .destination_path ,
118
223
override = options .override ,
@@ -124,29 +229,6 @@ def delete_secret(self, options: DeleteSecretOptions) -> List[str]:
124
229
env_name = options .env_name ,
125
230
keys_to_delete = [options .key_to_delete ],
126
231
app_name = options .app_name ,
232
+ app_id = options .app_id ,
127
233
path = options .secret_path
128
234
)
129
-
130
- def resolve_references (self , secrets : List [PhaseSecret ], env_name : str , app_name : str ) -> List [PhaseSecret ]:
131
- all_secrets = [
132
- {
133
- 'environment' : env_name ,
134
- 'application' : app_name ,
135
- 'key' : secret .key ,
136
- 'value' : secret .value ,
137
- 'path' : secret .path
138
- }
139
- for secret in secrets
140
- ]
141
-
142
- for secret in secrets :
143
- resolved_value = resolve_all_secrets (
144
- secret .value ,
145
- all_secrets ,
146
- self ._phase_io ,
147
- app_name ,
148
- env_name
149
- )
150
- secret .value = resolved_value
151
-
152
- return secrets
0 commit comments