Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 0 additions & 50 deletions .github/workflows/ci-simple.yml

This file was deleted.

181 changes: 17 additions & 164 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,126 +1,21 @@
# GitHub Actions CI Workflow for StockSense Agent
# This workflow runs automated tests on every push and pull request to main branch
# Validates code, tests, and Docker builds on every push/pull_request to main.

name: Python Application CI
name: CI - StockSense Agent

# Trigger Configuration
# Runs on pushes to main branch and all pull requests targeting main
on:
push:
branches: [main]
pull_request:
branches: [main]

# Define CI Jobs
jobs:
build:
# Job Configuration
name: Build and Test
test-and-validate:
name: Run Tests and Validate Docker Images
runs-on: ubuntu-latest

# Define build steps
steps:
# Step 1: Checkout Repository Code
- name: Checkout code
uses: actions/checkout@v4
with:
# Fetch full history for better Git operations
fetch-depth: 0

# Step 2: Set up Python Environment
- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: '3.10'
# Cache pip dependencies for faster builds
cache: 'pip'

# Step 3: Install Dependencies
- name: Upgrade pip
run: |
python -m pip install --upgrade pip

- name: Install project dependencies
run: |
pip install -r requirements.txt

- name: Install testing dependencies
run: |
pip install pytest requests

# Step 4: Run Linting (Optional but recommended)
- name: Run code quality checks
run: |
# Install flake8 for linting
pip install flake8
# Stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# Exit-zero treats all errors as warnings. GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
continue-on-error: true

# Step 5: Run Unit Tests (No external dependencies required)
- name: Run unit tests
run: |
# Run only unit tests that don't require external services
python run_tests.py unit
env:
# Set environment variables from GitHub secrets
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
NEWSAPI_KEY: ${{ secrets.NEWSAPI_KEY }}

# Step 6: Run Smoke Tests (Quick validation)
- name: Run smoke tests
run: |
# Run quick smoke tests for basic functionality validation
python run_tests.py smoke
env:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
NEWSAPI_KEY: ${{ secrets.NEWSAPI_KEY }}

# Step 7: Run Full Test Suite with Coverage (Optional)
- name: Run tests with coverage
run: |
# Install coverage tool
pip install coverage
# Run pytest with coverage reporting
coverage run -m pytest tests/test_tools.py -v
# Generate coverage report
coverage report -m
# Generate HTML coverage report
coverage html
env:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
NEWSAPI_KEY: ${{ secrets.NEWSAPI_KEY }}
continue-on-error: true

# Step 8: Upload Coverage Reports (Optional)
- name: Upload coverage reports
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: htmlcov/
if: always()

# Step 9: Upload Test Results
- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
.pytest_cache/
test-results.xml
if: always()

# Additional Jobs for Different Scenarios
integration-tests:
# Only run integration tests if unit tests pass
needs: build
name: Integration Tests
runs-on: ubuntu-latest

steps:
- name: Checkout code
- name: Checkout Repository
uses: actions/checkout@v4

- name: Set up Python 3.10
Expand All @@ -129,66 +24,24 @@ jobs:
python-version: '3.10'
cache: 'pip'

- name: Install dependencies
- name: Install All Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest requests
pip install -r requirements-backend.txt
pip install -r requirements-frontend.txt
pip install pytest pytest-cov

# Start the API server in background for integration tests
- name: Start API server
run: |
# Start the StockSense API server in background
python -m stocksense.main &
# Wait for server to start
sleep 10
- name: Run Test Suite
env:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
NEWSAPI_KEY: ${{ secrets.NEWSAPI_KEY }}
run: pytest

- name: Run integration tests
run: |
# Run API integration tests
python run_tests.py api
env:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
NEWSAPI_KEY: ${{ secrets.NEWSAPI_KEY }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# Security and Code Quality Job
security-scan:
name: Security Scan
runs-on: ubuntu-latest
- name: Validate Backend Docker Image
run: docker build -f Dockerfile.backend -t stocksense-backend-ci .

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python 3.10
uses: actions/setup-python@v5
with:
python-version: '3.10'

- name: Install security tools
run: |
python -m pip install --upgrade pip
pip install safety bandit

- name: Run safety check
run: |
# Check for known security vulnerabilities in dependencies
safety check --file requirements.txt
continue-on-error: true

- name: Run bandit security scan
run: |
# Run security analysis on Python code
bandit -r stocksense/ -f json -o bandit-report.json
continue-on-error: true

- name: Upload security reports
uses: actions/upload-artifact@v4
with:
name: security-reports
path: |
bandit-report.json
if: always()
- name: Validate Frontend Docker Image
run: docker build -f Dockerfile.frontend -t stocksense-frontend-ci .
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,11 @@ env/
/venv/
.conda/
deploy_test_env/
docker-compose.yml
docker-compose.override.yml

# Local database (explicit)
stocksense.db
*.db

# =============================================================================
# -- Editor & IDE Files --
Expand Down
15 changes: 5 additions & 10 deletions Dockerfile.backend
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@ FROM python:3.10-slim
# Set working directory
WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
g++ \
curl \
&& rm -rf /var/lib/apt/lists/*
# No system packages needed; keep image minimal to reduce vulnerabilities

# Copy requirements first (for better caching)
COPY requirements.txt .
COPY requirements-backend.txt .

# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir -r requirements-backend.txt

# Copy application code
COPY . .
Expand All @@ -26,9 +21,9 @@ RUN mkdir -p /app/data
# Expose port for FastAPI backend
EXPOSE 8000

# Health check for backend API
# Health check for backend API (no curl dependency)
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
CMD python -c "import sys, requests; sys.exit(0) if requests.get('http://localhost:8000/health', timeout=5).ok else sys.exit(1)"

# Run the FastAPI backend application
CMD ["uvicorn", "stocksense.main:app", "--host", "0.0.0.0", "--port", "8000"]
15 changes: 5 additions & 10 deletions Dockerfile.frontend
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@ FROM python:3.10-slim
# Set working directory
WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
g++ \
curl \
&& rm -rf /var/lib/apt/lists/*
# No system packages needed; keep image minimal to reduce vulnerabilities

# Copy requirements first (for better caching)
COPY requirements.txt .
COPY requirements-frontend.txt .

# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir -r requirements-frontend.txt

# Copy application code
COPY . .
Expand All @@ -33,9 +28,9 @@ RUN echo '[server]' > ~/.streamlit/config.toml && \
echo 'enableCORS = false' >> ~/.streamlit/config.toml && \
echo 'enableXsrfProtection = false' >> ~/.streamlit/config.toml

# Health check
# Health check (no curl dependency)
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8501/_stcore/health || exit 1
CMD python -c "import sys, requests; sys.exit(0) if requests.get('http://localhost:8501/_stcore/health', timeout=5).ok else sys.exit(1)"

# Run Streamlit app
CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
Loading
Loading