Reporting to GitHub code scanning
sqlens:security writes SARIF 2.1.0, which is the format GitHub's code-scanning tab reads. This
page is the recipe: a workflow that runs, uploads, and does not lose its findings to an exit code.
The workflow
name: SQLens security
on:
pull_request:
push:
branches: [main]
permissions:
# Without this the upload step fails with a 403 that reads like an authentication problem
# and is not one. `contents: read` is needed too once you set any permissions block at all,
# because naming one permission drops every default.
contents: read
security-events: write
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
- run: composer install --no-interaction --prefer-dist
# `continue-on-error`, and it is the load-bearing line of this workflow. The command exits
# non-zero when it finds something above your gate — which is the normal, useful case — and a
# step that stopped there would skip the upload and leave the Security tab empty on exactly
# the runs that had something to say.
- name: Run SQLens
continue-on-error: true
run: php artisan sqlens:security --format=sarif --output=sqlens.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: sqlens.sarif
What the exit codes mean
The upload runs regardless, but a workflow that wants to fail on findings needs to tell them apart:
| Code | Meaning |
|---|---|
0 | nothing above the gate |
1 | findings above the gate — the ordinary "it worked and found things" |
2 | misconfiguration: the run could not be set up as asked |
3 | something was undetermined and the run is strict about that |
2 and 3 are the two you should never let pass silently. A misconfigured run and a run that could
not check something both produce a SARIF file, and both are smaller than the run you asked for.
security-severity is what GitHub ranks by, not level
This is the part that surprises people. The code-scanning UI sorts and filters alerts by a numeric
property named security-severity; a rule with the right level and no security-severity arrives
as an alert with no weight at all — sorted below everything that carried a number.
SQLens writes both, from its own security severity:
| SQLens severity | SARIF level | security-severity |
|---|---|---|
| critical | error | 9.0 |
| high | error | 7.0 |
| medium | warning | 5.0 |
| low | warning | 3.0 |
| info | note | 1.0 |
Only security and privacy findings carry a weight. A safety finding is measured by the strictness level rather than by a severity, so giving it a number would place it above real security findings in a security tab — which is the one place that ranking has to be right.
Narrowing what gets uploaded
php artisan sqlens:security --format=sarif --output=sqlens.sarif --min-severity=high
A floor keeps the tab useful on a database with a long tail of low-severity findings. Set it deliberately rather than by habit: an alert you never uploaded is an alert nobody triages, and the finding you filtered out is invisible in a way a closed alert is not.
Related
- Understanding
undetermined— why exit code3exists - Optional tools — what an absent amplifier does to a run