react-perf-analyzer 0.5.1

React performance + security scanner. Finds perf anti-patterns, XSS, secrets, and CVEs. Single binary, zero config, SARIF output.
name: 'react-perf-analyzer'
description: >
  React performance + security scanner. Finds perf anti-patterns, security
  vulnerabilities, and CVEs in JS/TS/JSX/TSX codebases. Uploads results as
  SARIF for inline GitHub PR annotations.

author: 'rashvish18'

branding:
  icon: 'shield'
  color: 'orange'

inputs:
  path:
    description: 'Path to the directory or file to scan (default: repo root)'
    required: false
    default: '.'

  format:
    description: 'Output format: text | json | html | sarif (default: sarif)'
    required: false
    default: 'sarif'

  output:
    description: 'Output file path (default: results.sarif)'
    required: false
    default: 'results.sarif'

  fail-on:
    description: >
      Minimum severity that causes a non-zero exit: none | low | medium |
      high | critical. Default: high (CI fails on high/critical only).
    required: false
    default: 'high'

  category:
    description: 'Rule category: all | perf | security (default: all)'
    required: false
    default: 'all'

  baseline:
    description: >
      Path to a .sast-baseline.json file. Known issues in the baseline are
      suppressed so CI only fails on new regressions.
    required: false
    default: ''

  upload-sarif:
    description: >
      Upload the SARIF file to GitHub Code Scanning (requires repo permission
      security-events:write). Set to "false" to skip upload.
    required: false
    default: 'true'

  version:
    description: >
      react-perf-analyzer version to install (e.g. "0.4.1").
      Defaults to "latest".
    required: false
    default: 'latest'

outputs:
  sarif-path:
    description: 'Absolute path to the generated SARIF file'
    value: ${{ steps.scan.outputs.sarif-path }}

  issue-count:
    description: 'Total number of issues found'
    value: ${{ steps.scan.outputs.issue-count }}

runs:
  using: 'composite'
  steps:
    - name: Install react-perf-analyzer
      shell: bash
      run: |
        if [[ "${{ inputs.version }}" == "latest" ]]; then
          VERSION=$(curl -s https://crates.io/api/v1/crates/react-perf-analyzer \
            | python3 -c "import sys,json; print(json.load(sys.stdin)['crate']['newest_version'])")
        else
          VERSION="${{ inputs.version }}"
        fi
        echo "Installing react-perf-analyzer v${VERSION}"
        cargo install react-perf-analyzer --version "${VERSION}" --locked --quiet

    - name: Run react-perf-analyzer
      id: scan
      shell: bash
      run: |
        BASELINE_FLAG=""
        if [[ -n "${{ inputs.baseline }}" && -f "${{ inputs.baseline }}" ]]; then
          BASELINE_FLAG="--baseline ${{ inputs.baseline }}"
        fi

        set +e
        react-perf-analyzer "${{ inputs.path }}" \
          --format "${{ inputs.format }}" \
          --output "${{ inputs.output }}" \
          --fail-on "${{ inputs.fail-on }}" \
          --category "${{ inputs.category }}" \
          $BASELINE_FLAG 2>&1
        EXIT_CODE=$?
        set -e

        # Expose output variables
        SARIF_ABS="$(pwd)/${{ inputs.output }}"
        echo "sarif-path=${SARIF_ABS}" >> "$GITHUB_OUTPUT"

        # Count results from SARIF (basic jq parse, fallback to 0)
        if command -v jq &>/dev/null && [[ -f "${{ inputs.output }}" ]]; then
          COUNT=$(jq '[.runs[].results | length] | add // 0' "${{ inputs.output }}" 2>/dev/null || echo 0)
        else
          COUNT=0
        fi
        echo "issue-count=${COUNT}" >> "$GITHUB_OUTPUT"

        exit $EXIT_CODE

    - name: Upload SARIF to GitHub Code Scanning
      if: inputs.upload-sarif == 'true' && always()
      uses: github/codeql-action/upload-sarif@v3
      with:
        sarif_file: ${{ inputs.output }}
        category: 'react-perf-analyzer'