Metadata-Version: 2.4
Name: multi-engine-scanner
Version: 0.2.2
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>=3.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

# 🛡️ 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** in a corporate theme (light/dark, live search, severity
    and engine filters, sortable + paginated register, expandable finding 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 |
| :--- | :--- | :--- |
| Accent | `#028673` | Headings, links, primary buttons, active states |
| Primary | `#1A272C` | Masthead, table headers, body ink |
| Canvas | `#ECECEC` | Page background, with white surfaces on top |
| Heading face | Titillium Web | `h1`–`h3`, KPI figures, posture band |
| Body face | Open Sans | Everything else |
| Radius | `5px` surfaces, `0` controls | Cards vs buttons, inputs and badges |
| Elevation | none | Flat surfaces separated by hairline borders |

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

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

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

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

```bash
./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](.pypirc.example)) or from
`TWINE_USERNAME=__token__` and `TWINE_PASSWORD`, which take precedence over the file.

## License

MIT — see [LICENSE](LICENSE).
