Skip to content

ci: split rust mutation testing across a seventh shard #83

ci: split rust mutation testing across a seventh shard

ci: split rust mutation testing across a seventh shard #83

Workflow file for this run

name: codeql
# Static analysis of the three languages this repository actually holds: the workflow files
# themselves, the frontend, and the Rust backend.
#
# This replaces GitHub's *default setup*, which had been running the same three languages since
# 2026-07 and doing so correctly. The move is not about coverage. It is about where the
# configuration lives. Every other gate in this repository pins what it runs: the Rust toolchain
# (rust-toolchain.toml), Node (.nvmrc plus a consistency check), every action by SHA, every
# `cargo install` by exact version, and every runner image by OS major. Default setup was the one
# gate whose behavior lived in the repository *settings* rather than in a file, so a change to it
# (a language dropped, the query suite narrowed, the schedule loosened) left no trace anybody
# could review, and nothing in a diff would show that the analysis had changed.
#
# The settings this file reproduces are the ones default setup was configured with, read back from
# the API before the switch (languages actions/javascript-typescript/rust, the `default` query
# suite, the `remote` threat model, a weekly schedule). The push/pull_request triggers are the
# additions. Default setup ran on push and weekly, and running on PRs as well means a finding
# arrives on the change that introduced it rather than after it has landed.
#
# IMPORTANT, and the reason this file may sit unused for a moment: default setup and advanced setup
# cannot both be active. While default setup is enabled, this workflow's `upload-sarif` step is
# refused by the API ("Code scanning default setup is enabled"). Disable it first: Settings > Code
# security > Code scanning > Set up > Disable CodeQL, or
# `gh api -X PATCH repos/eduardoghi/kavynex/code-scanning/default-setup -f state=not-configured`.
# Only then push this file. Dispatch it by hand once afterwards to confirm all three languages
# analyze before relying on the schedule.
on:
push:
branches: [main]
pull_request:
schedule:
# Fridays 08:00 UTC. Offset from mutation.yml (Mondays 06:00) and scheduled-audit.yml
# (Thursdays 07:00) so the three scheduled workflows never contend for runners, matching
# the offset those two already keep from each other.
- cron: "0 8 * * 5"
workflow_dispatch:
# Read-only by default, like every other workflow here, so a job added later cannot silently
# inherit write access from the repository default. The analyze job escalates to what CodeQL needs.
permissions:
contents: read
concurrency:
group: codeql-${{ github.ref }}
cancel-in-progress: true
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Pinned rather than `ubuntu-latest`, for the reason the whole repository pins: `-latest`
# moves to a new OS major whenever GitHub decides, and an analysis whose results shift for
# that reason is worse than one that shifts because the code did.
runs-on: ubuntu-26.04
# Well above the observed runtime of the default-setup runs this replaces (~2 minutes for
# the whole matrix) while still bounded, so a wedged extractor fails rather than running
# toward the 6h default.
timeout-minutes: 60
permissions:
# Uploading the SARIF results is what needs a write scope. Nothing else here does.
security-events: write
# Required for the action to read the workflow run's own metadata on a private repo,
# and harmless on a public one. Kept explicit rather than inherited.
actions: read
contents: read
strategy:
fail-fast: false
matrix:
# One leg per language, exactly the three the default setup was analyzing (the API
# additionally listed `javascript` and `typescript`, which are aliases of
# `javascript-typescript` and produce no separate analysis, confirmed against the
# analyses endpoint, which reported three categories, not five).
#
# `build-mode: none` for all three: none of them is a compiled language as far as
# CodeQL is concerned. That is the mode the Rust extractor supports, and it is why
# this workflow needs no toolchain, no apt packages and no build step: it reads
# the sources rather than observing a compilation. If a future CodeQL release
# requires a build for Rust, that leg fails loudly here rather than silently
# analyzing nothing.
include:
- language: actions
build-mode: none
- language: javascript-typescript
build-mode: none
- language: rust
build-mode: none
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Initialize CodeQL
uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# The `security-extended` suite rather than the `default` one the migration from
# default setup kept. That migration left `queries:` absent on purpose, so a red
# run after it could only mean the move broke something and never that a wider
# suite found something the old setup was not asked about; with the move settled,
# widening is the separate, reviewable change it was meant to be.
#
# Why wider: the app's whole threat model is caller-supplied paths reaching the
# filesystem, caller-supplied URLs reaching the network, and argument vectors
# reaching external processes (docs/THREAT-MODEL.md). Those are exactly the
# classes the extended suite carries more variants of, at a lower precision than
# `default`, so it will name things the code already guards in ways the analyzer
# cannot follow (a `is_network_path` check before a stat, say). Each of those is
# read and dismissed in Security > Code scanning with a reason, which is cheaper
# than the one real variant the narrower suite would have stayed silent about.
# `security-and-quality` is deliberately not chosen: its extra queries are code
# quality, which clippy and ESLint already cover at the gate, not security.
queries: security-extended
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0
with:
category: /language:${{ matrix.language }}