name: Security & Safety Checks

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]
  schedule:
    # Run weekly on Monday at 9am UTC
    - cron: '0 9 * * 1'
  workflow_dispatch:

permissions:
  contents: read
  security-events: write
  actions: read

jobs:
  dependency-scan:
    name: Dependency Vulnerability Scan
    runs-on: ubuntu-latest

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

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

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install safety pip-audit

      - name: Run safety check
        continue-on-error: true
        run: |
          safety check --json --output safety-report.json || true
          safety check

      - name: Run pip-audit
        continue-on-error: true
        run: |
          pip-audit --format json --output pip-audit-report.json || true
          pip-audit

      - name: Upload vulnerability reports
        uses: actions/upload-artifact@v4
        with:
          name: dependency-vulnerability-reports
          path: |
            safety-report.json
            pip-audit-report.json
          retention-days: 90

  sast-scan:
    name: Static Application Security Testing
    runs-on: ubuntu-latest

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

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

      - name: Install bandit
        run: pip install bandit[toml]

      - name: Run bandit security linter
        run: |
          bandit -r . \
            -f json \
            -o bandit-report.json \
            --exclude './tests/*,./venv/*,./.venv/*,*/site-packages/*' \
            -ll || true

          bandit -r . \
            -f screen \
            --exclude './tests/*,./venv/*,./.venv/*,*/site-packages/*' \
            -ll

      - name: Upload SAST report
        uses: actions/upload-artifact@v4
        with:
          name: sast-report
          path: bandit-report.json
          retention-days: 90

  secret-scan:
    name: Secret Detection
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history for secret scanning

      - name: Run Gitleaks
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE}}

  codeql:
    name: CodeQL Analysis
    runs-on: ubuntu-latest

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

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: python, javascript
          queries: security-and-quality

      - name: Autobuild
        uses: github/codeql-action/autobuild@v3

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3
        with:
          category: "/language:python"

  license-check:
    name: License Compliance Check
    runs-on: ubuntu-latest

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

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

      - name: Install pip-licenses
        run: pip install pip-licenses

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

      - name: Check licenses
        run: |
          echo "Generating license report..."
          pip-licenses --format=json --output-file=licenses.json
          pip-licenses --format=markdown --output-file=licenses.md

          # Check for problematic licenses (GPL, AGPL, etc.)
          PROBLEMATIC=$(pip-licenses --format=json | jq -r '.[] | select(.License | test("GPL|AGPL")) | .Name')

          if [ -n "$PROBLEMATIC" ]; then
            echo "⚠️ Warning: Found packages with potentially problematic licenses:"
            echo "$PROBLEMATIC"
            # Don't fail the build, just warn
          else
            echo "✅ No problematic licenses found"
          fi

      - name: Upload license report
        uses: actions/upload-artifact@v4
        with:
          name: license-report
          path: |
            licenses.json
            licenses.md
          retention-days: 90

  container-scan:
    name: Container Image Scan
    runs-on: ubuntu-latest
    if: github.event_name != 'schedule'

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

      - name: Build Docker image
        run: docker build -t security-scan:${{ github.sha }} .

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: security-scan:${{ github.sha }}
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'

      - name: Upload Trivy results to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: 'trivy-results.sarif'

      - name: Run Trivy for readable output
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: security-scan:${{ github.sha }}
          format: 'table'
          severity: 'CRITICAL,HIGH,MEDIUM'

  summary:
    name: Security Summary
    needs: [dependency-scan, sast-scan, secret-scan, license-check]
    runs-on: ubuntu-latest
    if: always()

    steps:
      - name: Security check summary
        run: |
          echo "### Security Scan Results"
          echo ""
          echo "- Dependency Scan: ${{ needs.dependency-scan.result }}"
          echo "- SAST Scan: ${{ needs.sast-scan.result }}"
          echo "- Secret Scan: ${{ needs.secret-scan.result }}"
          echo "- License Check: ${{ needs.license-check.result }}"
          echo ""

          if [ "${{ needs.secret-scan.result }}" == "failure" ]; then
            echo "❌ CRITICAL: Secrets detected in repository!"
            exit 1
          fi

          if [ "${{ needs.dependency-scan.result }}" == "failure" ] || \
             [ "${{ needs.sast-scan.result }}" == "failure" ]; then
            echo "⚠️ Security vulnerabilities detected. Review the reports."
            # Don't fail the build for vulnerability warnings
          else
            echo "✅ No critical security issues detected"
          fi
