Skip to main content

🛡️ Multi-Engine Scanner

PyPI Python License: MIT

A unified project security scanner that runs Anchore Grype, Aqua Trivy, Astral Ruff and SQLFluff concurrently, deduplicates their findings, and renders them as branded, reviewable reports.

Distributed on PyPI as multi-engine-scanner; the import package is project_scanner and the console commands are multiscan and multi-engine-scanner.

pip install multi-engine-scanner
multiscan /path/to/your/project

Features

  • Multi-Engine Scanning: Runs every available engine concurrently for maximum detection coverage.
  • Smart Deduplication: Normalizes CVEs and package identifiers, cross-verifying findings to highlight dual-verified vulnerabilities versus tool-unique findings.
  • Multi-Format Reporting:
    • 📊 Interactive HTML Reports built for triage: every row states the severity, the finding in plain language, the affected component and the remediation step. Live search, severity and engine filters, sortable and paginated register, expandable detail, CSV export, print/PDF layout.
    • 🗂️ Master Dashboard (index.html) with a hierarchical left rail: executive overview → consolidated register → per-engine reports → transcript and raw exports.
    • 📝 GitHub-Flavored Markdown Report (ideal for pull requests and documentation).
    • 📄 Structured JSON Dataset (ideal for CI/CD integration).
    • 💻 Colorized Terminal Output (ideal for immediate CLI feedback).
  • Run Anywhere: Can be executed from any terminal directory against any project path.

Report hierarchy

Every HTML report is laid out as a four-level review hierarchy:

Level Section Contents
1 Executive summary Posture band, Severity Weight Index, KPI tiles
2 Scan coverage Per-engine status cards and severity distribution
3 Hierarchy explorer Collapsible tree, regroupable by severity, component or engine
4 Findings register Sortable, searchable table with per-finding detail panels

The Severity Weight Index is 100 × Σ(weight × count) ÷ (10 × total), with weights Critical 10, High 6, Medium 3, Low/Unknown 1 — i.e. 100 means every finding is critical.

Presentation lives in project_scanner/reporters/theme.py (palette, stylesheet, shared document furniture); change the brand tokens there to restyle every report at once.

Design tokens

Token Value Used for
Ink #0D0C22 Headings and primary reading text
Secondary #655C7A Supporting copy and descriptions
Accent #060318 Links and primary actions
Metadata #808080 Labels, timestamps, counts
Background #FFFFFF Everything sits on white; structure comes from space and hairlines
Type Mona Sans 32px headings, 14px body
Spacing 4px base unit Rhythm across the whole document
Radius 3px Surfaces and controls alike

Severity keeps its own semantic palette (red / amber / ochre / indigo) and is always coded twice — a colour bar on the row plus a text badge — so it never depends on colour alone. Layout is responsive: two columns on desktop, one below 1080px, and under 700px the findings table becomes one card per finding rather than a horizontally scrolling grid.

Severity colours stay semantic (red / orange / amber / blue) so criticality is never carried by the brand hue alone. The logo is an original scan-shield mark — the SVG sources are in assets/, and the reports embed it inline so they never fetch a remote image.

Branding the reports

Reports ship with neutral naming. Point the masthead at your own organisation with environment variables — no code changes needed:

Variable Default Appears as
SCANNER_BRAND_NAME Multi-Engine Scanner Masthead heading
SCANNER_BRAND_UNIT Security & Code Quality Assurance Line under the heading
SCANNER_BRAND_TAGLINE Automated Multi-Engine Vulnerability Reporting Small caps strapline
SCANNER_REPORT_CLASSIFICATION Internal · Confidential Classification banner
SCANNER_DOC_PREFIX SEC-VA Document reference, e.g. SEC-VA-20260801-CON
export SCANNER_BRAND_NAME="Your Organisation"
export SCANNER_BRAND_UNIT="Information Security Office"
multiscan /path/to/project

Installation

Requires Python 3.9 or newer on macOS, Linux or Windows.

Step 1 — install the scanner

The scanner itself is pure Python standard library, so this command is the same everywhere:

pip install multi-engine-scanner

Installing into a virtual environment is recommended. The only difference between platforms is how you activate it:

macOS / Linux
python3 -m venv .venv
source .venv/bin/activate
pip install multi-engine-scanner
Windows (PowerShell)
py -m venv .venv
.venv\Scripts\Activate.ps1
pip install multi-engine-scanner

If activation is blocked by execution policy, run Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass first, or use .venv\Scripts\activate.bat from cmd.exe.

Step 2 — install the scanning engines

Each engine is a separate tool the scanner shells out to.Install the ones you care about — any engine that is missing is reported as MISSING_BINARY in the report rather than failing the run.

Engine Scope Type
Anchore Grype Dependency & SBOM CVE matching Go binary
Aqua Trivy Filesystem, lockfile & misconfiguration Go binary
Astral Ruff Python static analysis Python package
SQLFluff SQL linting & query hygiene Python package

Ruff and SQLFluff come from PyPI on every platform:

pip install "multi-engine-scanner[engines]"

Grype and Trivy are native binaries, so they differ per platform:

macOS

brew install grype trivy

Linux

# Grype - official install script
curl -sSfL https://get.anchore.io/grype | sudo sh -s -- -b /usr/local/bin

# Trivy - official install script
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin

Distribution packages work too. Debian / Ubuntu:

sudo apt-get install wget gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update && sudo apt-get install trivy

Homebrew on Linux also works: brew install grype trivy.

Windows

With Chocolatey in an elevated PowerShell:

choco install grype trivy

Without a package manager, download the release archives, unzip them, and add the folder to your PATH:

# add an unzipped folder to PATH for the current session
$env:PATH += ";C:\tools\grype;C:\tools\trivy"

WSL2 is a good alternative on Windows — install inside the Linux distribution using the Linux commands above and scan your project through the /mnt/c/... path.

Note: releases are built and tested on Linux CI. macOS is used daily for development; Windows is supported on a best-effort basis. Use a modern terminal (Windows Terminal or PowerShell 7) so the colourised CLI output renders correctly.

Step 3 — verify

multiscan --help
grype version
trivy --version
ruff --version
sqlfluff --version

Every engine reports its own status in the generated report, so you can also just run a scan and read the engine coverage cards.

From source

git clone https://gitlab.com/chandrabrt/multi-engine-scanner.git
cd multi-engine-scanner
pip install -e ".[dev,engines]"

You can also invoke it as a module without installing the console scripts:

python -m project_scanner /path/to/project

CLI Usage Examples

Scan Current Directory

multiscan

Scan Specific Project Directory

multiscan /path/to/your/project

Specify Output Directory & Formats

multiscan /path/to/target --out-dir ./security-reports --format html,markdown

Filter Minimum Severity

multiscan /path/to/target --min-severity HIGH

Run Single Scanner Only

multiscan /path/to/target --grype-only
# or --trivy-only / --ruff-only / --sqlfluff-only

Auto-fix Python findings

--fix hands the target to Ruff's autofixer before reporting, so the run both repairs what it safely can and tells you what is left.

multiscan --fix
multiscan /path/to/target --fix

This rewrites source files in place. Commit or stash your work first — the scanner prints a warning but will not stop you. Output looks like:

🛠️  Ruff auto-fixed 4 finding(s); 4 remain for manual review.

By default only fixes Ruff considers safe are applied. Add --unsafe-fixes to apply the rest:

multiscan /path/to/target --fix --unsafe-fixes

Unsafe fixes can change behaviour. Removing an unused assignment, for example, deletes the value it held — PASSWORD = "hunter2" disappears along with the F841 warning. Review the diff.

--fix applies to Ruff only; Grype, Trivy and SQLFluff findings are always reported, never modified. Combining it with --grype-only, --trivy-only or --sqlfluff-only is a no-op and warns.

Choose which Ruff rules apply

Rule selection follows Ruff's rule selection rules. --ruff-select replaces the default set (E,F,S,W,C,I,B,ASYNC) and --ruff-ignore removes rules from it. Both also govern what --fix will touch.

# security rules only (Bandit-derived S rules)
multiscan /path/to/target --ruff-only --ruff-select S
# everything except line-length and import-sorting
multiscan /path/to/target --ruff-ignore E501,I001
# fix import ordering and unused imports, nothing else
multiscan /path/to/target --ruff-select I,F401 --fix

Report the installed version

multiscan --version

Output

Reports are written to <target>/vulnerability_reports/<target>\vulnerability_reports\ on Windows — and the location can be overridden with --out-dir:

File Contents
index.html Master dashboard — open this first
combined_report.html Consolidated, deduplicated register
<engine>_report.html One report per engine
combined_report.md Markdown transcript for merge requests
combined_report.json Structured dataset for CI/CD

Releasing

Releases are cut by tagging; .gitlab-ci.yml lints, builds, smoke-tests the wheel, verifies the tag matches project_scanner.__version__, and publishes to PyPI via Trusted Publishing.

# bump __version__ in project_scanner/__init__.py and update CHANGELOG.md first
git tag v0.2.1
git push origin v0.2.1

Check what is installed at any time with:

multiscan --version

To build and publish by hand, use publish.sh — it lints, builds, validates metadata, smoke-tests the wheel in a clean environment and asks for confirmation before uploading:

./publish.sh            # upload to PyPI
./publish.sh --dry-run  # build and verify only
./publish.sh --test     # upload to TestPyPI
./publish.sh --verbose  # show PyPI's full response when an upload fails

Credentials come from ~/.pypirc (see .pypirc.example) or from TWINE_USERNAME=__token__ and TWINE_PASSWORD, which take precedence over the file.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

multi_engine_scanner-0.2.3.tar.gz (44.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

multi_engine_scanner-0.2.3-py3-none-any.whl (50.5 kB view details)

Uploaded Python 3

File details

Details for the file multi_engine_scanner-0.2.3.tar.gz.

File metadata

  • Download URL: multi_engine_scanner-0.2.3.tar.gz
  • Upload date:
  • Size: 44.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.0

File hashes

Hashes for multi_engine_scanner-0.2.3.tar.gz
Algorithm Hash digest
SHA256 0e208a94f55cb679313a0c6d78be693b129c294128f4a4242b47bfbc97e601d2
MD5 ff3fca4f7a0428cd06ced54e06f87f94
BLAKE2b-256 6920633d8bbc5df202cd1ecb06cabf78be7012d40be9b337b9f910d30284be47

See more details on using hashes here.

File details

Details for the file multi_engine_scanner-0.2.3-py3-none-any.whl.

File metadata

File hashes

Hashes for multi_engine_scanner-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 6366edc31de8b00ca7b047c2ce955f9434879c895f1cd4ee3b7a660f7818ae10
MD5 087cebb39e233152a7ad1c2c0c534d72
BLAKE2b-256 4a504bcc9d407d8989c5259d9c3f9c69beb417c6de0d614f07a81ab593fd18b9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page