Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FixRelay

FixRelay is a GitHub Action and Node CLI that turns SARIF security scanner output plus PR diff context into:

  • merge-risk-report.md: a human-readable merge-risk report with one embedded AI agent fix prompt.
  • normalized-findings.json: normalized SARIF findings annotated with diff context.

In GitHub Actions, FixRelay can also post or update a single PR comment using the marker <!-- fixrelay-comment:start -->.

FixRelay is not a scanner and does not call an LLM. It is deterministic glue around scanner output, git diff context, and a small risk-scoring model.

Runtime requirements:

  • Node.js 20 or newer.
  • No npm runtime dependencies.
  • Semgrep installed only if you want FixRelay to run its built-in Semgrep audit.

Local Quick Start

From this repository:

npm link

Then, inside any git repository:

fixrelay

By default, the local CLI:

  1. Detects origin/main, then origin/master.
  2. Reviews <base>...HEAD.
  3. Runs built-in Semgrep when no --sarif is provided and Semgrep is installed.
  4. Prints a concise terminal summary.
  5. Writes fixrelay-out/merge-risk-report.md and fixrelay-out/normalized-findings.json.

Example output:

FixRelay: medium risk
Decision: warn
Findings: 2 PR-relevant / 7 total
Report: fixrelay-out/merge-risk-report.md
Findings JSON: fixrelay-out/normalized-findings.json

Use an explicit base when your branch does not track origin/main or origin/master:

fixrelay --base origin/develop

Use --fail-on high when you want the local command to exit non-zero for high-risk changes:

fixrelay --fail-on high

Quick Start

Drop this into .github/workflows/fixrelay.yml:

name: FixRelay

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write
  issues: write

jobs:
  fixrelay:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Semgrep
        run: python -m pip install semgrep

      - name: Run FixRelay
        uses: willwang0202/FixRelay@v1
        env:
          GITHUB_TOKEN: ${{ github.token }}
        with:
          diff: origin/${{ github.base_ref }}...HEAD
          fail-on: high
          protected-paths: |
            auth/
            billing/
            infra/
            .github/workflows/

This uses FixRelay's built-in Semgrep path. When no sarif input is provided and run-semgrep is true, FixRelay runs:

semgrep scan --config auto --sarif --output <out-dir>/semgrep.sarif --no-git-ignore

For a stable major version, use willwang0202/FixRelay@v1. For a fully pinned release, use a patch tag such as willwang0202/FixRelay@v1.0.2 or a commit SHA.

If the check passes but no PR comment appears, verify that the workflow has issues: write, pull-requests: write, GITHUB_TOKEN, and repository Actions read/write workflow permissions.

Bring Your Own SARIF

If you already run Semgrep, CodeQL, Trivy, Snyk, or another SARIF-producing scanner, pass the SARIF file explicitly. When sarif is set, FixRelay does not run built-in Semgrep.

      - name: Run Semgrep
        run: semgrep scan --config auto --sarif --output semgrep.sarif || true

      - name: Run FixRelay
        uses: willwang0202/FixRelay@v1
        env:
          GITHUB_TOKEN: ${{ github.token }}
        with:
          sarif: semgrep.sarif
          diff: origin/${{ github.base_ref }}...HEAD
          fail-on: high

Multiple SARIF files can be passed as newline- or comma-separated values.

Large Or Noisy Diffs

If generated files or data files make the PR diff too noisy, build a filtered diff file yourself and pass it with diff-file.

      - name: Build FixRelay diff
        run: |
          git diff --unified=0 origin/${{ github.base_ref }}...HEAD -- \
            . \
            ':!data/**' \
            ':!web/public/songs.json' \
            > fixrelay.diff

      - name: Run FixRelay
        uses: willwang0202/FixRelay@v1
        env:
          GITHUB_TOKEN: ${{ github.token }}
        with:
          sarif: semgrep.sarif
          diff-file: fixrelay.diff
          fail-on: high

diff-file takes precedence over diff.

When FixRelay runs git diff itself, it allows up to 50 MB of diff output. If the unified diff still exceeds the Node process buffer, FixRelay falls back to:

git diff --name-only <range>

That keeps changed-file filtering working, but changed-line scoring is not available for that run.

Action Inputs

These are defined in action.yml.

Input Default Behavior
run-semgrep true Runs built-in Semgrep only when sarif is empty.
semgrep-config auto Value passed to Semgrep --config.
sarif empty Newline- or comma-separated SARIF files to load.
diff empty Git diff range such as origin/main...HEAD. On PR events, the action infers origin/<base>...HEAD if neither diff nor diff-file is set.
diff-file empty Path to a saved unified diff file. Takes precedence over diff.
out-dir fixrelay-out Directory for generated artifacts.
fail-on high Fails the action when risk reaches this threshold. Allowed: low, medium, high, critical, unknown, never.
post-comment true Posts or updates the FixRelay PR comment when PR context exists.
scope pr pr scores only findings in changed files. entire-repo scores all loaded findings.
protected-paths auth/, billing/, infra/, .github/workflows/ Newline- or comma-separated protected path prefixes.

Action Outputs

These are written to GITHUB_OUTPUT.

Output Meaning
risk Risk level: low, medium, high, critical, or unknown.
decision Merge decision: allow, warn, or block.
report Absolute path to merge-risk-report.md.
findings Absolute path to normalized-findings.json.

CLI

From this repository:

node bin/fixrelay.js review \
  --sarif examples/semgrep.sarif \
  --diff-file examples/pr.diff \
  --out-dir fixrelay-out \
  --fail-on never

fixrelay review is the local developer command, and bare fixrelay is an alias for it.

Usage:

fixrelay [options]
fixrelay review [options]
fixrelay generate --sarif <file> [--diff <range>|--diff-file <file>] [options]

Review options:

  • --base <ref>: base ref for local review. Defaults to origin/main, then origin/master.
  • --sarif <file>: SARIF scanner output. Repeatable.
  • --diff <range>: git diff range, such as origin/main...HEAD.
  • --diff-file <file>: saved unified diff file.
  • --out-dir <dir>: artifact directory. Defaults to fixrelay-out.
  • --fail-on <level>: low, medium, high, critical, unknown, or never. CLI default is never.
  • --scope <scope>: pr or entire-repo. Defaults to pr.
  • --pr-title <text> and --pr-body <text>: report context.
  • --protected-path <path>: protected path prefix. Repeatable.
  • --no-semgrep: skip built-in Semgrep when no --sarif is provided.
  • --semgrep-config <cfg>: Semgrep --config value. Defaults to auto.

fixrelay generate is the lower-level command for scripts and CI jobs. It prints the full JSON summary instead of the concise terminal summary.

Generate options:

  • --sarif <file>: SARIF scanner output. Repeatable.
  • --diff <range>: git diff range, such as origin/main...HEAD.
  • --diff-file <file>: saved unified diff file.
  • --out-dir <dir>: artifact directory. Defaults to fixrelay-out.
  • --fail-on <level>: low, medium, high, critical, unknown, or never. CLI default is never.
  • --scope <scope>: pr or entire-repo. Defaults to pr.
  • --pr-title <text> and --pr-body <text>: report context.
  • --protected-path <path>: protected path prefix. Repeatable.
  • --no-semgrep: skip built-in Semgrep when no --sarif is provided.
  • --semgrep-config <cfg>: Semgrep --config value. Defaults to auto.
  • --post-comment: post the report with gh pr comment.

--post-comment requires GITHUB_TOKEN or GH_TOKEN, and the gh CLI must be available.

Diff And Scope Behavior

FixRelay parses unified diff output and tracks:

  • changed files
  • changed lines
  • test file changes
  • CI workflow changes
  • dependency manifest changes

scope: pr keeps only scanner findings whose file appears in the diff. scope: entire-repo keeps every loaded scanner finding.

If no explicit diff or diff-file is provided outside GitHub PR context, FixRelay tries git diff --unified=0 HEAD. If that produces no changed files and scope is pr, FixRelay falls back to treating scanner finding files as changed files. This keeps local no-diff runs useful, but PR workflows should prefer an explicit diff or diff-file.

Risk Scoring

Risk scoring is deterministic.

Per finding:

  • Low severity: +10
  • Medium severity: +22
  • High severity: +35
  • Critical severity: +55
  • Finding is in a changed file: +15
  • Finding is on a changed line: +15
  • Finding is in a protected path: +15

Per PR:

  • Findings exist and no test changes were detected: +10
  • CI/CD workflow files changed: +12
  • Dependency manifest or lockfile changed: +8

Risk levels:

  • critical: score is at least 100, or any finding is critical.
  • high: score is at least 70, or any finding is high.
  • medium: score is at least 35.
  • low: anything lower.
  • unknown: no scanner output was loaded because built-in Semgrep was missing or failed and no SARIF was provided.

Decisions:

  • low: allow
  • medium: warn
  • high: block
  • critical: block
  • unknown: warn

fail-on uses threshold comparison for low, medium, high, and critical. unknown is special: it fails only when fail-on: unknown.

Report Contents

merge-risk-report.md includes:

  • stable FixRelay comment markers
  • merge risk heading
  • decision text
  • score or N/A for unknown risk
  • reasons
  • up to three top findings
  • recommended action
  • one AI agent fix prompt for the first generated task

normalized-findings.json includes normalized SARIF fields plus:

  • is_in_diff
  • is_on_changed_line
  • is_blocking

Limitations

  • FixRelay only loads SARIF. There is no generic JSON scanner input.
  • Built-in Semgrep requires the semgrep command to be installed.
  • SARIF parsing uses the first physical location for each result.
  • scope: pr filters by changed file, not by git blame. A finding in a changed file may have existed before the PR.
  • Large diff fallback keeps file-level context but loses changed-line context.
  • The generated report embeds one agent prompt, based on the first task.
  • FixRelay does not call an LLM and does not verify that a proposed fix is correct.

Privacy

FixRelay reads local SARIF files and local git diff context. It writes local artifacts. In GitHub Actions it talks to GitHub only when post-comment is true and PR context exists.

It does not upload source code to a hosted model, train on code, or store code.

License

FixRelay is licensed under the Business Source License 1.1 (BUSL-1.1). Internal use in your own repositories, CI/CD systems, and security workflows is permitted. Providing FixRelay as a hosted or managed service to third parties requires a commercial license.

Change Date: 2030-05-14. Versions convert to Apache 2.0 on that date or the fourth anniversary of their first public distribution, whichever is earlier.

Development

npm test
node bin/fixrelay.js generate \
  --sarif examples/semgrep.sarif \
  --diff-file examples/pr.diff \
  --out-dir tmp/fixrelay-demo \
  --fail-on never

About

Turn security scanner findings into merge-risk summaries and AI-agent-ready fix prompts.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages