Metadata-Version: 2.4
Name: reachguard
Version: 0.2.0
Summary: Refined. Secure. Connected. — Reachability-aware dependency vulnerability scanner for Python
Author-email: Chaitanya Bhujbal <chaitanyabhujbal912006@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/chaitanyabhujbal912006-afk/reachguard
Project-URL: Repository, https://github.com/chaitanyabhujbal912006-afk/reachguard.git
Project-URL: Bug Tracker, https://github.com/chaitanyabhujbal912006-afk/reachguard/issues
Keywords: security,vulnerability,cve,reachability,call-graph,osv,static-analysis
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Security
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: typer>=0.9.0
Requires-Dist: rich>=13.0.0
Requires-Dist: requests>=2.28.0
Requires-Dist: pycg>=0.0.6
Dynamic: license-file


<p align="center">
  <img src="logo.png" alt="ReachGuard Logo" width="600" />
</p>

<p align="center">
  <strong>Refined. Secure. Connected.</strong><br>
  <em>Reachability-Aware Dependency Vulnerability Scanner for Python</em>
</p>

<p align="center">
  <a href="https://pypi.org/project/reachguard/"><img src="https://img.shields.io/pypi/v/reachguard.svg" alt="PyPI Version"></a>
  <a href="https://github.com/chaitanyabhujbal912006-afk/reachguard/releases"><img src="https://img.shields.io/github/v/release/chaitanyabhujbal912006-afk/reachguard.svg" alt="GitHub Release"></a>
  <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10%2B-blue.svg" alt="Python 3.10+"></a>
  <a href="https://github.com/chaitanyabhujbal912006-afk/reachguard"><img src="https://img.shields.io/badge/ReachGuard-0%20Reachable%20CVEs-brightgreen.svg" alt="ReachGuard Self-Scan"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
  <a href="https://osv.dev/"><img src="https://img.shields.io/badge/Vulnerability%20Data-OSV.dev-green.svg" alt="OSV.dev"></a>
  <a href="https://github.com/vitsalis/pycg"><img src="https://img.shields.io/badge/Call%20Graph-PyCG-purple.svg" alt="PyCG Powered"></a>
</p>

---

## 🎯 The Problem

Traditional dependency security tools (**Dependabot**, **Snyk**, **Safety**) flag hundreds of vulnerabilities simply because a package version is listed in `requirements.txt`. However, in real-world applications:

* **>80% of flagged CVEs are completely unreachable** because your application never imports or calls the vulnerable functions.
* Developers suffer from **severe alert fatigue**, leading to critical vulnerabilities being ignored amidst the noise.
* Enterprise reachability tools are expensive, proprietary, and require sending private code to external cloud SaaS platforms.

---

## ✨ The Solution

**ReachGuard** is an open-source, local-first, zero-cost vulnerability scanner that performs **static call-graph reachability analysis**. It traces your application's execution path from entry points down to external dependency calls to verify whether a vulnerable function can actually be reached at runtime.

```
[ Entry Points ] ---> [ AST Walk ] ---> [ PyCG Call Graph ]
                                               │
                                               ▼
[ OSV Advisory ] ---> [ Target Mine ] ---> [ BFS Reachability Check ]
                                               │
                                               ▼
                                  ┌──────────────────────────┐
                                  │   REACHABLE   (Action!)  │
                                  │   UNKNOWN     (Review)   │
                                  │   UNREACHABLE (Ignore)   │
                                  └──────────────────────────┘
```

---

## 💡 How It Works (In 2 Simple Steps)

1. **Finds CVEs in Dependencies**: ReachGuard reads your `requirements.txt` (or `pyproject.toml` / `Pipfile.lock`) and queries the open **OSV.dev** security database for known vulnerabilities.
2. **Traces Your Source Code**: It walks your Python source code (`--src ./src`), constructs a call graph via PyCG, and verifies: *"Does your code actually call the broken function inside that package?"*

### 📊 The 3 Statuses ReachGuard Gives You:

| Status | Meaning | Action |
|---|---|---|
| 🔴 **`REACHABLE`** | Your code **actually calls** the vulnerable function! | **Fix / Patch Immediately!** |
| 🟡 **`UNKNOWN`** | Package has a CVE, but advisory function details are sparse. | Manual Review. |
| 🟢 **`UNREACHABLE`** | Package has a CVE, but your code **never calls** that function. | **Safe to Ignore!** |

### 🔍 Real-World Example:

```text
Suppose your requirements.txt contains `werkzeug==2.3.3` (which has CVE-2023-221 in `parse_multipart`):

- Dependabot:  🔴 "CRITICAL VULNERABILITY! Update Werkzeug!" (Even if your app never uploads files!)
- ReachGuard:  🟢 "UNREACHABLE — Werkzeug has a CVE, but your code never calls parse_multipart()."
- ReachGuard:  🔴 "REACHABLE   — app.py::download() -> Flask.dispatch_request() -> werkzeug.safe_join()"
```

---

## 🚀 Key Features

* 🎯 **Smart Reachability Ranking**: Classifies findings into:
  * `REACHABLE` 🔴: Vulnerable function is reachable from application entry points (High Priority).
  * `UNKNOWN` 🟡: Package is imported but function-level advisory details are sparse (Manual Review).
  * `UNREACHABLE` 🟢: Package contains a CVE, but the vulnerable code path is never called (Safe to Deprioritize).
* ⚡ **Zero-Cost & Local-First**: Built entirely on free, open tools — **OSV.dev API** (no API key needed) and **PyCG** (static analysis).
* 📦 **Multi-Format & Dynamic Dependency Support**: Auto-detects `requirements.txt`, `pyproject.toml` (PEP 621 & Poetry), and `Pipfile.lock`. Automatically resolves exact pins (`flask==2.3.2`) as well as unpinned or version-ranged dependencies (`flask>=2.0`) via `importlib.metadata`.
* 🔍 **AST Entry Point Detector**: Automatically identifies `if __name__ == '__main__'` blocks and web route handlers (`@app.route`, `@app.get`, `@router.post` for Flask, FastAPI, Starlette).
* 🧹 **Noise & Stdlib Filter**: Eliminates false positives by filtering standard library method references (`str.format`) and template filter names (`xmlattr`).
* 📊 **CI/CD Integrated**: Rich terminal formatting with severity levels (`CRITICAL`, `HIGH`, `MEDIUM`, `LOW`), `--output-json` exports, `--output-sarif` for GitHub Code Scanning, `--output-html` interactive dashboards, and `--fail-on-reachable` exit gates for build pipelines.
* 🪝 **Pre-Commit Hook**: Native [pre-commit](https://pre-commit.com/) framework support — block commits automatically if reachable CVEs are detected.

---

## ⚙️ Installation

### Option 1: Via PyPI (Recommended)
Install ReachGuard globally from PyPI:

```bash
pip install reachguard
```

### Option 2: From Source
```bash
git clone https://github.com/chaitanyabhujbal912006-afk/reachguard.git
cd reachguard
pip install -e .
```

*(Requirements include `typer`, `rich`, `requests`, and `pycg`)*

---

## 💻 Quick Start & Usage

### 1. Basic Scan (Auto-build Call Graph)
Provide your dependency file and source code directory. ReachGuard will automatically detect entry points and generate the call graph:

```bash
reachguard requirements.txt --src ./src
```

### 2. Scan using Pre-Built Call Graph
If you already generated a PyCG call graph JSON file:

```bash
reachguard requirements.txt --src ./src --call-graph callgraph.json
```

### 3. CI/CD Quality Gate Pipeline
Export findings to JSON and break the build if any `REACHABLE` vulnerabilities exist:

```bash
reachguard requirements.txt --src ./src --output-json report.json --fail-on-reachable
```

---

## 🤖 GitHub Actions Integration

Add ReachGuard as an automated security quality gate in your repository (`.github/workflows/security.yml`):

```yaml
name: ReachGuard Security Scan

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  reachguard-scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Run ReachGuard Reachability Scan
        uses: chaitanyabhujbal912006-afk/reachguard@main
        with:
          requirements: 'requirements.txt'
          src: '.'
          output_json: 'reachguard-report.json'
          fail_on_reachable: 'true'
```

---

## 🪝 Pre-Commit Integration

ReachGuard supports the [pre-commit](https://pre-commit.com/) framework, letting you block commits automatically when reachable CVEs are found.

### Setup

1. Install pre-commit (if you haven't already):
   ```bash
   pip install pre-commit
   ```

2. Add the following to your project's `.pre-commit-config.yaml`:
   ```yaml
   repos:
     - repo: https://github.com/chaitanyabhujbal912006-afk/reachguard
       rev: main  # or pin to a specific release tag
       hooks:
         - id: reachguard
           args: ["requirements.txt", "--src", ".", "--fail-on-reachable"]
   ```

3. Install the hooks:
   ```bash
   pre-commit install
   ```

From now on, every `git commit` will automatically run a ReachGuard scan. Commits are blocked if any `REACHABLE` CVEs are found.

---


```text
Usage: reachguard [OPTIONS] REQUIREMENTS_PATH

Arguments:
  REQUIREMENTS_PATH  Path to requirements.txt, pyproject.toml, or Pipfile.lock  [required]

Options:
  -s, --src TEXT          Path to Python source directory for auto call-graph & entry points.
  -g, --call-graph TEXT   Path to pre-built PyCG call graph JSON file.
  -o, --output-json TEXT  File path to export scan findings as structured JSON.
  --output-sarif TEXT     Write findings in SARIF v2.1.0 format (for GitHub Security Code Scanning).
  --output-html TEXT      Write an interactive HTML dashboard report to this file.
  --fail-on-reachable     Exit with non-zero status (1) if reachable CVEs are detected.
  --suggest-fixes         Display recommended pip upgrade patch commands for vulnerabilities.
  --help                  Show this message and exit.
```

---

## 📊 Sample Terminal Output

```text
ReachGuard scanning requirements.txt — 21 pinned dependencies

Loaded call graph: callgraph.json (137 nodes)
Entry points detected: 2

                            ReachGuard Scan Results                            
┌──────────────────┬─────────────────────┬──────────┬──────────────┬─────────────────────────────────────────┐
│ Package          │ CVE / ID            │ Severity │ Status       │ Summary                                 │
├──────────────────┼─────────────────────┼──────────┼──────────────┼─────────────────────────────────────────┤
│ werkzeug==2.3.3  │ GHSA-29vq-49wr-vm6x │ MODERATE │ REACHABLE    │ Werkzeug high resource usage parsing... │
│ werkzeug==2.3.3  │ GHSA-87hc-h4r5-73f7 │ MODERATE │ REACHABLE    │ Werkzeug parsing multipart form data... │
│ celery==5.2.7    │ GHSA-1234-abcd-5678 │ HIGH     │ UNKNOWN      │ Celery deserialization advisory         │
│ flask==2.3.2     │ GHSA-68rp-wp8r-4726 │ LOW      │ UNREACHABLE  │ Flask session Vary: Cookie header       │
│ jinja2==3.1.2    │ GHSA-q2x7-8rv6-6q7h │ MODERATE │ UNREACHABLE  │ Jinja sandbox breakout via format       │
└──────────────────┴─────────────────────┴──────────┴──────────────┴─────────────────────────────────────────┘

Summary:  2 reachable  |  1 unknown  |  2 unreachable  |  0 critical severity (total CVEs: 5)

! Action required: 2 CVE(s) are reachable from your code -- patch or mitigate these first.
```

---

## 🛠️ Architecture & How It Works

```
                     ┌───────────────────────────────┐
                     │   Dependency File Parser      │
                     │ (requirements / toml / lock)  │
                     └───────────────┬───────────────┘
                                     │
                                     ▼
                     ┌───────────────────────────────┐
                     │       OSV.dev API Query       │
                     └───────────────┬───────────────┘
                                     │
                                     ▼
┌──────────────────────────────┐    ┌──────────────────────────────┐
│  AST Entry Point Detector    │    │  PyCG Static Call Graph      │
│  (__main__, @app.route)      │    │  (Caller -> Callee Graph)    │
└──────────────┬───────────────┘    └──────────────┬───────────────┘
               │                                   │
               └─────────────────┬─────────────────┘
                                 │
                                 ▼
                     ┌───────────────────────────────┐
                     │   Three-Tier BFS Engine       │
                     │  1. Basename Match            │
                     │  2. Path-Prefix Match         │
                     │  3. Top-Level Entry Seed      │
                     └───────────────┬───────────────┘
                                     │
                                     ▼
                     ┌───────────────────────────────┐
                     │     Rich Terminal & JSON      │
                     └───────────────────────────────┘
```

1. **Dependency Ingestion**: Auto-detects dependency files and normalizes package names and exact pinned versions according to PEP 503.
2. **Advisory Resolution**: Batch queries OSV.dev REST endpoints to retrieve known vulnerability data and extracts function targets using heuristic regex mining.
3. **Call Graph Generation**: Invokes PyCG to construct a complete control-flow call graph of Python callables.
4. **AST Entry Point Mining**: Walks repository ASTs to locate execution roots (`if __name__ == '__main__'`, Flask/FastAPI route decorators).
5. **Graph Traversal (BFS)**: Executes a multi-tier Breadth-First Search from discovered entry points to target vulnerability functions, returning a deterministic `ReachabilityStatus`.

---

## 🧪 Running Tests

ReachGuard includes a 35-test suite covering AST parsing, OSV target extraction, noise filtering, call-graph normalisation, and reachability traversal:

```bash
python tests/test_suite.py
```

---

## 🗺️ Roadmap & Future Backlog

Interested in what's coming next or looking to contribute? Check out our detailed [**ROADMAP.md**](ROADMAP.md) for planned features including:
- 💡 **Auto-Remediation Patch Advice (`--suggest-fixes`)**
- 🛡️ **SARIF v2.1.0 Export (`--output-sarif`)**
- 📊 **Interactive HTML Dashboards (`--output-html`)**
- 🪝 **Pre-Commit Git Hooks**
- 🔍 **Extended Framework Detectors (Django, Celery, Click)**

---

## 🤝 Contributing

Contributions are welcome! Feel free to open an issue or submit a pull request:

1. Fork the Project
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

---

## 📜 License

Distributed under the MIT License. See [`LICENSE`](LICENSE) for details.
