name: Security Scan

on:
  push:
    branches: [ master, develop ]
  pull_request:
    branches: [ master ]
  schedule:
    # Weekly on Monday at 6:00 UTC
    - cron: '0 6 * * 1'

permissions:
  contents: read

jobs:
  security:
    name: Security Analysis
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v6

    - name: Set up Python
      uses: actions/setup-python@v6
      with:
        python-version: "3.10"

    - name: Cache pip dependencies
      uses: actions/cache@v5
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-security-${{ hashFiles('**/requirements.txt') }}
        restore-keys: |
          ${{ runner.os }}-pip-security-

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

    - name: Run Bandit (code security)
      run: |
        echo "=== Running Bandit Security Scan ==="
        bandit \
          -c .bandit.yml \
          -r rdagent/ \
          -f json \
          -o bandit-report.json \
          --exit-zero || true

        # Show summary
        bandit -c .bandit.yml -r rdagent/ -ll || true

    - name: Upload Bandit report
      uses: actions/upload-artifact@v7
      if: always()
      with:
        name: bandit-security-report
        path: bandit-report.json
        retention-days: 30

    - name: Check dependencies for vulnerabilities
      run: |
        echo "=== Checking Dependencies for Vulnerabilities ==="
        safety check --json || {
          echo "::warning::Some dependencies have known vulnerabilities"
          echo "Please review and update dependencies."
          exit 0  # Non-blocking
        }

    - name: Check for exposed secrets
      run: |
        echo "=== Scanning for Exposed Secrets ==="

        # Check for common secret patterns
        PATTERNS=(
          "api_key\s*=\s*['\"][^'\"]+['\"]"
          "secret\s*=\s*['\"][^'\"]+['\"]"
          "password\s*=\s*['\"][^'\"]+['\"]"
          "token\s*=\s*['\"][^'\"]+['\"]"
          "PRIVATE.KEY"
          "BEGIN RSA PRIVATE KEY"
        )

        FOUND_SECRETS=0
        for pattern in "${PATTERNS[@]}"; do
          if grep -rInE "$pattern" --include='*.py' --include='*.yml' --include='*.yaml' --include='*.json' . | \
             grep -v '.git' | \
             grep -v 'test/' | \
             grep -v 'example' | \
             grep -v '# ' | \
             grep -v 'os.environ' | \
             grep -v 'getenv' | \
             grep -v 'argparse'; then
            FOUND_SECRETS=1
          fi
        done

        if [ $FOUND_SECRETS -eq 1 ]; then
          echo "::error::Potential secrets exposure detected!"
          echo "Please review the output above and remove any hardcoded credentials."
          echo "Use environment variables or .env files instead."
          exit 1
        fi

        echo "✓ No exposed secrets found"

    - name: Verify closed-source files not committed
      run: |
        echo "=== Verifying No Closed-Source Assets Committed ==="

        FOUND_CLOSED=0

        # Exact directory prefixes that must never appear (use grep -F for literal matching)
        EXACT_PREFIXES=(
          "git_ignore_folder/"
          "models/local/"
          "prompts/local/"
          "rdagent/scenarios/qlib/local/"
        )
        for prefix in "${EXACT_PREFIXES[@]}"; do
          if git ls-files | grep -qF "$prefix"; then
            echo "::error::Found closed-source asset: $prefix"
            FOUND_CLOSED=1
          fi
        done

        # results/ — allow README.md and .gitkeep but nothing else
        if git ls-files | grep -F "results/" | grep -qvE "results/README\.md|results/\.gitkeep"; then
          echo "::error::Found closed-source asset: results/ (non-documentation file)"
          git ls-files | grep -F "results/" | grep -vE "results/README\.md|results/\.gitkeep"
          FOUND_CLOSED=1
        fi

        # .env files — match only .env and .env.* exactly, not paths containing "env"
        if git ls-files | grep -qE "(^|/)\.env($|\.)"; then
          echo "::error::Found closed-source asset: .env file"
          FOUND_CLOSED=1
        fi

        # Binary / data files that must never be committed
        if git ls-files | grep -qE "\.(db|h5|parquet|log)$"; then
          echo "::error::Found data/log file committed (*.db, *.h5, *.parquet, *.log)"
          git ls-files | grep -E "\.(db|h5|parquet|log)$"
          FOUND_CLOSED=1
        fi

        if [ $FOUND_CLOSED -eq 1 ]; then
          echo "CRITICAL: Closed-source assets must not be committed to the repository!"
          echo "Please remove them and add to .gitignore if needed."
          exit 1
        fi

        echo "✓ No closed-source assets found"
