Metadata-Version: 2.4
Name: safegate
Version: 2.0.0
Summary: Self-hosted security layer for LLM applications — detect PII by format, substitute or mask, and audit every call.
Project-URL: Homepage, https://github.com/patonkikh/SafeGate
Project-URL: Documentation, https://github.com/patonkikh/SafeGate#readme
Project-URL: Repository, https://github.com/patonkikh/SafeGate
Project-URL: Issues, https://github.com/patonkikh/SafeGate/issues
Project-URL: Changelog, https://github.com/patonkikh/SafeGate/blob/main/CHANGELOG.md
Author: SafeGate Contributors
License: MIT
License-File: LICENSE
Keywords: ai,guardrails,llm,pii,security
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Requires-Python: >=3.10
Requires-Dist: pyyaml>=6.0
Provides-Extra: all
Requires-Dist: boto3>=1.28; extra == 'all'
Requires-Dist: build>=1.0; extra == 'all'
Requires-Dist: clickhouse-connect>=0.7; extra == 'all'
Requires-Dist: langchain-core>=0.2; extra == 'all'
Requires-Dist: openai>=1.0; extra == 'all'
Requires-Dist: pillow>=10.0; extra == 'all'
Requires-Dist: psycopg[binary]>=3.1; extra == 'all'
Requires-Dist: pymongo>=4.0; extra == 'all'
Requires-Dist: pymysql>=1.1; extra == 'all'
Requires-Dist: pytesseract>=0.3; extra == 'all'
Requires-Dist: pytest-cov>=5.0; extra == 'all'
Requires-Dist: pytest>=8.0; extra == 'all'
Requires-Dist: redis>=5.0; extra == 'all'
Requires-Dist: ruff>=0.4; extra == 'all'
Provides-Extra: clickhouse
Requires-Dist: clickhouse-connect>=0.7; extra == 'clickhouse'
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.2; extra == 'langchain'
Provides-Extra: mongodb
Requires-Dist: pymongo>=4.0; extra == 'mongodb'
Provides-Extra: mysql
Requires-Dist: pymysql>=1.1; extra == 'mysql'
Provides-Extra: ocr
Requires-Dist: pillow>=10.0; extra == 'ocr'
Requires-Dist: pytesseract>=0.3; extra == 'ocr'
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == 'openai'
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
Provides-Extra: redis
Requires-Dist: redis>=5.0; extra == 'redis'
Provides-Extra: s3
Requires-Dist: boto3>=1.28; extra == 's3'
Description-Content-Type: text/markdown

<div align="center">

**English** | [Русский](README.ru.md)

# SafeGate

**Self-hosted AI security platform for LLM applications**

Protect sensitive data · Stop prompt attacks · Control inference cost · Audit everything

[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![CI](https://github.com/patonkikh/SafeGate/actions/workflows/ci.yml/badge.svg)](https://github.com/patonkikh/SafeGate/actions/workflows/ci.yml)
[![Version](https://img.shields.io/badge/version-2.0.0-orange.svg)](CHANGELOG.md)

[Features](#features) · [Quick start](#quick-start) · [What we detect](#what-we-detect) · [Examples](#examples) · [How it works](#how-it-works) · [Docs](#documentation)

<sub><code>pip install safegate</code></sub>

</div>

---

## Features

SafeGate sits **between your app and the LLM** (and around RAG embeddings). You enable only the stages you need.

| Capability | What you get | How to use |
|------------|--------------|------------|
| **PII / secrets detection** | 60+ entity types across identity, finance, health, network, vehicles, RU/US/UK IDs | `SafeGate()` / `entity_types=[...]` |
| **Substitution or mask** | **Prompt:** replace with dictionary fakes, or `***`. **Response:** always `***` (never fake values to the user) | `protection_mode="substitute"` / `"mask"` |
| **Prompt & response guards** | Protect text before the LLM call; scan the answer for leaks; mask residual PII in the reply | `protect_prompt` → `invoke` → `protect_response` |
| **Choose what to detect** | Enable only the sensitive types you care about; everything else is ignored | `entity_types=["email", "ssn", …]` |
| **EDOS guard** (optional) | Score “cognitive bomb” prompts; strip wasteful instructions, route to a fallback LLM, or block | `edos_enabled`, `edos_high_risk_action` |
| **Vector privacy** (RAG) | ε-differential privacy noise + lineage obfuscation for embeddings | `VectorPrivacyGuard` / `ContextGuard` |
| **Policies & industry packs** | YAML rules, presets (`health_hipaa`, `bank_ru`, …), simulator | `preset="…"`, `safegate policy catalog` |
| **Audit & SIEM** | JSONL trail, CEF/ECS/CSV export, approval workflow | `audit_path=…` |

```
Prompt  →  PII guard  →  EDOS*  →  your LLM  →  response guard  →  user
RAG     →  context guard  →  vector privacy*  →  vector DB

* optional stages
```

---

## Quick start

### Install

```bash
pip install safegate
```

### 1) Protect text (no LLM required)

```python
from safegate import SafeGate

guard = SafeGate(protection_mode="substitute")  # or "mask"
session = guard.protect_prompt(
    "Contact Alice at alice@company.com or +1 (415) 555-0100"
)
print(session.prompt_result.text)
# Contact … at <dictionary email> or <dictionary phone>
print(session.prompt_mappings)
```

### 2) Detect only selected types

```python
from safegate import SafeGate, list_entity_types

# only email + phone + SSN
guard = SafeGate(entity_types=["email", "phone", "ssn"])

# or a whole domain
guard = SafeGate(entity_types=list_entity_types("financial"))
```

Full catalog: [docs/SENSITIVE_ATTRIBUTES.md](docs/SENSITIVE_ATTRIBUTES.md)  
CLI: `safegate entities list --domains`

### 3) Wire your real LLM

```python
from safegate import SafeGate
from safegate.llm import OpenAIAdapter  # or OllamaAdapter

guard = SafeGate(protection_mode="substitute")
session = (
    guard.protect_prompt("My SSN is 123-45-6789")
    .invoke(OpenAIAdapter(client, model="gpt-4o-mini"))
    .protect_response()
)
print(session.result)
```

`OpenAIAdapter` works with any OpenAI-compatible API. `OllamaAdapter` is for local models.

> **About `MockLLM`:** it is a tiny stub that returns a fixed string. SafeGate uses it only in **unit tests** and **offline demos** so CI does not need API keys. It is **not** a production model — pass your own adapter to `invoke()` / `chat()`.

### 4) Optional: EDOS cost protection

```python
guard = SafeGate(
    edos_enabled=True,                          # set False to skip the stage
    edos_high_risk_action="block",              # or "route_fallback"
    fallback_llm=OpenAIAdapter(cheap_client, model="gpt-4o-mini"),
)
```

### 5) Optional: RAG embedding privacy

```python
from safegate import VectorPrivacyGuard
from safegate.guards import ContextChunk, ContextGuard

vector_guard = VectorPrivacyGuard(epsilon=1.0)
ctx = ContextGuard(vector_privacy=vector_guard)
result = ctx.protect_embeddings(
    [ContextChunk(id="doc-1", text=text, embedding=vector)]
)
```

---

## What we detect

Entities are grouped into **domains**. Enable a domain or pick individual types.

| Domain | Types (examples) |
|--------|------------------|
| **identity** | `full_name`, `date_of_birth`, `passport`, `us_passport`, driver licenses |
| **contact** | `email`, `phone`, `address`, `zip_code` |
| **national_ids** | `ssn`, `nino` (UK), `inn`/`snils` (RU), `ein`, `itin`, `employee_id` |
| **financial** | `credit_card`, `cvv`, `card_expiration`, `iban`, `swift_bic`, `salary`, bank accounts |
| **health** | `medical`, `member_id`, `insurance_id`, `npi`, `medicare_id` |
| **credentials** | `password`, `username`, `api_key` |
| **network** | `ip_address`, `mac_address`, `domain`, `social_handle` (LinkedIn, @handles) |
| **vehicles** | `vin`, `vehicle_registration`, `ru_license_plate`, `frequent_flyer` |
| **business** | `commercial_secret` |
| **attacks** | `prompt_injection`, `jailbreak` (ThreatFeed) |

```bash
safegate entities list --domains
```

Complete tables with examples: **[docs/SENSITIVE_ATTRIBUTES.md](docs/SENSITIVE_ATTRIBUTES.md)**

---

## Examples

Sensitive values are found first, then either **substituted from a built-in dictionary** (prompt path) or **masked with `*`** (mask mode, and always on the LLM response).

<p align="center"><img src="docs/images/demo-detect.png" alt="PII detectors highlighting sensitive fields" width="720" /></p>

### Mode A — Dictionary substitution (prompt → LLM)

Fake values come from **generated dictionary pools** shipped with SafeGate (`gdpr_fakes`, `default`, industry packs). The vault maps each real value → one synthetic token for the session, so the LLM still sees realistic emails, phones, and IDs — not your real data.

```python
guard = SafeGate(protection_mode="substitute")
# michael.carter@example.com  →  sofia.brennan@privacy.test   (from dictionary)
# +1 (415) 555-0187           →  +49 30 4829173               (from dictionary)
```

<p align="center"><img src="docs/images/demo-substitute.png" alt="Prompt Guard substitutions from dictionary" width="720" /></p>

### Mode B — Mask with asterisks

```python
guard = SafeGate(protection_mode="mask")
# michael.carter@example.com  →  **************************
```

<p align="center"><img src="docs/images/demo-mask.png" alt="Prompt Guard masking with asterisks" width="720" /></p>

### LLM response — always masked

Whatever comes back from the model is **never** filled with dictionary fakes and is **never** restored to real PII by default. Residual PII and echoed substitute tokens are replaced with `*`. Opt-in `detokenize=True` restores real values only when you explicitly need that legacy behaviour.

<p align="center"><img src="docs/images/demo-llm-masked.png" alt="Prompt sent to the LLM after masking" width="720" /></p>

| Direction | Substitute mode | Mask mode |
|-----------|-----------------|-----------|
| **Prompt → LLM** | Dictionary fakes | `****` |
| **LLM → user** | `****` (always) | `****` (always) |

Local UI to try both modes:

```bash
cd local-demo && python app.py
# http://127.0.0.1:8765/
```

---

## How it works

```mermaid
flowchart LR
    A[Input] --> B[Detectors — optional entity filter]
    B --> C[Policy]
    C -->|substitute / mask / block| D[Prompt guard]
    D --> E[EDOS optional]
    E --> F[Your LLM]
    F --> G[Response guard — always mask]
    G --> H[Output]
```

| Stage | Role |
|-------|------|
| **Detectors** | Find sensitive values (filtered by `entity_types` if set) |
| **Policy** | Decide action per type: substitute · mask · block · remove |
| **Prompt guard** | Apply policy before the LLM call (dictionary or `****`) |
| **EDOS** | Optional complexity scoring / strip / route / block |
| **Response guard** | Leak check; **always mask** residual PII and echoed tokens with `****` |
| **Audit** | JSONL + SIEM fields including EDOS |

---

## Examples

| Example | Use case |
|---------|----------|
| [chatbot_demo.py](examples/chatbot_demo.py) | Chatbot with PII substitution |
| [rag_demo.py](examples/rag_demo.py) | RAG context guard |
| [mcp_demo.py](examples/mcp_demo.py) | MCP tool filter |
| [gateway_client.py](examples/gateway_client.py) | REST AI gateway |
| [langchain_demo.py](examples/langchain_demo.py) | LangChain handler |

Full list: [examples/README.md](examples/README.md)

---

## Industry packs

`bank_ru` · `health_hipaa` · `gov_fz152` · `retail_eu` · `fintech_us` · `insurance_us` · `saas_global` · `telecom_eu` · `education_us` · `energy_eu` · `legal_eu` · `logistics_eu`

```bash
safegate policy catalog --format markdown
```

```python
guard = SafeGate(preset="health_hipaa", region="us")
```

---

## Documentation

| Doc | Contents |
|-----|----------|
| [SENSITIVE_ATTRIBUTES.md](docs/SENSITIVE_ATTRIBUTES.md) | Full entity catalog + how to select types |
| [INSTALL.md](docs/INSTALL.md) | Install / Docker |
| [COMPARISON.md](docs/COMPARISON.md) | vs Presidio / LLM Guard |
| [PRODUCT_ROADMAP.md](docs/PRODUCT_ROADMAP.md) | Platform roadmap |

---

## Contributing

SafeGate is open source ([MIT](LICENSE)).

```bash
git clone https://github.com/patonkikh/SafeGate.git
cd SafeGate
python -m pip install -e ".[dev]"
pytest -v
```

| | |
|---|---|
| **Issues** | [github.com/patonkikh/SafeGate/issues](https://github.com/patonkikh/SafeGate/issues) |
| **Guidelines** | [CONTRIBUTING.md](CONTRIBUTING.md) |
| **Security** | [SECURITY.md](SECURITY.md) |

---

## License

[MIT](LICENSE)
