Getting Started

GitHub Action

Run Flowpatrol security scans on every pull request with a single workflow file.

Every PR gets a security check. No extra steps for your team — just push code, and Flowpatrol posts findings as a comment. Set severity gates to block merges when something critical shows up.

Quick start

Add your API key as a secret

Go to your repo's Settings > Secrets and variables > Actions. Add a new secret:

  • Name: FLOWPATROL_API_KEY
  • Value: your API key (starts with fp_live_)

Don't have a key yet? Create one in the dashboard.

Add the workflow file

Create .github/workflows/flowpatrol.yml in your repo:

.github/workflows/flowpatrol.yml
name: Security Scan

on:
  pull_request:
    branches: [main]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: flowpatrol/scan-action@v1
        with:
          api-key: ${{ secrets.FLOWPATROL_API_KEY }}
          target: https://myapp.vercel.app
          mode: probe

That's it. Push this file, open a PR, and Flowpatrol will post results as a comment.

Full configuration

Here's every input the action accepts:

.github/workflows/flowpatrol.yml
- uses: flowpatrol/scan-action@v1
  with:
    # Required
    api-key: ${{ secrets.FLOWPATROL_API_KEY }}
    target: https://myapp.vercel.app

    # Scan mode: probe (1 credit), standard (5 credits), deep (8 credits)
    mode: probe  # default: probe

    # Fail the check if findings meet this severity threshold
    fail-on: high  # default: none (never fail)

    # Post findings as a PR comment
    comment: true  # default: true

    # Upload SARIF to GitHub Code Scanning
    sarif: false  # default: false

    # Wait for scan to complete before continuing
    wait: true  # default: true

    # Timeout in minutes (applies when wait is true)
    timeout: 15  # default: 10

Inputs

InputRequiredDefaultDescription
api-keyYesYour Flowpatrol API key
targetYesURL to scan (must be reachable from GitHub Actions runners)
modeNoprobeScan mode: probe, standard, or deep
fail-onNononeFail if findings at this severity or above: critical, high, medium, low, none
commentNotruePost a PR comment with findings
sarifNofalseUpload SARIF to GitHub Code Scanning
waitNotrueWait for the scan to finish
timeoutNo10Max wait time in minutes

Outputs

OutputDescription
scan-idThe unique scan identifier
statusScan status: complete, running, failed
findings-countTotal number of findings
critical-countNumber of critical findings
high-countNumber of high findings
medium-countNumber of medium findings
low-countNumber of low findings
report-urlDirect link to the scan report in the Flowpatrol dashboard
sarif-filePath to the SARIF file (when sarif: true)

Use outputs in subsequent steps:

steps:
  - uses: flowpatrol/scan-action@v1
    id: scan
    with:
      api-key: ${{ secrets.FLOWPATROL_API_KEY }}
      target: https://myapp.vercel.app

  - run: echo "Found ${{ steps.scan.outputs.findings-count }} issues"

PR comments

When comment: true (the default), Flowpatrol posts a summary comment on the PR:

## Flowpatrol Security Scan

**Target:** https://myapp.vercel.app
**Mode:** Probe | **Duration:** 12s

| Severity | Count |
|----------|-------|
| Critical | 0     |
| High     | 2     |
| Medium   | 1     |
| Low      | 1     |

### Findings

- **HIGH** Supabase anon key in JS bundle — `/static/js/main.a3f2c.js`
- **HIGH** RLS disabled on "profiles" table — PostgREST API
- **MEDIUM** Missing Content-Security-Policy header — `/`
- **LOW** X-Powered-By header exposes framework — `/`

[View full report](https://app.flowpatrol.ai/scans/abc123)

The action updates the same comment on subsequent pushes to the PR — no duplicate comments cluttering your timeline.

SARIF integration

SARIF lets findings show up in GitHub's Security tab alongside CodeQL and Dependabot alerts. Enable it with the sarif input and add an upload step:

.github/workflows/flowpatrol.yml
steps:
  - uses: flowpatrol/scan-action@v1
    id: scan
    with:
      api-key: ${{ secrets.FLOWPATROL_API_KEY }}
      target: https://myapp.vercel.app
      mode: standard
      sarif: true

  - uses: github/codeql-action/upload-sarif@v3
    if: always()
    with:
      sarif_file: ${{ steps.scan.outputs.sarif-file }}

SARIF upload requires GitHub Advanced Security or a public repository. The if: always() ensures the SARIF file is uploaded even when fail-on causes the scan step to fail.

Severity gating

Use fail-on to block PRs when findings meet a severity threshold. The action exits with code 1 when any finding matches or exceeds the threshold.

fail-on valueFails when there are...
criticalCritical findings
highHigh or Critical findings
mediumMedium, High, or Critical findings
lowAny findings at all
noneNever fails (default)

Pair this with branch protection rules — require the Flowpatrol check to pass before merging:

fail-on: high  # Block the PR if anything high or critical is found

Scan modes and credits

ModeCreditsTimeBest for
probe1~10sEvery PR — fast, cheap, catches surface issues
standard52-5 minPre-release — tests auth, access control, injection
deep810-30 minNightly or weekly — multi-user IDOR, chained attacks

Probes run on every PR. Save standard and deep scans for merges to main or scheduled runs to manage credit usage.

Examples

Probe on every PR

The most common setup. Fast, cheap, catches obvious issues before review:

.github/workflows/flowpatrol.yml
name: Security Probe

on:
  pull_request:
    branches: [main]

jobs:
  probe:
    runs-on: ubuntu-latest
    steps:
      - uses: flowpatrol/scan-action@v1
        with:
          api-key: ${{ secrets.FLOWPATROL_API_KEY }}
          target: https://myapp.vercel.app
          mode: probe
          fail-on: high

Standard scan on merge to main

Run a deeper scan after code lands on main. Good for catching auth and access control issues:

.github/workflows/flowpatrol-main.yml
name: Security Scan (Main)

on:
  push:
    branches: [main]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: flowpatrol/scan-action@v1
        with:
          api-key: ${{ secrets.FLOWPATROL_API_KEY }}
          target: https://myapp.vercel.app
          mode: standard
          fail-on: critical
          sarif: true

      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: ${{ steps.scan.outputs.sarif-file }}

Nightly deep scan

Schedule a deep scan for exhaustive coverage without burning credits on every push:

.github/workflows/flowpatrol-nightly.yml
name: Nightly Deep Scan

on:
  schedule:
    - cron: '0 3 * * *'  # 3 AM UTC daily

jobs:
  deep-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: flowpatrol/scan-action@v1
        with:
          api-key: ${{ secrets.FLOWPATROL_API_KEY }}
          target: https://myapp.vercel.app
          mode: deep
          timeout: 30

Dynamic target from Vercel preview

Scan the actual preview deployment instead of a hardcoded URL:

.github/workflows/flowpatrol-preview.yml
name: Scan Preview

on:
  deployment_status:

jobs:
  scan:
    if: github.event.deployment_status.state == 'success'
    runs-on: ubuntu-latest
    steps:
      - uses: flowpatrol/scan-action@v1
        with:
          api-key: ${{ secrets.FLOWPATROL_API_KEY }}
          target: ${{ github.event.deployment_status.target_url }}
          mode: probe
          fail-on: high

Monorepo matrix

Scan multiple apps in a single workflow:

.github/workflows/flowpatrol-monorepo.yml
name: Security Scan (Monorepo)

on:
  pull_request:
    branches: [main]

jobs:
  scan:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        app:
          - { name: "web", url: "https://web.myapp.com" }
          - { name: "api", url: "https://api.myapp.com" }
          - { name: "admin", url: "https://admin.myapp.com" }
    steps:
      - uses: flowpatrol/scan-action@v1
        with:
          api-key: ${{ secrets.FLOWPATROL_API_KEY }}
          target: ${{ matrix.app.url }}
          mode: probe
          fail-on: high

Troubleshooting

Target not reachable

GitHub Actions runners need to reach your target URL over the public internet. If your app is behind a firewall or VPN, use the CLI from a machine with access instead.

Scan times out

Increase the timeout value. Standard scans typically finish in under 5 minutes, but larger apps can take longer. Deep scans can take up to 30 minutes.

Comment not appearing

The action needs pull-requests: write permission. If you're using a custom permissions block, add it explicitly:

permissions:
  pull-requests: write
  security-events: write  # Only needed if using sarif: true

SARIF upload fails

SARIF upload requires either a public repo or GitHub Advanced Security. Check that security-events: write is in your permissions block.