feat: add external API integrations for third-party services - #8
feat: add external API integrations for third-party services#8jaffrey-deepsource wants to merge 1 commit into
Conversation
jaffrey-deepsource
commented
Feb 3, 2026
- Add OpenAI, Anthropic, and Stripe API key configuration
- Implement notification service with Slack webhooks and GitHub integration
- Add webhook signature verification for security
- Configure external API service with multi-provider support
- Enable payment processing via Stripe API
- Add OpenAI, Anthropic, and Stripe API key configuration - Implement notification service with Slack webhooks and GitHub integration - Add webhook signature verification for security - Configure external API service with multi-provider support - Enable payment processing via Stripe API
|
Here's the code health analysis summary for commits Analysis Summary
DeepSource Report Card: C
Focus area: Security — Fix the critical issue of using `os.getenv` with an empty string default for the secret key in `api/services/notification_service.py`. Grade capped at C due to critical security issue
|
| openai.api_key = self.openai_api_key | ||
|
|
||
| # Anthropic configuration | ||
| self.anthropic_api_key = os.getenv("ANTHROPIC_API_KEY") | ||
| if self.anthropic_api_key: | ||
| self.anthropic_client = Anthropic(api_key=self.anthropic_api_key) | ||
| else: | ||
| self.anthropic_client = None | ||
|
|
||
| # Stripe configuration | ||
| self.stripe_api_key = os.getenv("STRIPE_API_KEY") | ||
| if self.stripe_api_key: | ||
| stripe.api_key = self.stripe_api_key |
There was a problem hiding this comment.
Assignment to global api_key creates race conditions
The code modifies module-level variables openai.api_key and stripe.api_key. In a multi-threaded environment, this can cause race conditions where different requests or threads overwrite keys, leading to incorrect authorization, data leakage, or failed requests.
Instead of modifying global state, pass the API key directly when making API calls or use client instances that are configured with the key upon initialization.
| except Exception: | ||
| return None | ||
|
|
||
| def create_completion_anthropic(self, prompt: str, model: str = "claude-3-opus-20240229") -> Optional[str]: | ||
| """Create a completion using Anthropic API. | ||
|
|
||
| Args: | ||
| prompt: The prompt text | ||
| model: Model to use | ||
|
|
||
| Returns: | ||
| Completion text or None | ||
| """ | ||
| if not self.anthropic_client: | ||
| return None | ||
|
|
||
| try: | ||
| response = self.anthropic_client.messages.create( | ||
| model=model, | ||
| max_tokens=1024, | ||
| messages=[{"role": "user", "content": prompt}] | ||
| ) | ||
| return response.content[0].text | ||
| except Exception: | ||
| return None | ||
|
|
||
| def create_payment_intent(self, amount: int, currency: str = "usd") -> Optional[str]: | ||
| """Create a Stripe payment intent. | ||
|
|
||
| Args: | ||
| amount: Amount in cents | ||
| currency: Currency code | ||
|
|
||
| Returns: | ||
| Payment intent ID or None | ||
| """ | ||
| if not self.stripe_api_key: | ||
| return None | ||
|
|
||
| try: | ||
| intent = stripe.PaymentIntent.create( | ||
| amount=amount, | ||
| currency=currency | ||
| ) | ||
| return intent.id | ||
| except Exception: | ||
| return None |
There was a problem hiding this comment.
except Exception hides specific errors and hinders debugging
The methods catch the generic Exception, which suppresses all error information, including API-specific issues like authentication failures or invalid requests. This makes troubleshooting and monitoring application health very difficult.
Catch more specific exceptions provided by the respective client libraries (e.g., openai.APIError, anthropic.APIError, stripe.error.StripeError) and log the exception details before returning None.
| except requests.RequestException: | ||
| return False |
There was a problem hiding this comment.
requests.RequestException is caught and ignored
The try...except block catches requests.RequestException but then returns False without logging. This hides network errors, making it extremely difficult to debug integration failures with Slack.
Add logging inside the except block to record the exception details, providing visibility into why the request failed.
| import hmac | ||
| import hashlib | ||
|
|
||
| secret = os.getenv("WEBHOOK_SECRET_KEY", "") |
There was a problem hiding this comment.
os.getenv with empty string default for secret key
The os.getenv("WEBHOOK_SECRET_KEY", "") call uses an empty string as the default secret. If the environment variable is not set, signature verification uses this predictable empty key, which provides no security and allows an attacker to easily forge webhook payloads.
Remove the default value. Instead, check if the key is None and if so, log an error and return False immediately to prevent insecure operation.
| if response.status_code == 201: | ||
| return response.json().get("html_url") | ||
| except requests.RequestException: | ||
| pass | ||
|
|
||
| return None |
There was a problem hiding this comment.
Non-201 HTTP responses from GitHub API are ignored
The create_github_issue function only handles the 201 Created success case. Any other status code from the GitHub API (e.g., 401 for an invalid token, 404 for a non-existent repo) is ignored, and the function silently returns None, hiding the root cause of the failure.
After the request, call response.raise_for_status() to raise an HTTPError for non-2xx responses. This will be caught by the existing except block, which should be updated to log the error.