From 9fc699a3862fa9409d8759c75b5fea52d7a4f34f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 11 Nov 2025 09:45:48 +0000 Subject: [PATCH 1/2] Add security improvements and environment configuration ## Security Enhancements - Add missing `requests` import in utils.py (CRITICAL BUG FIX) - Implement URL validation before webbrowser.open() calls - Add validate_url() function to check URL safety - Replace hardcoded email with UNPAYWALL_EMAIL environment variable ## Configuration - Create .env.example documenting all environment variables - Add support for UNPAYWALL_EMAIL configuration ## Changes - quantcli/utils.py: Add requests import, urlparse, validate_url() - quantcli/cli.py: Add URL validation to browser operations - quantcli/gui.py: Add URL validation to browser operations - .env.example: Document all configurable environment variables These changes improve security by validating all URLs before opening them in the browser and fix the critical missing requests import bug. --- .env.example | 19 +++++++++++++++++++ quantcli/cli.py | 18 +++++++++++++----- quantcli/gui.py | 7 ++++++- quantcli/utils.py | 43 +++++++++++++++++++++++++++++++++++++++---- 4 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..27b4f7af --- /dev/null +++ b/.env.example @@ -0,0 +1,19 @@ +# QuantCLI Environment Configuration +# Copy this file to .env and fill in your values + +# Required: OpenAI API Key for LLM generation +OPENAI_API_KEY=your_openai_api_key_here + +# Optional: OpenAI Model to use (default: gpt-4o-2024-11-20) +OPENAI_MODEL=gpt-4o-2024-11-20 + +# Optional: Maximum attempts to refine generated code (default: 6) +MAX_REFINE_ATTEMPTS=6 + +# Optional: Email for Unpaywall API (for downloading PDFs) +UNPAYWALL_EMAIL=your.email@example.com + +# Optional: File paths and directories +ARTICLES_FILE=articles.json +DOWNLOADS_DIR=downloads +GENERATED_CODE_DIR=generated_code diff --git a/quantcli/cli.py b/quantcli/cli.py index b0a284ec..c2dd19ab 100644 --- a/quantcli/cli.py +++ b/quantcli/cli.py @@ -5,7 +5,7 @@ import json # Lazy import for GUI to avoid tkinter dependency from .processor import ArticleProcessor -from .utils import setup_logging, load_api_key, download_pdf +from .utils import setup_logging, load_api_key, download_pdf, validate_url from .search import search_crossref, save_to_html import logging import webbrowser @@ -115,8 +115,12 @@ def download(article_id): click.echo("Failed to download the PDF. You can open the article's webpage instead.") open_manual = click.confirm("Would you like to open the article URL in your browser for manual download?", default=True) if open_manual: - webbrowser.open(article["URL"]) - click.echo("Opened the article URL in your default web browser.") + url = article["URL"] + if validate_url(url): + webbrowser.open(url) + click.echo("Opened the article URL in your default web browser.") + else: + click.echo(f"Invalid or unsafe URL: {url}") @cli.command() @click.argument('article_id', type=int) @@ -206,8 +210,12 @@ def open_article(article_id): return article = articles[article_id - 1] - webbrowser.open(article["URL"]) - click.echo(f"Opened article URL: {article['URL']}") + url = article["URL"] + if validate_url(url): + webbrowser.open(url) + click.echo(f"Opened article URL: {url}") + else: + click.echo(f"Invalid or unsafe URL: {url}") @cli.command() def interactive(): diff --git a/quantcli/gui.py b/quantcli/gui.py index 65bb1adb..60a3f204 100644 --- a/quantcli/gui.py +++ b/quantcli/gui.py @@ -7,6 +7,7 @@ import os import logging from .processor import ArticleProcessor +from .utils import validate_url import webbrowser from pygments import lex from pygments.lexers import PythonLexer @@ -157,7 +158,11 @@ def open_selected_article(self): def open_article_by_id(self, index): try: article = self.articles[index] - webbrowser.open(article["URL"]) + url = article["URL"] + if validate_url(url): + webbrowser.open(url) + else: + messagebox.showerror("Invalid URL", f"The URL is invalid or unsafe: {url}") except IndexError: messagebox.showwarning("Invalid Index", f"Article at index {index} not found.") diff --git a/quantcli/utils.py b/quantcli/utils.py index b63e5996..7604ab76 100644 --- a/quantcli/utils.py +++ b/quantcli/utils.py @@ -3,8 +3,9 @@ import logging from dotenv import load_dotenv import os -# OpenAI import removed - now handled by llm_client module -from typing import Optional # Import Optional +import requests +from typing import Optional +from urllib.parse import urlparse def setup_logging(verbose: bool = False): """ @@ -97,8 +98,8 @@ def download_pdf(article_url: str, save_path: str, doi: Optional[str] = None) -> else: logger.info("Direct download unsuccessful. Attempting to use Unpaywall.") if doi: - # Replace 'your.email@example.com' with your actual email - unpaywall_email = "your.email@example.com" + # Get email from environment variable + unpaywall_email = os.getenv("UNPAYWALL_EMAIL", "your.email@example.com") pdf_url = get_pdf_url_via_unpaywall(doi, unpaywall_email) if pdf_url: response = requests.get(pdf_url, headers=headers) @@ -113,3 +114,37 @@ def download_pdf(article_url: str, save_path: str, doi: Optional[str] = None) -> except requests.exceptions.RequestException as e: logger.error(f"Failed to download PDF: {e}") return False + + +def validate_url(url: str) -> bool: + """ + Validate if a URL is safe to open in a web browser. + + Args: + url (str): The URL to validate. + + Returns: + bool: True if URL is valid and safe, False otherwise. + """ + logger = logging.getLogger(__name__) + try: + if not url or not isinstance(url, str): + logger.warning("Invalid URL: empty or not a string") + return False + + parsed = urlparse(url) + + # Check if scheme is http or https + if parsed.scheme not in ['http', 'https']: + logger.warning(f"Invalid URL scheme: {parsed.scheme}") + return False + + # Check if netloc (domain) exists + if not parsed.netloc: + logger.warning("Invalid URL: missing domain") + return False + + return True + except Exception as e: + logger.error(f"Error validating URL: {e}") + return False From 79e862615e80ebf13986ad2f9226f2940ffb1c0e Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 11 Nov 2025 09:55:13 +0000 Subject: [PATCH 2/2] Add comprehensive testing guide for v1.0.0 - Installation verification steps - Security testing procedures - Example workflows - Troubleshooting guide - Complete CLI command reference --- TESTING_GUIDE.md | 331 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 TESTING_GUIDE.md diff --git a/TESTING_GUIDE.md b/TESTING_GUIDE.md new file mode 100644 index 00000000..9f77bc39 --- /dev/null +++ b/TESTING_GUIDE.md @@ -0,0 +1,331 @@ +# QuantCoder CLI v1.0.0 - Testing Guide + +## ๐ŸŽ‰ Installation Complete! + +Your QuantCoder CLI is now installed with all security improvements and modernizations. + +--- + +## โœ… What's Been Improved + +### Critical Bug Fixes +- โœ… Added missing `requests` import in `utils.py` +- โœ… Fixed OpenAI SDK migration (0.28 โ†’ 1.x+) +- โœ… Added LLMClient abstraction layer + +### Security Enhancements +- โœ… URL validation before opening in browser +- โœ… `validate_url()` function to check URL safety +- โœ… Blocks unsafe URLs (javascript:, ftp:, etc.) +- โœ… Environment variable support for sensitive data + +### Architecture Improvements +- โœ… OpenAI SDK 1.x+ with proper error handling +- โœ… Lazy tkinter imports (no GUI dependency for CLI) +- โœ… Defensive programming patterns in code generation +- โœ… Token usage tracking + +--- + +## ๐Ÿš€ Quick Start + +### 1. Activate Virtual Environment + +```bash +source .venv/bin/activate +``` + +### 2. Download spaCy Language Model (Required) + +```bash +# Try direct download +python -m spacy download en_core_web_sm + +# If that fails, use pip +pip install https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-tar.gz +``` + +### 3. Configure Environment Variables + +```bash +# Copy example file +cp .env.example .env + +# Edit .env and add your API key +nano .env # or use your preferred editor +``` + +Required in `.env`: +```bash +OPENAI_API_KEY=your_actual_openai_api_key_here +``` + +Optional: +```bash +OPENAI_MODEL=gpt-4o-2024-11-20 +UNPAYWALL_EMAIL=your.email@example.com +MAX_REFINE_ATTEMPTS=6 +``` + +--- + +## ๐Ÿงช Testing the CLI + +### Test 1: Basic Commands + +```bash +# Activate environment +source .venv/bin/activate + +# Test help +quantcli --help + +# Test hello command +quantcli hello +``` + +**Expected Output:** +``` +Hello from QuantCLI! +``` + +### Test 2: Search for Articles + +```bash +quantcli search "algorithmic trading momentum" --num 3 +``` + +**Expected Output:** +- List of 3 articles from CrossRef +- Articles saved to `articles.json` +- Option to save to HTML + +**Security Test:** URLs are validated before opening in browser. + +### Test 3: List Saved Articles + +```bash +quantcli list +``` + +**Expected Output:** +- Shows previously searched articles from `articles.json` + +### Test 4: Download Article PDF + +```bash +quantcli download 1 +``` + +**Expected Output:** +- PDF downloaded to `downloads/article_1.pdf`, OR +- Prompt to open article URL in browser (with URL validation) + +### Test 5: Generate Trading Code from PDF + +```bash +# First, make sure you have a PDF in downloads/ +quantcli generate-code 1 +``` + +**Expected Output:** +- Article summary displayed +- QuantConnect algorithm code generated +- Code saved to `generated_code/algorithm_1.py` + +### Test 6: Interactive Mode (GUI) + +```bash +quantcli interactive +``` + +**Expected Output:** +- GUI window opens (requires tkinter) +- Search interface with article list +- URL validation before opening articles + +**If tkinter not available:** +``` +โš ๏ธ Interactive mode requires tkinter (GUI library) +Install with: sudo apt-get install python3-tk +``` + +--- + +## ๐Ÿ”’ Security Testing + +### Test URL Validation + +Create a test script: + +```bash +source .venv/bin/activate +python << 'EOF' +from quantcli.utils import validate_url + +test_cases = [ + ("https://example.com", True, "Valid HTTPS URL"), + ("http://google.com", True, "Valid HTTP URL"), + ("javascript:alert(1)", False, "XSS attempt blocked"), + ("ftp://example.com", False, "Unsafe protocol blocked"), + ("", False, "Empty string blocked"), + ("not-a-url", False, "Invalid format blocked"), +] + +print("๐Ÿ”’ Security Test Results:\n") +for url, expected, description in test_cases: + result = validate_url(url) + status = "โœ… PASS" if result == expected else "โŒ FAIL" + print(f"{status}: {description}") + print(f" URL: '{url}' โ†’ {result}") + print() +EOF +``` + +**Expected:** All tests should PASS. + +--- + +## ๐Ÿ“Š Verification Checklist + +After testing, verify: + +- [ ] CLI commands work (help, hello, search) +- [ ] Article search returns results +- [ ] URL validation blocks unsafe URLs +- [ ] OpenAI API key is loaded from .env +- [ ] PDF download attempts work +- [ ] Code generation produces valid Python +- [ ] No errors about missing imports +- [ ] spaCy model is installed + +--- + +## ๐Ÿ› Troubleshooting + +### Issue: "Module not found" errors + +**Solution:** +```bash +source .venv/bin/activate +pip install -e . +``` + +### Issue: spaCy model not found + +**Solution:** +```bash +source .venv/bin/activate +python -m spacy download en_core_web_sm +``` + +### Issue: OpenAI API errors + +**Solution:** +- Check `.env` file has valid `OPENAI_API_KEY` +- Verify API key has credits: https://platform.openai.com/usage +- Check you're using OpenAI SDK 1.x+ (run `pip show openai`) + +### Issue: tkinter not available + +**Solution:** +```bash +# Ubuntu/Debian +sudo apt-get install python3-tk + +# macOS (should be included) +# No action needed + +# Use CLI commands instead of interactive mode +quantcli search "query" --num 5 +``` + +### Issue: PDF download fails + +**Reason:** Many academic articles are behind paywalls. + +**Solution:** +- Use `quantcli open-article ` to manually download +- Set `UNPAYWALL_EMAIL` in `.env` for open access attempts + +--- + +## ๐Ÿ“ Example Workflow + +Complete workflow to generate a trading algorithm: + +```bash +# 1. Activate environment +source .venv/bin/activate + +# 2. Search for articles +quantcli search "momentum trading strategy" --num 5 + +# 3. List results +quantcli list + +# 4. Download an article (e.g., #1) +quantcli download 1 + +# 5. Generate algorithm from PDF +quantcli generate-code 1 + +# 6. Check generated code +cat generated_code/algorithm_1.py +``` + +--- + +## ๐Ÿ”„ Switching Branches + +You're currently on: `refactor/modernize-2025` + +To switch to the remote branch with all improvements: + +```bash +# Option 1: Stay on current branch (already has all improvements) +git status + +# Option 2: Track remote branch explicitly +git checkout claude/refactor-modernize-2025-011CV1sadPRrxj5sPHjWp7Wa + +# Option 3: Create your own branch from current state +git checkout -b my-testing-branch +``` + +--- + +## ๐Ÿ“š Additional Resources + +- **CHANGELOG.md** - Full list of changes +- **README.md** - Project overview +- **.env.example** - Configuration options +- **quantcli/llm_client.py** - New LLM abstraction layer + +--- + +## ๐ŸŽฏ Next Steps + +1. โœ… Install spaCy model: `python -m spacy download en_core_web_sm` +2. โœ… Configure `.env` with your OpenAI API key +3. โœ… Run test workflow above +4. โœ… Try generating code from a real PDF +5. โœ… Report any issues on GitHub + +--- + +## ๐Ÿ“ง Need Help? + +If you encounter issues: + +1. Check this guide's Troubleshooting section +2. Review logs in `quantcli.log` +3. Run with `--verbose` flag: `quantcli --verbose search "query"` +4. Report issues at: https://github.com/SL-Mar/quantcoder-cli/issues + +--- + +**Version:** 1.0.0 +**Branch:** refactor/modernize-2025 +**Python:** >= 3.9 +**OpenAI SDK:** >= 1.0.0