github-actions-maintainer 0.7.10

General-purpose GitHub Actions maintenance toolkit with secure workflow pinning
Documentation
name: Security

on:
  push:
    branches: [main, dev]
  pull_request:
    branches: [main, dev]
  schedule:
    - cron: "0 3 * * 1"
  workflow_dispatch:

permissions:
  contents: read

jobs:
  audit:
    name: Security Audit
    runs-on: ${{ vars.RUST_TEMPLATE_RUNNER_UBUNTU || 'ubuntu-latest' }}
    env:
      CARGO_TERM_COLOR: always
      RUST_VERSION: 1.100.0
      RUSTUP_TOOLCHAIN: 1.100.0
      BINARY_NAME: ${{ vars.RUST_TEMPLATE_BINARY_NAME || 'github-actions-maintainer' }}
      SBOM_MANIFEST_PATH: ${{ vars.RUST_TEMPLATE_SBOM_MANIFEST_PATH || 'Cargo.toml' }}
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Install Rust
        uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1
        with:
          toolchain: ${{ env.RUST_VERSION }}

      - name: Verify selected compiler
        run: |
          rustup show active-toolchain
          rustc --version --verbose
          cargo --version

      - name: Install cargo-audit
        run: cargo install --locked --version 0.23.0 cargo-audit

      - name: Run security audit
        run: cargo audit

      - name: Generate audit report
        run: cargo audit --json > audit-report.json

      - name: Upload audit report
        uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
        with:
          name: audit-report
          path: audit-report.json
          if-no-files-found: error
          retention-days: 30

  deny:
    name: Dependency Check
    runs-on: ${{ vars.RUST_TEMPLATE_RUNNER_UBUNTU || 'ubuntu-latest' }}
    env:
      CARGO_TERM_COLOR: always
      RUST_VERSION: 1.100.0
      RUSTUP_TOOLCHAIN: 1.100.0
      BINARY_NAME: ${{ vars.RUST_TEMPLATE_BINARY_NAME || 'github-actions-maintainer' }}
      SBOM_MANIFEST_PATH: ${{ vars.RUST_TEMPLATE_SBOM_MANIFEST_PATH || 'Cargo.toml' }}
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Install Rust
        uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1
        with:
          toolchain: ${{ env.RUST_VERSION }}

      - name: Verify selected compiler
        run: |
          rustup show active-toolchain
          rustc --version --verbose
          cargo --version

      - name: Install cargo-deny
        uses: taiki-e/install-action@cfdb7ed4ccc7c7dce37759eae89dc5674b469b39 # v2.90.3
        with:
          tool: cargo-deny@0.20.2

      - name: Check licenses
        run: cargo deny check licenses

      - name: Check advisories
        run: cargo deny check advisories

      - name: Check bans
        run: cargo deny check bans

  supply-chain:
    name: Supply Chain
    runs-on: ${{ vars.RUST_TEMPLATE_RUNNER_UBUNTU || 'ubuntu-latest' }}
    env:
      CARGO_TERM_COLOR: always
      RUST_VERSION: 1.100.0
      RUSTUP_TOOLCHAIN: 1.100.0
      BINARY_NAME: ${{ vars.RUST_TEMPLATE_BINARY_NAME || 'github-actions-maintainer' }}
      SBOM_MANIFEST_PATH: ${{ vars.RUST_TEMPLATE_SBOM_MANIFEST_PATH || 'Cargo.toml' }}
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Install Rust
        uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1
        with:
          toolchain: ${{ env.RUST_VERSION }}

      - name: Verify selected compiler
        run: |
          rustup show active-toolchain
          rustc --version --verbose
          cargo --version

      - name: Install cargo-cyclonedx
        run: cargo install --locked --version 0.5.10 cargo-cyclonedx

      - name: Generate SBOM
        run: make sbom BINARY_NAME="${BINARY_NAME}" SBOM_MANIFEST_PATH="${SBOM_MANIFEST_PATH}"

      - name: Upload SBOM
        uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
        with:
          name: sbom
          path: sbom/*.json
          if-no-files-found: error
          retention-days: 30

  secrets:
    name: Secret Scanning
    runs-on: ${{ vars.RUST_TEMPLATE_RUNNER_UBUNTU || 'ubuntu-latest' }}
    permissions:
      contents: read
      security-events: write
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: TruffleHog Scan
        uses: trufflesecurity/trufflehog@ea68ca03c865c5f324e86e849ced20ed3cf9dbbb # v3.99.8
        with:
          version: 3.99.8
          extra_args: --only-verified

      - name: Install Gitleaks
        env:
          GITLEAKS_VERSION: "8.30.1"
        run: |
          set -euo pipefail
          archive="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
          curl -fsSLo "${archive}" "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${archive}"
          curl -fsSLo gitleaks_checksums.txt "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_checksums.txt"
          grep " ${archive}$" gitleaks_checksums.txt | sha256sum --check --
          tar -xzf "${archive}" gitleaks
          sudo install gitleaks /usr/local/bin/gitleaks

      - name: Gitleaks Scan
        run: |
          gitleaks git . \
            --no-banner \
            --redact \
            --exit-code 1 \
            --report-format sarif \
            --report-path gitleaks.sarif

      - name: Upload Gitleaks results
        uses: github/codeql-action/upload-sarif@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3
        with:
          sarif_file: gitleaks.sarif
        if: always() && hashFiles('gitleaks.sarif') != ''

  scorecard:
    name: OSSF Scorecard
    runs-on: ${{ vars.RUST_TEMPLATE_RUNNER_UBUNTU || 'ubuntu-latest' }}
    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
    permissions:
      security-events: write
      id-token: write
      contents: read
      actions: read
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Run Scorecard
        uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0
        with:
          results_file: scorecard.sarif
          results_format: sarif
          publish_results: true