Skip to content

GitHub Actions

Every PR that ships without a security scan is a gamble. This one takes five minutes to set up and runs on every push from that point on — no maintenance required.

Add this workflow to your repository to scan on every push and pull request.

.github/workflows/firmis.yml
name: Firmis Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Run Firmis CI
run: npx firmis ci --fail-on high --format sarif --output results.sarif
- name: Upload SARIF to GitHub
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif

The minimal workflow for a security gate. Fails the build on high or critical findings.

.github/workflows/firmis.yml
name: Firmis Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Scan with Firmis
run: npx firmis ci --fail-on high

GitHub, VS Code, and every major SAST dashboard speaks SARIF. When you upload a SARIF file with github/codeql-action/upload-sarif@v3, GitHub displays findings as:

  • Inline annotations on pull request diffs
  • Code scanning alerts in the Security tab under Code scanning
  • Dismissed/resolved tracking across commits
permissions:
security-events: write # required to upload SARIF
contents: read # required to check out code

Add a step to post a findings summary as a PR comment using the GitHub CLI.

.github/workflows/firmis-pr-comment.yml
name: Firmis Security Scan
on: [pull_request]
jobs:
security:
runs-on: ubuntu-latest
permissions:
pull-requests: write
security-events: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Run Firmis CI
id: firmis
run: |
npx firmis ci \
--fail-on high \
--format sarif \
--output results.sarif \
--quiet 2>&1 | tee firmis-output.txt
echo "exit_code=${PIPESTATUS[0]}" >> "$GITHUB_OUTPUT"
continue-on-error: true
- name: Post PR comment
if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
run: |
SUMMARY=$(cat firmis-output.txt | tail -5)
gh pr comment ${{ github.event.pull_request.number }} \
--body "## Firmis Security Scan
\`\`\`
${SUMMARY}
\`\`\`
[View full results →](https://github.com/${{ github.repository }}/security/code-scanning)"
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
- name: Fail if threats found
if: steps.firmis.outputs.exit_code != '0'
run: exit 1

To require Firmis to pass before merging, add it as a required status check.

  1. Go to SettingsBranches in your GitHub repository.

  2. Click Add branch protection rule for main (or your default branch).

  3. Enable Require status checks to pass before merging.

  4. Search for and select security (the job name in your workflow).

  5. Optionally enable Require branches to be up to date before merging for stricter enforcement.

  6. Save the rule.

With this in place, pull requests that introduce high or critical findings will be blocked from merging.

VariableDescriptionDefault
FIRMIS_SEVERITYMinimum severity to reportlow
FIRMIS_FAIL_ONSeverity level that causes non-zero exithigh

You can set these in your workflow or in GitHub repository secrets/variables.

- name: Run Firmis CI
env:
FIRMIS_FAIL_ON: critical # only fail on critical in this workflow
run: npx firmis ci --fail-on ${{ env.FIRMIS_FAIL_ON }} --format sarif --output results.sarif

For large repositories, you can scope the scan to files changed in a PR to reduce scan time.

- name: Get changed files
id: changed
uses: tj-actions/changed-files@v44
with:
dir_names: true
dir_names_exclude_current_dir: false
- name: Run Firmis on changed directories
if: steps.changed.outputs.any_changed == 'true'
run: |
for dir in ${{ steps.changed.outputs.all_changed_files }}; do
npx firmis scan "$dir" --format sarif --output "results-${dir//\//-}.sarif" || true
done