name: Security Audit

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]
  schedule:
    # Run security audit daily at 2 AM UTC
    - cron: "0 2 * * *"
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

jobs:
  security-audit:
    name: Security Vulnerability Scan
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
      issues: write

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

      - name: Setup Rust and cache
        uses: ./.github/actions/setup-rust-cached
        with:
          toolchain: stable
          components: clippy

      - name: Install security audit tools
        uses: ./.github/actions/install-cargo-tools
        with:
          tools: audit,deny,outdated
          cache-tools: "true"

      - name: Run cargo audit
        id: audit
        continue-on-error: true
        run: |
          echo "## 🔒 Cargo Audit Results" > audit-report.md
          echo "" >> audit-report.md
          if cargo audit --json > audit.json 2>&1; then
            echo "✅ **No vulnerabilities found**" >> audit-report.md
            echo "status=success" >> $GITHUB_OUTPUT
          else
            echo "⚠️ **Vulnerabilities detected**" >> audit-report.md
            echo "" >> audit-report.md
            echo "\`\`\`" >> audit-report.md
            cargo audit >> audit-report.md 2>&1 || true
            echo "\`\`\`" >> audit-report.md

            # Check for critical vulnerabilities
            if jq -e '.vulnerabilities.list[] | select(.advisory.severity == "critical")' audit.json > /dev/null 2>&1; then
              echo "has_critical=true" >> $GITHUB_OUTPUT
              echo "status=critical" >> $GITHUB_OUTPUT
            else
              echo "has_critical=false" >> $GITHUB_OUTPUT
              echo "status=warning" >> $GITHUB_OUTPUT
            fi
          fi

      - name: Run cargo deny
        id: deny
        continue-on-error: true
        run: |
          echo "" >> audit-report.md
          echo "## 📋 License & Dependency Check" >> audit-report.md
          echo "" >> audit-report.md
          if cargo deny check 2>&1 | tee deny-output.txt; then
            echo "✅ **All checks passed**" >> audit-report.md
            echo "status=success" >> $GITHUB_OUTPUT
          else
            echo "⚠️ **Issues detected**" >> audit-report.md
            echo "" >> audit-report.md
            echo "\`\`\`" >> audit-report.md
            cat deny-output.txt >> audit-report.md
            echo "\`\`\`" >> audit-report.md
            echo "status=failed" >> $GITHUB_OUTPUT
          fi

      - name: Run cargo outdated
        id: outdated
        continue-on-error: true
        run: |
          echo "" >> audit-report.md
          echo "## 📦 Dependency Freshness" >> audit-report.md
          echo "" >> audit-report.md
          if cargo outdated --exit-code 1 2>&1 | tee outdated-output.txt; then
            echo "✅ **All dependencies up to date**" >> audit-report.md
            echo "status=current" >> $GITHUB_OUTPUT
          else
            echo "⚠️ **Outdated dependencies found**" >> audit-report.md
            echo "" >> audit-report.md
            echo "\`\`\`" >> audit-report.md
            cat outdated-output.txt >> audit-report.md
            echo "\`\`\`" >> audit-report.md
            echo "status=outdated" >> $GITHUB_OUTPUT
          fi

      - name: Generate security summary
        run: |
          set -euo pipefail
          echo "" >> audit-report.md
          echo "---" >> audit-report.md
          echo "" >> audit-report.md
          echo "### Summary" >> audit-report.md
          echo "- 🔒 Vulnerability Scan: ${{ steps.audit.outputs.status }}" >> audit-report.md
          echo "- 📋 License Check: ${{ steps.deny.outputs.status }}" >> audit-report.md
          echo "- 📦 Dependencies: ${{ steps.outdated.outputs.status }}" >> audit-report.md
          echo "" >> audit-report.md
          echo "_Generated on $(date -u '+%Y-%m-%d %H:%M:%S UTC')_" >> audit-report.md

      - name: Upload security report
        uses: actions/upload-artifact@v4
        with:
          name: security-audit-report
          path: |
            audit-report.md
            audit.json
            deny-output.txt
            outdated-output.txt
          retention-days: 30

      - name: Comment PR with results
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const fs = require('fs');
            const report = fs.readFileSync('audit-report.md', 'utf8');

            const body = `# Security Audit Report\n\n${report}\n\n---\n*Automated security scan powered by cargo-audit, cargo-deny, and cargo-outdated*`;

            // Find existing comment
            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
            });

            const botComment = comments.find(comment =>
              comment.user.type === 'Bot' &&
              comment.body.includes('Security Audit Report')
            );

            if (botComment) {
              // Update existing comment
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: botComment.id,
                body: body
              });
            } else {
              // Create new comment
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body: body
              });
            }

      - name: Create issue for critical vulnerabilities
        if: steps.audit.outputs.has_critical == 'true'
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const fs = require('fs');
            const report = fs.readFileSync('audit-report.md', 'utf8');

            await github.rest.issues.create({
              owner: context.repo.owner,
              repo: context.repo.repo,
              title: '🚨 Critical Security Vulnerabilities Detected',
              body: `Critical security vulnerabilities have been detected in dependencies.\n\n${report}\n\n**Action Required**: Please review and update affected dependencies immediately.`,
              labels: ['security', 'critical', 'dependencies']
            });

      - name: Fail on critical vulnerabilities
        if: steps.audit.outputs.has_critical == 'true'
        run: |
          set -euo pipefail
          echo "::error::Critical security vulnerabilities detected. Build failed."
          exit 1

      - name: Warn on other issues
        if: |
          steps.audit.outputs.status == 'warning' ||
          steps.deny.outputs.status == 'failed'
        run: |
          set -euo pipefail
          echo "::warning::Security issues detected but not critical. Please review the audit report."

  dependency-review:
    name: Dependency Review
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    permissions:
      contents: read
      pull-requests: write

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

      - name: Dependency Review
        uses: actions/dependency-review-action@v4
        with:
          fail-on-severity: moderate
          deny-licenses: GPL-3.0, AGPL-3.0
          comment-summary-in-pr: always

  clippy-security:
    name: Clippy Security Lints
    runs-on: ubuntu-latest
    permissions:
      contents: read
      checks: write

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

      - name: Setup Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-clippy-${{ hashFiles('**/Cargo.lock') }}

      - name: Run Clippy with security lints
        run: |
          cargo clippy --all-targets --all-features -- \
            -W clippy::all \
            -W clippy::pedantic \
            -W clippy::nursery \
            -W clippy::cargo \
            -D warnings
