Skip to content

Commit fae940d

Browse files
alidate API key early before initializing optimizer
1 parent a41d7cf commit fae940d

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

codeflash/api/cfapi.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,70 @@ def get_user_id(api_key: Optional[str] = None) -> Optional[str]:
120120
return None
121121

122122

123+
def validate_api_key(api_key: Optional[str] = None) -> None:
124+
"""Validate that the API key is valid by attempting to retrieve the user ID.
125+
126+
Raises OSError if the API key is invalid or missing.
127+
128+
:param api_key: The API key to validate. If None, uses get_codeflash_api_key().
129+
:raises OSError: If the API key is invalid or missing.
130+
"""
131+
# First check if API key exists
132+
if not api_key:
133+
api_key = get_codeflash_api_key()
134+
135+
# Make the request to validate the API key
136+
try:
137+
response = make_cfapi_request(
138+
endpoint="/cli-get-user",
139+
method="GET",
140+
extra_headers={"cli_version": __version__},
141+
api_key=api_key,
142+
suppress_errors=True # Don't log errors yet, we'll handle it below
143+
)
144+
145+
if response.status_code == 403:
146+
msg = (
147+
"Invalid Codeflash API key. The API key you provided is not valid.\n"
148+
"Please generate a new one at https://app.codeflash.ai/app/apikeys ,\n"
149+
"then set it as a CODEFLASH_API_KEY environment variable.\n"
150+
"For more information, refer to the documentation at "
151+
"https://docs.codeflash.ai/getting-started/codeflash-github-actions#add-your-api-key-to-your-repository-secrets."
152+
)
153+
raise OSError(msg)
154+
elif response.status_code != 200:
155+
msg = (
156+
f"Failed to validate API key with Codeflash API (status {response.status_code}).\n"
157+
"Please verify your API key is correct.\n"
158+
"You can generate a new one at https://app.codeflash.ai/app/apikeys"
159+
)
160+
raise OSError(msg)
161+
162+
# Check for version updates
163+
if response.status_code == 200:
164+
try:
165+
resp_json = response.json()
166+
min_version = resp_json.get("min_version")
167+
if min_version and version.parse(min_version) > version.parse(__version__):
168+
msg = "Your Codeflash CLI version is outdated. Please update to the latest version using `pip install --upgrade codeflash`."
169+
raise OSError(msg)
170+
except (json.JSONDecodeError, KeyError, TypeError):
171+
# If response is not JSON or doesn't have min_version, that's okay
172+
pass
173+
174+
except OSError:
175+
# Re-raise OSError as-is
176+
raise
177+
except Exception as e:
178+
# Wrap other exceptions
179+
msg = (
180+
f"Failed to validate API key: {e}\n"
181+
"Please verify your API key is correct.\n"
182+
"You can generate a new one at https://app.codeflash.ai/app/apikeys"
183+
)
184+
raise OSError(msg) from e
185+
186+
123187
def suggest_changes(
124188
owner: str,
125189
repo: str,

codeflash/optimization/optimizer.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from typing import TYPE_CHECKING
1111

1212
from codeflash.api.aiservice import AiServiceClient, LocalAiServiceClient
13-
from codeflash.api.cfapi import send_completion_email
13+
from codeflash.api.cfapi import send_completion_email, validate_api_key
1414
from codeflash.cli_cmds.console import console, logger, progress_bar
1515
from codeflash.code_utils import env_utils
1616
from codeflash.code_utils.code_utils import cleanup_paths, get_run_tmp_file
@@ -493,11 +493,24 @@ def mirror_path(path: Path, src_root: Path, dest_root: Path) -> Path:
493493
def run_with_args(args: Namespace) -> None:
494494
optimizer = None
495495
try:
496+
# Validate API key early before initializing optimizer
497+
validate_api_key()
498+
496499
optimizer = Optimizer(args)
497500
optimizer.run()
498501
except KeyboardInterrupt:
499502
logger.warning("Keyboard interrupt received. Cleaning up and exiting, please wait…")
500503
if optimizer:
501504
optimizer.cleanup_temporary_paths()
502-
503-
raise SystemExit from None
505+
raise SystemExit(0) from None
506+
except (OSError, Exception) as e:
507+
# Log the error if we have an optimizer instance with cleanup
508+
if optimizer:
509+
logger.error(f"Error during optimization: {e}")
510+
try:
511+
optimizer.cleanup_temporary_paths()
512+
except Exception:
513+
pass
514+
else:
515+
logger.error(f"Error initializing optimizer: {e}")
516+
raise

0 commit comments

Comments
 (0)