11import argparse
2+ from eval_protocol .cli_commands .utils import DiscoveredTest
23import importlib .util
34import os
45import re
1415 _build_entry_point ,
1516 _build_evaluator_dashboard_url ,
1617 _discover_and_select_tests ,
17- _discover_tests ,
1818 _ensure_account_id ,
19+ _get_questionary_style ,
1920 _normalize_evaluator_id ,
20- _prompt_select ,
2121)
2222
2323
@@ -170,6 +170,109 @@ def _mask_secret_value(value: str) -> str:
170170 return "<masked>"
171171
172172
173+ def _prompt_select_secrets (
174+ secrets : Dict [str , str ],
175+ secrets_from_env_file : Dict [str , str ],
176+ non_interactive : bool ,
177+ ) -> Dict [str , str ]:
178+ """
179+ Prompt user to select which environment variables to upload as secrets.
180+ Returns the selected secrets.
181+ """
182+ if not secrets :
183+ return {}
184+
185+ if non_interactive :
186+ return secrets
187+
188+ # Check if running in a non-TTY environment (e.g., CI/CD)
189+ if not sys .stdin .isatty ():
190+ return secrets
191+
192+ try :
193+ import questionary
194+
195+ custom_style = _get_questionary_style ()
196+
197+ # Build choices with source info and masked values
198+ choices = []
199+ for key , value in secrets .items ():
200+ source = ".env" if key in secrets_from_env_file else "env"
201+ masked = _mask_secret_value (value )
202+ label = f"{ key } ({ source } : { masked } )"
203+ choices .append (questionary .Choice (title = label , value = key , checked = True ))
204+
205+ if len (choices ) == 0 :
206+ return {}
207+
208+ print ("\n Found environment variables to upload as Fireworks secrets:" )
209+ selected_keys = questionary .checkbox (
210+ "Select secrets to upload:" ,
211+ choices = choices ,
212+ style = custom_style ,
213+ pointer = ">" ,
214+ instruction = "(↑↓ move, space select, enter confirm)" ,
215+ ).ask ()
216+
217+ if selected_keys is None :
218+ # User cancelled with Ctrl+C
219+ print ("\n Secret upload cancelled." )
220+ return {}
221+
222+ return {k : v for k , v in secrets .items () if k in selected_keys }
223+
224+ except ImportError :
225+ # Fallback to simple text-based selection
226+ return _prompt_select_secrets_fallback (secrets , secrets_from_env_file )
227+ except KeyboardInterrupt :
228+ print ("\n \n Secret upload cancelled." )
229+ return {}
230+
231+
232+ def _prompt_select_secrets_fallback (
233+ secrets : Dict [str , str ],
234+ secrets_from_env_file : Dict [str , str ],
235+ ) -> Dict [str , str ]:
236+ """Fallback prompt selection for when questionary is not available."""
237+ print ("\n " + "=" * 60 )
238+ print ("Found environment variables to upload as Fireworks secrets:" )
239+ print ("=" * 60 )
240+ print ("\n Tip: Install questionary for better UX: pip install questionary\n " )
241+
242+ secret_list = list (secrets .items ())
243+ for idx , (key , value ) in enumerate (secret_list , 1 ):
244+ source = ".env" if key in secrets_from_env_file else "env"
245+ masked = _mask_secret_value (value )
246+ print (f" [{ idx } ] { key } ({ source } : { masked } )" )
247+
248+ print ("\n " + "=" * 60 )
249+ print ("Enter numbers to select (comma-separated), 'all' for all, or 'none' to skip:" )
250+
251+ try :
252+ choice = input ("Selection: " ).strip ().lower ()
253+ except KeyboardInterrupt :
254+ print ("\n Secret upload cancelled." )
255+ return {}
256+
257+ if not choice or choice == "none" :
258+ return {}
259+
260+ if choice == "all" :
261+ return secrets
262+
263+ try :
264+ indices = [int (x .strip ()) for x in choice .split ("," )]
265+ selected = {}
266+ for idx in indices :
267+ if 1 <= idx <= len (secret_list ):
268+ key , value = secret_list [idx - 1 ]
269+ selected [key ] = value
270+ return selected
271+ except ValueError :
272+ print ("Invalid input. Skipping secret upload." )
273+ return {}
274+
275+
173276def upload_command (args : argparse .Namespace ) -> int :
174277 root = os .path .abspath (getattr (args , "path" , "." ))
175278 entries_arg = getattr (args , "entry" , None )
@@ -181,7 +284,7 @@ def upload_command(args: argparse.Namespace) -> int:
181284 qualname , resolved_path = _resolve_entry_to_qual_and_source (e , root )
182285 selected_specs .append ((qualname , resolved_path ))
183286 else :
184- selected_tests = _discover_and_select_tests (root , non_interactive = non_interactive )
287+ selected_tests : list [ DiscoveredTest ] | None = _discover_and_select_tests (root , non_interactive = non_interactive )
185288 if not selected_tests :
186289 return 1
187290 selected_specs = [(t .qualname , t .file_path ) for t in selected_tests ]
@@ -212,24 +315,34 @@ def upload_command(args: argparse.Namespace) -> int:
212315 secrets_from_file ["FIREWORKS_API_KEY" ] = fw_api_key_value
213316
214317 if fw_account_id and secrets_from_file :
215- print (f"Found { len (secrets_from_file )} API keys to upload as Fireworks secrets..." )
216318 if secrets_from_env_file and os .path .exists (env_file_path ):
217319 print (f"Loading secrets from: { env_file_path } " )
218320
219- for secret_name , secret_value in secrets_from_file .items ():
220- source = ".env" if secret_name in secrets_from_env_file else "environment"
221- print (
222- f"Ensuring { secret_name } is registered as a secret on Fireworks for rollout... "
223- f"({ source } : { _mask_secret_value (secret_value )} )"
224- )
225- if create_or_update_fireworks_secret (
226- account_id = fw_account_id ,
227- key_name = secret_name ,
228- secret_value = secret_value ,
229- ):
230- print (f"✓ { secret_name } secret created/updated on Fireworks." )
231- else :
232- print (f"Warning: Failed to create/update { secret_name } secret on Fireworks." )
321+ # Prompt user to select which secrets to upload
322+ selected_secrets = _prompt_select_secrets (
323+ secrets_from_file ,
324+ secrets_from_env_file ,
325+ non_interactive ,
326+ )
327+
328+ if selected_secrets :
329+ print (f"\n Uploading { len (selected_secrets )} selected secret(s) to Fireworks..." )
330+ for secret_name , secret_value in selected_secrets .items ():
331+ source = ".env" if secret_name in secrets_from_env_file else "environment"
332+ print (
333+ f"Ensuring { secret_name } is registered as a secret on Fireworks for rollout... "
334+ f"({ source } : { _mask_secret_value (secret_value )} )"
335+ )
336+ if create_or_update_fireworks_secret (
337+ account_id = fw_account_id ,
338+ key_name = secret_name ,
339+ secret_value = secret_value ,
340+ ):
341+ print (f"✓ { secret_name } secret created/updated on Fireworks." )
342+ else :
343+ print (f"Warning: Failed to create/update { secret_name } secret on Fireworks." )
344+ else :
345+ print ("No secrets selected for upload." )
233346 else :
234347 if not fw_account_id :
235348 print (
0 commit comments