Skip to content

chinmay-sawant/deslop

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

343 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Deslop: The lightning-fast bad practice detector for AI-generated code. Deslop finds it in seconds.

deslop is a Rust-based static analyzer for Go, Python, and Rust repositories that focuses on signals commonly associated with low-context AI-generated code. It currently scans a repository, parses Go, Python, and Rust files with tree-sitter, extracts structural fingerprints for each function, builds a lightweight local package index, runs early heuristic checks, and can benchmark the pipeline against real repositories.

Commands

Run a scan against a target path:

cargo run -- scan /path/to/repo

deslop auto-detects supported source files under that path. The same command works for Go-only repositories, Python-only repositories, Rust-only repositories, and mixed-language repositories.

By default, scan output prints the scan summary plus the standard finding set. Pass --details when you want the per-function fingerprint breakdown alongside the normal findings.

Repository-local scan behavior can be tuned with a .deslop.toml file at the scan root:

go_semantic_experimental = true
rust_async_experimental = true
disabled_rules = ["panic_macro_leftover"]
suppressed_paths = ["tests/fixtures"]

[severity_overrides]
expect_in_non_test_code = "error"

go_semantic_experimental = true enables the deeper semantic Go heuristics such as nested-loop allocation/string-build checks and stronger nested N+1 escalation. rust_async_experimental = true keeps the Rust async rule pack enabled for that repository. disabled_rules removes matching rule ids entirely, suppressed_paths filters findings under matching relative path prefixes after analysis, and severity_overrides rewrites the emitted severity after analysis.

You can also ignore rule ids for a single scan invocation without changing repository config:

cargo run -- scan --ignore hallucinated_import_call,hallucinated_local_call /path/to/repo

--ignore applies after analysis and only affects the emitted findings for that command.

Run the same scan with JSON output:

cargo run -- scan --json /path/to/repo

Enable the deeper semantic Go checks for a single run:

cargo run -- scan --enable-semantic /path/to/go-repo

Show full per-function fingerprint details in either text or JSON output:

cargo run -- scan --details /path/to/repo
cargo run -- scan --json --details /path/to/repo

By default, scan also exports review-ready function context files and batched chunk files:

cargo run -- scan /path/to/repo --no-fail

Output locations (created automatically):

  • scripts/findings/functions/1.txt, 2.txt, ...
  • scripts/chunks/Chunk_1_25.txt, Chunk_26_50.txt, ...

Opt out of export:

cargo run -- scan /path/to/repo --no-context --no-chunks

Customize chunk size or output directories:

cargo run -- scan /path/to/repo --no-fail --chunk-size 50
cargo run -- scan /path/to/repo --context-output-dir /tmp/functions --chunks-output-dir /tmp/chunks

Write scan output directly to a file:

cargo run -- scan /path/to/repo > results.txt
cargo run -- scan /home/chinmay/ChinmayPersonalProjects/gopdfsuit > gopdfsuit_results.txt
cargo run -- scan /home/chinmay/ChinmayPersonalProjects/SnapBack > snapback_results.txt
cargo run -- scan --json /path/to/repo > results.txt

Run a scan without .gitignore filtering:

cargo run -- scan --no-ignore /path/to/repo

Benchmark the current pipeline against a real local repository:

cargo run -- bench /path/to/repo

Benchmark with explicit repeats and warmups:

cargo run -- bench --warmups 2 --repeats 5 /path/to/repo

Benchmark with JSON output:

cargo run -- bench --json /path/to/repo

List rules from the central registry:

cargo run -- rules
cargo run -- rules --language go
cargo run -- rules --status experimental --json

Rule Inventory

deslop now publishes a central rule registry that drives the CLI and the synced docs surfaces.

Language Stable Experimental Research Total
common 11 0 0 11
go 751 2 0 753
python 691 0 0 691
rust 338 12 0 350
total 1791 14 0 1805

The totals above are language-scoped rule entries, so a shared rule ID implemented in more than one backend appears in each relevant language bucket. The registry is now the source of truth for deslop rules, the frontend rule catalog, and the generated detection inventory guide.

GitHub Action

Use deslop directly in GitHub Actions without installing Rust. The action downloads the matching release binary for the current runner, adds it to the PATH, and runs either deslop scan or deslop bench.

Scan the checked out repository with the defaults:

name: Deslop

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: chinmay-sawant/deslop@v0.2.0
        with:
          path: .

Emit JSON and include per-function fingerprint details:

- uses: actions/checkout@v4
- uses: chinmay-sawant/deslop@v0.2.0
  with:
    path: .
    json: 'true'
    details: 'true'
    fail-on-findings: 'false'

Run a benchmark job instead of a scan:

- uses: actions/checkout@v4
- uses: chinmay-sawant/deslop@v0.2.0
  with:
    command: bench
    path: .
    repeats: '10'
    warmups: '2'

Inputs:

  • version: Release tag to install, for example v0.1.0. Defaults to the current action ref when it is a full release tag, otherwise latest. Optional.
  • command: Subcommand to run. Supported values are scan and bench. Defaults to scan. Optional.
  • path: Path to the repository to analyze. Defaults to .. Optional.
  • json: Emit JSON output. Defaults to false. Optional.
  • details: Include full per-function fingerprint details in scan output. Applies only to the scan command. Defaults to false. Optional.
  • no-ignore: Scan without respecting .gitignore. Defaults to false. Optional.
  • enable-semantic: Enable the opt-in deeper semantic Go heuristics. Defaults to false. Optional.
  • fail-on-findings: Exit with a non-zero status code when scan findings are present. Applies only to the scan command. Defaults to true. Optional.
  • repeats: Benchmark repeat count. Applies only to the bench command. Defaults to 5. Optional.
  • warmups: Benchmark warmup count. Applies only to the bench command. Defaults to 1. Optional.

Recent Go additions

  • Wrapper propagation now covers receiver-field clients, local wrapper chains, and Query versus QueryContext-style mismatches when a function already accepts context.Context.
  • Functions that intentionally detach from request context can document that boundary and avoid the propagation warning.
  • The semantic Go pack adds likely_n_squared_allocation, likely_n_squared_string_concat, and stronger nested-loop correlation for n_plus_one_query.

Development

Run the test suite:

cargo test

Validate the documentation sync and corpus manifest:

python3 scripts/sync_docs.py --check
python3 scripts/corpus_harness.py validate

List or run the real-repository evaluation corpus:

python3 scripts/corpus_harness.py list
python3 scripts/corpus_harness.py run --target gopdfsuit --scan
python3 scripts/corpus_harness.py run --target gopdfsuit --bench

Expand a saved findings report into review-ready function context:

cargo run -- scan /path/to/repo --no-fail

Each exported block includes Source, Rule, Rule description, Auto triage note, and the full enclosing Function. Pass --details for richer metadata blocks.

Generate the findings visualizer dataset here with:

cargo run -- scan /path/to/repo --no-fail > temp.txt
python3 scripts/extract_function_context_json.py temp.txt \
  --output-dir frontend/public/findings \
  --include-function-text

Function context files and chunks are written automatically during the scan step above. Only the JSON dataset step still uses Python.

If you run the temp workflow above, make sure you start the frontend server from the frontend folder:

cd frontend
npm run dev

Those commands read the path:line entries from temp.txt and rewrite the generated findings data under frontend/public/findings. The scan step also writes per-finding review files under scripts/findings/functions/ and batched chunks under scripts/chunks/. By default each exported block includes:

  • Source
  • Rule description
  • Auto triage note
  • Function

If you want the full metadata-rich output again, pass --details to scan:

cargo run -- scan /path/to/repo --no-fail --details

Run the repo-local scripts through one shared entrypoint:

make run-scripts

run-scripts executes the normal repo-local utility scripts and validates installer scripts in a safe non-installing mode.

Build release executables for your current platform or cross-compile for other supported platforms:

cargo build --release
cargo build --release --target x86_64-pc-windows-gnu
cargo build --release --target x86_64-apple-darwin
cargo build --release --target x86_64-unknown-linux-gnu

If you are cross-compiling, make sure the matching Rust target is installed first. Adjust the target triple to match the architecture you want to ship:

rustup target add x86_64-pc-windows-gnu x86_64-apple-darwin x86_64-unknown-linux-gnu

The native release binary is written to target/release/. Cross-compiled binaries are written under target/<target-triple>/release/ and are named deslop on Unix-like systems and deslop.exe on Windows.


Helper: VS Code finding opener (Experimental)

If you review deslop scan output in Visual Studio Code, the vscode-finding-opener helper provides a small extension and scripts to open findings directly in the editor for quick triage. See vscode-finding-opener for installation, usage, and troubleshooting notes.

For a detailed architecture and roadmap guide, see guides/implementation-guide.md. For the corpus workflow and promotion contract, see guides/evaluation-and-promotion-policy.md. For a detector-oriented overview, see guides/features-and-detections.md.

Library code uses typed errors internally and keeps anyhow at the CLI edge. The scanner also uses bounded file reads by default so repository scans do not rely on unbounded read_to_string calls.

Rust scan hardening now also canonicalizes the scan root, rejects symlinked file reads, and compares the generated Rust security baseline report against the committed baseline in CI.