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.
Quickstart
Section titled “Quickstart”Add this workflow to your repository to scan on every push and pull request.
name: Firmis Security Scanon: [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.sarifWorkflow examples
Section titled “Workflow examples”The minimal workflow for a security gate. Fails the build on high or critical findings.
name: Firmis Security Scanon: [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 highUpload results to the GitHub Security tab for inline code annotations.
name: Firmis Security Scanon: [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 if: always() uses: github/codeql-action/upload-sarif@v3 with: sarif_file: results.sarif category: firmisFull pipeline: discover platforms, generate CycloneDX BOM, scan, and upload SARIF.
name: Firmis Full Pipelineon: [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: Firmis CI Pipeline run: | npx firmis ci \ --fail-on high \ --format sarif \ --output firmis.sarif - name: Generate Agent BOM run: npx firmis bom --format json --output firmis-bom.json - name: Upload SARIF if: always() uses: github/codeql-action/upload-sarif@v3 with: sarif_file: firmis.sarif - name: Archive BOM uses: actions/upload-artifact@v4 with: name: agent-bom path: firmis-bom.json retention-days: 90Cache the Firmis rule set and npm install for faster CI runs.
name: Firmis Security Scan (Cached)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' cache: 'npm' - name: Cache Firmis binaries uses: actions/cache@v4 with: path: ~/.npm/_npx key: firmis-${{ runner.os }}-${{ hashFiles('package-lock.json') }} restore-keys: | firmis-${{ runner.os }}- - name: Run Firmis CI run: npx firmis ci --fail-on high --format sarif --output results.sarif - name: Upload SARIF if: always() uses: github/codeql-action/upload-sarif@v3 with: sarif_file: results.sarifSARIF upload to GitHub Security tab
Section titled “SARIF upload to GitHub Security tab”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
Required permissions
Section titled “Required permissions”permissions: security-events: write # required to upload SARIF contents: read # required to check out codePR comment with findings summary
Section titled “PR comment with findings summary”Add a step to post a findings summary as a PR comment using the GitHub CLI.
name: Firmis Security Scanon: [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 1Branch protection rules
Section titled “Branch protection rules”To require Firmis to pass before merging, add it as a required status check.
-
Go to Settings → Branches in your GitHub repository.
-
Click Add branch protection rule for
main(or your default branch). -
Enable Require status checks to pass before merging.
-
Search for and select
security(the job name in your workflow). -
Optionally enable Require branches to be up to date before merging for stricter enforcement.
-
Save the rule.
With this in place, pull requests that introduce high or critical findings will be blocked from merging.
Environment variables
Section titled “Environment variables”| Variable | Description | Default |
|---|---|---|
FIRMIS_SEVERITY | Minimum severity to report | low |
FIRMIS_FAIL_ON | Severity level that causes non-zero exit | high |
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.sarifScan only changed files
Section titled “Scan only changed files”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 doneWhat to do next
Section titled “What to do next”- GitLab CI integration → — same security gate for GitLab pipelines
- Pre-commit hooks → — catch threats before they ever reach CI
- SARIF output reference → — full field mapping and example document
firmis cicommand → — the command powering this workflow