Skip to main content

DiffGuard

CI Python License

Security checks and risk triage for pull requests. DiffGuard reads only what a change adds and removes, so it needs no baseline for existing code and flags only what the pull request introduced. A typical PR scans in well under a second (a 30,000-line diff takes about 2.5 s).

  • Dangerous additions: leaked keys, SQL built from strings, eval on input, shell injection, TLS verification turned off, unsafe deserialization, XSS sinks, CSRF or auth switched off, and more. See the 26 rules.
  • Deleted safety controls, which most scanners don't look for: a removed @login_required, a deleted permission check, CSRF middleware or password hashing taken out.
  • Sensitive areas: changes to auth, payments, migrations, infrastructure or dependencies get routed to the right reviewers.

Every point of the 0–100 score has a reason you can read.

$ diffguard scan --base main
DiffGuard: HIGH risk (score 100/100) - 1 file, +2/-2 lines

Score breakdown:
  +70  DG201                  SQL built from string formatting (critical, 1 occurrence)
  +45  DG601                  Authentication or authorization check removed (high, 1 occurrence)
  +25  DOMAIN_AUTH            Touches auth (1 file)

Findings (2):
  CRITICAL DG201  app/views.py:6  SQL built from string formatting
           + rows = cursor.execute(f"SELECT * FROM orders WHERE status = '{status}'")
  HIGH     DG601  app/views.py:3  Authentication or authorization check removed
           - @login_required

Sensitive areas: auth

Quick start

GitHub Actions

# .github/workflows/diffguard.yml
name: DiffGuard
on: pull_request

permissions:
  contents: read
  pull-requests: write   # for the PR comment

jobs:
  diffguard:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: mostaphaelansari/Feature-to-Production-Autonomous-Flow@v0.2.0
        with:
          fail-on: high          # low | medium | high | never

You get inline annotations on the diff, a PR comment that updates on each push, a job summary, and a failing check on high risk. To block merging, make the check required in branch protection.

Input Default
fail-on high Fail at this level or above (low, medium, high, never).
base PR base commit Ref to compare against.
config auto Config file path.
comment true Post/update a PR comment.
annotations true Inline annotations on the diff.
sarif-file Also write SARIF, for github/codeql-action/upload-sarif.

Outputs: risk-level, risk-score, report-json.

Command line

pip install diffguard-scan          # Python 3.10+; no dependencies on 3.11+

diffguard scan                      # uncommitted changes vs HEAD
diffguard scan --staged             # what you're about to commit
diffguard scan --base origin/main   # everything on this branch
git diff main | diffguard scan --diff -

Until the first PyPI release: pip install "git+https://github.com/mostaphaelansari/Feature-to-Production-Autonomous-Flow".

pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/mostaphaelansari/Feature-to-Production-Autonomous-Flow
    rev: v0.2.0
    hooks:
      - id: diffguard

GitLab CI

See docs/gitlab.md.

How the score works

Source Points
Each rule that fires (counted once per rule) critical 70 · high 45 · medium 20 · low 5
Sensitive area touched auth, payment, database 25 · security 20 · infrastructure 15 · dependencies, concurrency 10 · configuration 5
Change size (code lines) ≥300: 10 · ≥800: 25

The score is capped at 100. Low is under 25, medium is 25 or more or any medium/high finding, and high (the level that blocks by default) is any critical finding, or a score of 60+ that includes at least one medium-or-worse finding. Sensitive areas and size on their own top out at medium: they route review but never block. Documentation and test files never count toward sensitive areas, and test files skip most rules, so editing a README or a test fixture stays low.

Sensitive areas come from file paths (src/billing/, migrations/, Dockerfile, requirements.txt…) and specific identifiers in changed code (login, bcrypt, stripe, CREATE TABLE, threading.Lock…). Identifiers are matched as whole words after splitting snake_case and camelCase, so author doesn't count as auth and rapid doesn't count as api.

Configuration

Put this in pyproject.toml under [tool.diffguard], or in a .diffguard.toml without the prefix. Unknown keys and rule IDs are errors, not silently ignored.

[tool.diffguard]
fail-on = "high"
thresholds = { medium = 25, high = 60 }
extend-exclude = ["generated/**", "**/*.pb.go"]
test-paths = ["qa/**"]              # treated like tests
disable = ["DG303"]                 # turn rules off
severity = { DG305 = "high" }       # re-rank rules

[tool.diffguard.per-path-ignores]
"scripts/**" = ["DG203"]
"examples/**" = ["*"]

[tool.diffguard.domains.pricing]    # your own sensitive area
paths = ["src/pricing/**"]
weight = 30

[tool.diffguard.domains.configuration]
weight = 0                          # don't score config changes

[tool.diffguard.reviewers]          # shown as "suggested reviewers"
auth = ["@acme/identity"]
payment = ["@acme/payments"]
findings = ["@acme/appsec"]         # any medium+ finding

Suppress one line with a comment on that line: # diffguard: ignore[DG203], or # diffguard: ignore for all rules.

Output formats

--format text|json|markdown|sarif|github sets what goes to stdout, and -o FORMAT=PATH (repeatable) writes extra files. The JSON format has a schema. diffguard gate report.json --fail-on high applies a threshold to a saved report later.

Exit codes: 0 below the threshold, 1 at or above it, 2 for errors (bad config, missing git history, etc.).

Tamper resistance

A gate that runs from the pull request's own workflow file can be edited by the pull request. For CI that has to hold against its own authors:

  • GitHub: run DiffGuard through an organization ruleset with required workflows, so the workflow comes from a repository the author can't change, and pin the action to a commit SHA.
  • GitLab: use a pipeline execution policy or a compliance pipeline (see docs/gitlab.md).

Changes to CI files themselves (.github/workflows/, .gitlab-ci.yml) count as the infrastructure area, so they're always visible in the report.

Limitations

  • This is pattern matching, not program analysis. It doesn't follow data across functions or files, so a query built in one function and run in another is missed. Python files get syntax-tree checks for SQL, eval and shell calls; other languages use line-level patterns.
  • The removed-control rules are heuristics. Moving a check into middleware in another file is flagged unless the same line is re-added somewhere in the diff, and a reviewer has to confirm.
  • The accuracy numbers come only from this project's own test corpus (tests/test_corpus.py): 35 realistic changes, all classified as expected. That corpus was written alongside the rules, so treat it as a regression suite, not a benchmark. Please open an issue with any false positive or miss.
  • It complements a full SAST tool (CodeQL, Semgrep) and a secret scanner on the whole repository. It doesn't replace them.

Development

pip install -e ".[dev]"
pytest
ruff check .
diffguard rules --format markdown > docs/rules.md   # after changing rules

Each rule in src/diffguard/rules.py includes examples it must flag and examples it must not. The test suite enforces both, and the rules page is generated from them. To report a misclassification, add a case to tests/test_corpus.py.

History

The project started as a hackathon prototype for autonomous merge-request review (presentation, slides). Version 0.2 replaced the keyword-scoring prototype with the rule engine described here; see the changelog.

License

MIT

Metadata

Release files for diffguard-scan 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for diffguard-scan 0.2.0
File Size Uploaded Provenance
diffguard_scan-0.2.0.tar.gz 48.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for diffguard-scan 0.2.0
File Interpreter ABI Platform
diffguard_scan-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 89.0 kB

Release files / diffguard_scan-0.2.0.tar.gz

Download URL diffguard_scan-0.2.0.tar.gz
Size 48.9 kB
Tags Source
SHA-256 checksum
How to use checksums
c70d0f4844faf82a089758cda6e5734092b20868348b051ce14859ecb4ee8c8b
BLAKE2b-256 checksum
How to use checksums
6153fd039b2634f47e8b9ad182e9d822f6cbfee5f2ae72a2b9bf445931fb4894
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Release files / diffguard_scan-0.2.0-py3-none-any.whl

Download URL diffguard_scan-0.2.0-py3-none-any.whl
Size 40.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c5f4b070c5ecb7f438d3c0a1b678b801e7e2c99fe9bb977e2be8e8f626f6aab8
BLAKE2b-256 checksum
How to use checksums
b274efba5186594c26f06d555cee25d40081cb49ec639fb87686004232aabc38
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Security for diffguard-scan 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for diffguard_scan-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page