# Copyright (c) Microsoft Corporation. All rights reserved.
#
name: "CodeQL Security Analysis"

on:
  schedule:
    # Run weekly on Wednesdays at 3:17 AM UTC
    - cron: '17 3 * * 3'
  workflow_dispatch:
    # Allow manual triggering
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  analyze:
    name: Analyze (${{ matrix.language }})
    runs-on: ubuntu-latest
    timeout-minutes: 60
    permissions:
      # required for all workflows
      security-events: write
      # required to fetch internal or private CodeQL packs
      packages: read
      # only required for workflows in private repositories
      actions: read
      contents: read

    strategy:
      fail-fast: false
      matrix:
        include:
          # Rust analysis for main crate and Rust-based bindings
          - language: rust
            build-mode: none
            working-directory: .
          # C/C++ analysis for FFI bindings
          - language: c-cpp
            build-mode: manual
            working-directory: bindings/ffi
          # Python analysis for Python bindings
          - language: python
            build-mode: none
            working-directory: bindings/python
          # Java analysis for Java bindings
          - language: java-kotlin
            build-mode: manual
            working-directory: bindings/java
          # Go analysis for Go bindings
          - language: go
            build-mode: manual
            working-directory: bindings/go
          # C# analysis for C# bindings
          - language: csharp
            build-mode: manual
            working-directory: bindings/csharp
          # JavaScript analysis for WASM bindings
          - language: javascript-typescript
            build-mode: none
            working-directory: bindings/wasm

    steps:
    - name: Checkout repository
      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

    # Setup language-specific dependencies BEFORE CodeQL init for proper tracing setup
    - name: Setup Rust
      uses: ./.github/actions/toolchains/rust

    - name: Cache cargo
      uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
      with:
        shared-key: ${{ runner.os }}-regorus

    - name: Fetch workspace dependencies
      run: cargo fetch --locked

    - name: Fetch FFI crate dependencies
      if: matrix.language == 'c-cpp' || matrix.language == 'go' || matrix.language == 'csharp'
      run: cargo fetch --locked --manifest-path bindings/ffi/Cargo.toml

    - name: Fetch Java crate dependencies
      if: matrix.language == 'java-kotlin'
      run: cargo fetch --locked --manifest-path bindings/java/Cargo.toml

    - name: Setup Python
      if: matrix.language == 'python'
      uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
      with:
        python-version: '3.10'

    - name: Setup Java
      if: matrix.language == 'java-kotlin'
      uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
      with:
        distribution: 'corretto'
        java-version: '8'

    - name: Setup Go
      if: matrix.language == 'go'
      uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
      with:
        go-version: '1.21'

    - name: Setup .NET
      if: matrix.language == 'csharp'
      uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
      with:
        global-json-file: ./bindings/csharp/global.json

    - name: Invoke dotnet directly
      if: matrix.language == 'csharp'
      run: dotnet --info

    - name: Setup Node.js
      if: matrix.language == 'javascript-typescript'
      uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
      with:
        node-version: '18'

    - name: Initialize CodeQL
      uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
      with:
        languages: ${{ matrix.language }}
        build-mode: ${{ matrix.build-mode }}

    # Install additional build dependencies
    - name: Install system dependencies
      if: matrix.language == 'rust' || matrix.language == 'c-cpp'
      run: |
        sudo apt-get update
        sudo apt-get install -y build-essential cmake

    - name: Install Python build dependencies
      if: matrix.language == 'python'
      working-directory: ${{ matrix.working-directory }}
      run: |
        python -m pip install --upgrade pip
        pip install maturin[patchelf] pytest

    - name: Setup Ruby
      if: matrix.language == 'rust' && contains(matrix.working-directory, 'ruby')
      uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
      with:
        ruby-version: '3.4.2'
        bundler-cache: true
        working-directory: bindings/ruby

    - name: Install WASM build dependencies
      if: matrix.language == 'javascript-typescript'
      run: |
        cargo install wasm-pack

    # Manual build steps for different languages
    - name: Build C/C++ bindings via xtask
      if: matrix.language == 'c-cpp'
      run: |
        cargo xtask test-c --release --frozen
        cargo xtask test-cpp --release --frozen --skip-ffi
        cargo xtask test-c-no-std --release --frozen --skip-ffi

    - name: Build Java bindings via xtask
      if: matrix.language == 'java-kotlin'
      run: cargo xtask test-java --release --frozen

    - name: Build Go bindings via xtask
      if: matrix.language == 'go'
      run: cargo xtask test-go --release --frozen

    - name: Build C# bindings manually
      if: matrix.language == 'csharp'
      working-directory: ${{ matrix.working-directory }}
      run: |
        # Temporary workaround: CodeQL's tracer replaces dotnet with a missing shim when cargo xtask test-csharp runs,
        # so invoke dotnet directly here until the upstream fix lands.
        # Ideal command once fixed: cargo xtask test-csharp --release
        # Build the FFI library that C# bindings access via P/Invoke
        cd ../ffi
        cargo build --release --locked
        cd ../csharp
        # Restore NuGet packages and build .NET assemblies in release mode
        dotnet restore Regorus/Regorus.csproj
        dotnet build Regorus/Regorus.csproj --no-restore /p:Configuration=Release /p:IgnoreMissingArtifacts=true

    - name: Build WASM bindings via xtask
      if: matrix.language == 'javascript-typescript'
      run: cargo xtask build-wasm --release

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
      with:
        category: "/language:${{matrix.language}}"