Metadata-Version: 2.4
Name: multi-engine-scanner
Version: 0.2.9
Summary: Multi-engine project security scanner (Grype, Trivy, Ruff, SQLFluff) with branded HTML, Markdown and JSON reporting
Author-email: Chandra Bahadur Khadka <chandra2khadka4@gmail.com>
Maintainer-email: Chandra Bahadur Khadka <chandra2khadka4@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://gitlab.com/chandrabrt/multi-engine-scanner
Project-URL: Repository, https://gitlab.com/chandrabrt/multi-engine-scanner
Project-URL: Issues, https://gitlab.com/chandrabrt/multi-engine-scanner/-/issues
Project-URL: Changelog, https://gitlab.com/chandrabrt/multi-engine-scanner/-/blob/main/CHANGELOG.md
Keywords: security,vulnerability,scanner,sast,sbom,cve,grype,trivy,ruff,sqlfluff,devsecops,reporting
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: engines
Requires-Dist: ruff>=0.4; extra == "engines"
Requires-Dist: sqlfluff>=4.2.0; extra == "engines"
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5.1; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Dynamic: license-file

# <img src="docs/assets/logo.png" width="36" height="36" align="left" style="margin-right:12px; vertical-align:middle;" /> Multi-Engine Scanner

[![PyPI](https://img.shields.io/pypi/v/multi-engine-scanner.svg)](https://pypi.org/project/multi-engine-scanner/)
[![Python](https://img.shields.io/pypi/pyversions/multi-engine-scanner.svg)](https://pypi.org/project/multi-engine-scanner/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

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`.

```bash
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/`](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` |

```bash
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:

```bash
pip install multi-engine-scanner
```

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

<details>
<summary><b>macOS / Linux</b></summary>

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install multi-engine-scanner
```
</details>

<details>
<summary><b>Windows (PowerShell)</b></summary>

```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`.
</details>

### 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:

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

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

#### macOS

```bash
brew install grype trivy
```

#### Linux

```bash
# 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:

```bash
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](https://chocolatey.org/) in an elevated PowerShell:

```powershell
choco install grype trivy
```

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

- Grype — https://github.com/anchore/grype/releases (`grype_*_windows_amd64.zip`)
- Trivy — https://github.com/aquasecurity/trivy/releases (`trivy_*_windows-64bit.zip`)

```powershell
# 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

```bash
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

```bash
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:

```bash
python -m project_scanner /path/to/project
```

## CLI Usage Examples

### Scan Current Directory
```bash
multiscan
```

### Scan Specific Project Directory
```bash
multiscan /path/to/your/project
```

### Specify Output Directory & Formats
```bash
multiscan /path/to/target --out-dir ./security-reports --format html,markdown
```

### Filter Minimum Severity
```bash
multiscan /path/to/target --min-severity HIGH
```

### Run Single Scanner Only
```bash
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.

```bash
multiscan --fix
```

```bash
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:

```bash
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](https://docs.astral.sh/ruff/linter/#rule-selection).
`--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.

```bash
# security rules only (Bandit-derived S rules)
multiscan /path/to/target --ruff-only --ruff-select S
```

```bash
# everything except line-length and import-sorting
multiscan /path/to/target --ruff-ignore E501,I001
```

```bash
# fix import ordering and unused imports, nothing else
multiscan /path/to/target --ruff-select I,F401 --fix
```

### Report the installed version
```bash
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 |


Check what is installed at any time with:

```bash
multiscan --version
```

## License

MIT — see [LICENSE](LICENSE).
