aegis-privacy-proxy 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aegis_privacy_proxy-0.1.0/LICENSE +21 -0
- aegis_privacy_proxy-0.1.0/PKG-INFO +186 -0
- aegis_privacy_proxy-0.1.0/README.md +152 -0
- aegis_privacy_proxy-0.1.0/aegis_privacy_proxy.egg-info/PKG-INFO +186 -0
- aegis_privacy_proxy-0.1.0/aegis_privacy_proxy.egg-info/SOURCES.txt +22 -0
- aegis_privacy_proxy-0.1.0/aegis_privacy_proxy.egg-info/dependency_links.txt +1 -0
- aegis_privacy_proxy-0.1.0/aegis_privacy_proxy.egg-info/entry_points.txt +2 -0
- aegis_privacy_proxy-0.1.0/aegis_privacy_proxy.egg-info/requires.txt +15 -0
- aegis_privacy_proxy-0.1.0/aegis_privacy_proxy.egg-info/top_level.txt +2 -0
- aegis_privacy_proxy-0.1.0/aegismcp/__init__.py +6 -0
- aegis_privacy_proxy-0.1.0/aegismcp/cli.py +44 -0
- aegis_privacy_proxy-0.1.0/aegismcp/crypto.py +43 -0
- aegis_privacy_proxy-0.1.0/aegismcp/detectors.py +264 -0
- aegis_privacy_proxy-0.1.0/aegismcp/engine.py +61 -0
- aegis_privacy_proxy-0.1.0/aegismcp/redis_vault.py +97 -0
- aegis_privacy_proxy-0.1.0/aegismcp/vault.py +48 -0
- aegis_privacy_proxy-0.1.0/proxy_server.py +675 -0
- aegis_privacy_proxy-0.1.0/pyproject.toml +55 -0
- aegis_privacy_proxy-0.1.0/setup.cfg +4 -0
- aegis_privacy_proxy-0.1.0/tests/test_detectors.py +112 -0
- aegis_privacy_proxy-0.1.0/tests/test_proxy.py +488 -0
- aegis_privacy_proxy-0.1.0/tests/test_redis_integration.py +76 -0
- aegis_privacy_proxy-0.1.0/tests/test_redis_vault.py +73 -0
- aegis_privacy_proxy-0.1.0/tests/test_tokenization.py +43 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AEGISMCP contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aegis-privacy-proxy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Developer-first security and privacy proxy for AI workflows
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Environment :: Web Environment
|
|
8
|
+
Classifier: Framework :: FastAPI
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Security
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: fastapi<1,>=0.115
|
|
21
|
+
Requires-Dist: uvicorn<1,>=0.30
|
|
22
|
+
Requires-Dist: redis<7,>=5
|
|
23
|
+
Requires-Dist: cryptography<46,>=42
|
|
24
|
+
Requires-Dist: httpx<1,>=0.27
|
|
25
|
+
Requires-Dist: click<9,>=8.1
|
|
26
|
+
Requires-Dist: python-dotenv<2,>=1
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pytest<9,>=8; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-asyncio<2,>=0.24; extra == "test"
|
|
30
|
+
Provides-Extra: pii
|
|
31
|
+
Requires-Dist: presidio-analyzer<3,>=2.2; extra == "pii"
|
|
32
|
+
Requires-Dist: spacy<4,>=3.7; extra == "pii"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# AEGISMCP
|
|
36
|
+
|
|
37
|
+
**Developer-first security and privacy proxy for AI workflows.**
|
|
38
|
+
|
|
39
|
+
AEGISMCP is an OpenAI-compatible local proxy that detects selected secrets and personal data, replaces them with scoped placeholders before forwarding prompts, and restores values in responses locally. Its encrypted Redis vault stores temporary mappings with a short TTL.
|
|
40
|
+
|
|
41
|
+
> Phase 1 is an alpha prototype. Review the security notes below before using it with real data.
|
|
42
|
+
|
|
43
|
+
## Why AEGISMCP
|
|
44
|
+
|
|
45
|
+
Prompts can accidentally include API keys, credentials, or personal information. Once sent to an external model, that content has left the developer's environment. AEGISMCP aims to reduce that exposure while preserving prompt context: the model sees placeholders such as `[API_KEY_01]`, and the trusted proxy can restore them in the response.
|
|
46
|
+
|
|
47
|
+
## Detection coverage
|
|
48
|
+
|
|
49
|
+
The default detector runs locally and offline. Its rules cover common provider keys and tokens (OpenAI-style, AWS access keys, GitHub, GitLab, Slack, Stripe, Google API keys), bearer and Basic-auth credentials, JWTs, private-key blocks, labeled passwords/secrets, one-time/PIN codes, and credentials embedded in database or web URLs. It also checks for email addresses, phone numbers, payment cards (with Luhn validation), IBANs (with MOD-97 validation), UPI IDs, IP and MAC addresses, and labeled government IDs, dates of birth, and street addresses. India-specific rules include Aadhaar, PAN, and GSTIN formats; additional labeled rules cover identifiers such as SSNs, ITINs, passports, and driver's licenses.
|
|
50
|
+
|
|
51
|
+
To add local name and location recognition plus Presidio's larger regional recognizer set, install the optional PII extra and its small English spaCy model:
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
python -m pip install -e ".[pii]"
|
|
55
|
+
python -m spacy download en_core_web_sm
|
|
56
|
+
$env:AEGIS_PII_ENGINE = 'presidio'
|
|
57
|
+
aegismcp proxy --upstream-base-url https://api.openai.com/v1
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Presidio combines patterns, checksums, context, and named-entity recognition, and supports custom recognizers and country-specific entities. Its supported entity list varies by release and locale; see the [Presidio supported entities](https://microsoft.github.io/presidio/supported_entities/) and [Analyzer documentation](https://microsoft.github.io/presidio/analyzer/). For programmatic use, exact names and organization-specific identifiers can be added locally:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from aegismcp.detectors import PatternDetector
|
|
64
|
+
|
|
65
|
+
detector = PatternDetector(
|
|
66
|
+
known_names=["Ada Lovelace"],
|
|
67
|
+
custom_patterns={"EMPLOYEE_ID": r"\bEMP-\d{6}\b"},
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
No detector can find every sensitive fact in arbitrary text. Whether information identifies a person can depend on context and combinations of fields such as location and birth date, as NIST discusses in [SP 800-122](https://csrc.nist.gov/pubs/sp/800/122/final). Regex rules can miss unknown formats; NER can miss names or locations, especially across languages. The default mode does not send text to an external detection service. Test against your own data types and add organization-specific recognizers before relying on it.
|
|
72
|
+
|
|
73
|
+
## Quickstart
|
|
74
|
+
|
|
75
|
+
Requirements: Python 3.10+, Docker Desktop with Compose, and the repository checkout.
|
|
76
|
+
|
|
77
|
+
To install the published distribution from PyPI:
|
|
78
|
+
|
|
79
|
+
```powershell
|
|
80
|
+
python -m pip install aegis-privacy-proxy
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
1. **Prepare and start ephemeral local Redis.** Generate local TLS/ACL credentials once, then start Redis:
|
|
84
|
+
|
|
85
|
+
```powershell
|
|
86
|
+
python scripts/prepare_live_redis.py
|
|
87
|
+
docker compose up -d
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Keep the generated `.env.redis`, `docker/users.acl`, and `secrets/redis-tls/` files private. If you have already generated them, skip the setup script.
|
|
91
|
+
|
|
92
|
+
2. **Install AEGISMCP and its CLI.** A virtual environment is recommended:
|
|
93
|
+
|
|
94
|
+
```powershell
|
|
95
|
+
python -m venv .venv
|
|
96
|
+
.\.venv\Scripts\Activate.ps1
|
|
97
|
+
python -m pip install -e .
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
3. **Start the proxy.** Configure an upstream URL and provider first. For the local mock demo, use the URL below; for a real provider, set its API base URL instead.
|
|
101
|
+
|
|
102
|
+
```powershell
|
|
103
|
+
aegismcp proxy --upstream-base-url http://127.0.0.1:8101/v1
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The proxy listens on `http://127.0.0.1:8000`. In a second terminal, run the no-provider-key demo:
|
|
107
|
+
|
|
108
|
+
```powershell
|
|
109
|
+
python examples/chat_test.py
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The example starts a mock upstream, prints the sanitized prompt it receives, and then prints the response after local restoration. It uses only a fake key and does not call an external model.
|
|
113
|
+
|
|
114
|
+
## OpenAI-compatible client
|
|
115
|
+
|
|
116
|
+
Point an OpenAI SDK client at the local proxy. Keep the real provider credential in an environment variable; the proxy consumes `X-Upstream-Api-Key` and forwards it upstream.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
import os
|
|
120
|
+
from openai import OpenAI
|
|
121
|
+
|
|
122
|
+
client = OpenAI(
|
|
123
|
+
base_url="http://localhost:8000/v1",
|
|
124
|
+
api_key="proxy-placeholder", # Required by the SDK; proxy does not use this value.
|
|
125
|
+
default_headers={"X-Upstream-Api-Key": os.environ["MODEL_API_KEY"]},
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
result = client.chat.completions.create(
|
|
129
|
+
model="gpt-4o-mini",
|
|
130
|
+
messages=[{"role": "user", "content": "Summarize this text..."}],
|
|
131
|
+
)
|
|
132
|
+
print(result.choices[0].message.content)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The current ingress API is OpenAI-compatible `POST /v1/chat/completions`. OpenAI-compatible clients can use the proxy with OpenAI, Ollama, or the included basic Anthropic upstream adapter. The native Anthropic SDK `/v1/messages` ingress is not implemented; Anthropic upstream requests are made through AEGISMCP's OpenAI-compatible interface.
|
|
136
|
+
|
|
137
|
+
## Configuration
|
|
138
|
+
|
|
139
|
+
The proxy reads Redis and vault settings from `.env.redis` by default. Common settings can also be supplied as environment variables or CLI options:
|
|
140
|
+
|
|
141
|
+
```powershell
|
|
142
|
+
$env:AEGIS_UPSTREAM_PROVIDER = 'openai' # openai, anthropic, or ollama
|
|
143
|
+
$env:AEGIS_MODE = 'enforce' # enforce or warn
|
|
144
|
+
$env:AEGIS_UPSTREAM_BASE_URL = 'https://api.openai.com/v1'
|
|
145
|
+
aegismcp proxy
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
You can also pass `--provider`, `--mode`, `--host`, `--port`, and `--env-file` to `aegismcp proxy`. In `enforce` mode, tokenization and restoration errors fail closed. `warn` mode logs detected entity categories/counts and forwards original content unchanged; use it only with synthetic data.
|
|
149
|
+
|
|
150
|
+
## Security notes and limitations
|
|
151
|
+
|
|
152
|
+
- Regex and pattern-based detectors are experimental. They can miss sensitive values and produce false positives; names in particular are not reliably identified by regex alone.
|
|
153
|
+
- Optional Presidio detection runs locally when installed and enabled; it adds coverage but does not make detection exhaustive. The default detector remains offline and rule-based.
|
|
154
|
+
- The local Compose setup publishes Redis only on `127.0.0.1:6380` so a host-installed proxy can reach it; it still requires TLS/mTLS, ACLs, in-memory operation, and strict TTLs. Do not bind Redis to public interfaces. In production, place Redis on a private network beside the proxy. The Compose setup is a development example, not a production deployment blueprint.
|
|
155
|
+
- AEGISMCP is not a substitute for access control, secret management, or data-loss prevention. Audit detector behavior, proxy configuration, tenant identity handling, and failure modes before production use.
|
|
156
|
+
- The proxy process is inside the trusted boundary. Python cannot reliably zeroize immutable plaintext or key objects in memory.
|
|
157
|
+
- Multi-tenant deployments need authenticated tenant identity middleware. Do not derive tenant identity from prompt text or an untrusted request field.
|
|
158
|
+
|
|
159
|
+
## Tests
|
|
160
|
+
|
|
161
|
+
Run unit and mocked-upstream tests locally with the test extra:
|
|
162
|
+
|
|
163
|
+
```powershell
|
|
164
|
+
python -m pip install -e ".[test]"
|
|
165
|
+
python -m pytest -q
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
To run the real optional name/location NER test, install the PII extra and English model first. The test skips when that optional model is not installed:
|
|
169
|
+
|
|
170
|
+
```powershell
|
|
171
|
+
python -m pip install -e ".[test,pii]"
|
|
172
|
+
python -m spacy download en_core_web_sm
|
|
173
|
+
python -m pytest -q tests/test_detectors.py
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
To include the TLS Redis integration test in the Compose environment:
|
|
177
|
+
|
|
178
|
+
```powershell
|
|
179
|
+
docker compose --profile test run --rm redis-test
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Stop the local Redis service with `docker compose down` when finished.
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
AEGISMCP is released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# AEGISMCP
|
|
2
|
+
|
|
3
|
+
**Developer-first security and privacy proxy for AI workflows.**
|
|
4
|
+
|
|
5
|
+
AEGISMCP is an OpenAI-compatible local proxy that detects selected secrets and personal data, replaces them with scoped placeholders before forwarding prompts, and restores values in responses locally. Its encrypted Redis vault stores temporary mappings with a short TTL.
|
|
6
|
+
|
|
7
|
+
> Phase 1 is an alpha prototype. Review the security notes below before using it with real data.
|
|
8
|
+
|
|
9
|
+
## Why AEGISMCP
|
|
10
|
+
|
|
11
|
+
Prompts can accidentally include API keys, credentials, or personal information. Once sent to an external model, that content has left the developer's environment. AEGISMCP aims to reduce that exposure while preserving prompt context: the model sees placeholders such as `[API_KEY_01]`, and the trusted proxy can restore them in the response.
|
|
12
|
+
|
|
13
|
+
## Detection coverage
|
|
14
|
+
|
|
15
|
+
The default detector runs locally and offline. Its rules cover common provider keys and tokens (OpenAI-style, AWS access keys, GitHub, GitLab, Slack, Stripe, Google API keys), bearer and Basic-auth credentials, JWTs, private-key blocks, labeled passwords/secrets, one-time/PIN codes, and credentials embedded in database or web URLs. It also checks for email addresses, phone numbers, payment cards (with Luhn validation), IBANs (with MOD-97 validation), UPI IDs, IP and MAC addresses, and labeled government IDs, dates of birth, and street addresses. India-specific rules include Aadhaar, PAN, and GSTIN formats; additional labeled rules cover identifiers such as SSNs, ITINs, passports, and driver's licenses.
|
|
16
|
+
|
|
17
|
+
To add local name and location recognition plus Presidio's larger regional recognizer set, install the optional PII extra and its small English spaCy model:
|
|
18
|
+
|
|
19
|
+
```powershell
|
|
20
|
+
python -m pip install -e ".[pii]"
|
|
21
|
+
python -m spacy download en_core_web_sm
|
|
22
|
+
$env:AEGIS_PII_ENGINE = 'presidio'
|
|
23
|
+
aegismcp proxy --upstream-base-url https://api.openai.com/v1
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Presidio combines patterns, checksums, context, and named-entity recognition, and supports custom recognizers and country-specific entities. Its supported entity list varies by release and locale; see the [Presidio supported entities](https://microsoft.github.io/presidio/supported_entities/) and [Analyzer documentation](https://microsoft.github.io/presidio/analyzer/). For programmatic use, exact names and organization-specific identifiers can be added locally:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from aegismcp.detectors import PatternDetector
|
|
30
|
+
|
|
31
|
+
detector = PatternDetector(
|
|
32
|
+
known_names=["Ada Lovelace"],
|
|
33
|
+
custom_patterns={"EMPLOYEE_ID": r"\bEMP-\d{6}\b"},
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
No detector can find every sensitive fact in arbitrary text. Whether information identifies a person can depend on context and combinations of fields such as location and birth date, as NIST discusses in [SP 800-122](https://csrc.nist.gov/pubs/sp/800/122/final). Regex rules can miss unknown formats; NER can miss names or locations, especially across languages. The default mode does not send text to an external detection service. Test against your own data types and add organization-specific recognizers before relying on it.
|
|
38
|
+
|
|
39
|
+
## Quickstart
|
|
40
|
+
|
|
41
|
+
Requirements: Python 3.10+, Docker Desktop with Compose, and the repository checkout.
|
|
42
|
+
|
|
43
|
+
To install the published distribution from PyPI:
|
|
44
|
+
|
|
45
|
+
```powershell
|
|
46
|
+
python -m pip install aegis-privacy-proxy
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
1. **Prepare and start ephemeral local Redis.** Generate local TLS/ACL credentials once, then start Redis:
|
|
50
|
+
|
|
51
|
+
```powershell
|
|
52
|
+
python scripts/prepare_live_redis.py
|
|
53
|
+
docker compose up -d
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Keep the generated `.env.redis`, `docker/users.acl`, and `secrets/redis-tls/` files private. If you have already generated them, skip the setup script.
|
|
57
|
+
|
|
58
|
+
2. **Install AEGISMCP and its CLI.** A virtual environment is recommended:
|
|
59
|
+
|
|
60
|
+
```powershell
|
|
61
|
+
python -m venv .venv
|
|
62
|
+
.\.venv\Scripts\Activate.ps1
|
|
63
|
+
python -m pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
3. **Start the proxy.** Configure an upstream URL and provider first. For the local mock demo, use the URL below; for a real provider, set its API base URL instead.
|
|
67
|
+
|
|
68
|
+
```powershell
|
|
69
|
+
aegismcp proxy --upstream-base-url http://127.0.0.1:8101/v1
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The proxy listens on `http://127.0.0.1:8000`. In a second terminal, run the no-provider-key demo:
|
|
73
|
+
|
|
74
|
+
```powershell
|
|
75
|
+
python examples/chat_test.py
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The example starts a mock upstream, prints the sanitized prompt it receives, and then prints the response after local restoration. It uses only a fake key and does not call an external model.
|
|
79
|
+
|
|
80
|
+
## OpenAI-compatible client
|
|
81
|
+
|
|
82
|
+
Point an OpenAI SDK client at the local proxy. Keep the real provider credential in an environment variable; the proxy consumes `X-Upstream-Api-Key` and forwards it upstream.
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import os
|
|
86
|
+
from openai import OpenAI
|
|
87
|
+
|
|
88
|
+
client = OpenAI(
|
|
89
|
+
base_url="http://localhost:8000/v1",
|
|
90
|
+
api_key="proxy-placeholder", # Required by the SDK; proxy does not use this value.
|
|
91
|
+
default_headers={"X-Upstream-Api-Key": os.environ["MODEL_API_KEY"]},
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
result = client.chat.completions.create(
|
|
95
|
+
model="gpt-4o-mini",
|
|
96
|
+
messages=[{"role": "user", "content": "Summarize this text..."}],
|
|
97
|
+
)
|
|
98
|
+
print(result.choices[0].message.content)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The current ingress API is OpenAI-compatible `POST /v1/chat/completions`. OpenAI-compatible clients can use the proxy with OpenAI, Ollama, or the included basic Anthropic upstream adapter. The native Anthropic SDK `/v1/messages` ingress is not implemented; Anthropic upstream requests are made through AEGISMCP's OpenAI-compatible interface.
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
The proxy reads Redis and vault settings from `.env.redis` by default. Common settings can also be supplied as environment variables or CLI options:
|
|
106
|
+
|
|
107
|
+
```powershell
|
|
108
|
+
$env:AEGIS_UPSTREAM_PROVIDER = 'openai' # openai, anthropic, or ollama
|
|
109
|
+
$env:AEGIS_MODE = 'enforce' # enforce or warn
|
|
110
|
+
$env:AEGIS_UPSTREAM_BASE_URL = 'https://api.openai.com/v1'
|
|
111
|
+
aegismcp proxy
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
You can also pass `--provider`, `--mode`, `--host`, `--port`, and `--env-file` to `aegismcp proxy`. In `enforce` mode, tokenization and restoration errors fail closed. `warn` mode logs detected entity categories/counts and forwards original content unchanged; use it only with synthetic data.
|
|
115
|
+
|
|
116
|
+
## Security notes and limitations
|
|
117
|
+
|
|
118
|
+
- Regex and pattern-based detectors are experimental. They can miss sensitive values and produce false positives; names in particular are not reliably identified by regex alone.
|
|
119
|
+
- Optional Presidio detection runs locally when installed and enabled; it adds coverage but does not make detection exhaustive. The default detector remains offline and rule-based.
|
|
120
|
+
- The local Compose setup publishes Redis only on `127.0.0.1:6380` so a host-installed proxy can reach it; it still requires TLS/mTLS, ACLs, in-memory operation, and strict TTLs. Do not bind Redis to public interfaces. In production, place Redis on a private network beside the proxy. The Compose setup is a development example, not a production deployment blueprint.
|
|
121
|
+
- AEGISMCP is not a substitute for access control, secret management, or data-loss prevention. Audit detector behavior, proxy configuration, tenant identity handling, and failure modes before production use.
|
|
122
|
+
- The proxy process is inside the trusted boundary. Python cannot reliably zeroize immutable plaintext or key objects in memory.
|
|
123
|
+
- Multi-tenant deployments need authenticated tenant identity middleware. Do not derive tenant identity from prompt text or an untrusted request field.
|
|
124
|
+
|
|
125
|
+
## Tests
|
|
126
|
+
|
|
127
|
+
Run unit and mocked-upstream tests locally with the test extra:
|
|
128
|
+
|
|
129
|
+
```powershell
|
|
130
|
+
python -m pip install -e ".[test]"
|
|
131
|
+
python -m pytest -q
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
To run the real optional name/location NER test, install the PII extra and English model first. The test skips when that optional model is not installed:
|
|
135
|
+
|
|
136
|
+
```powershell
|
|
137
|
+
python -m pip install -e ".[test,pii]"
|
|
138
|
+
python -m spacy download en_core_web_sm
|
|
139
|
+
python -m pytest -q tests/test_detectors.py
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
To include the TLS Redis integration test in the Compose environment:
|
|
143
|
+
|
|
144
|
+
```powershell
|
|
145
|
+
docker compose --profile test run --rm redis-test
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Stop the local Redis service with `docker compose down` when finished.
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
AEGISMCP is released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aegis-privacy-proxy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Developer-first security and privacy proxy for AI workflows
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Environment :: Web Environment
|
|
8
|
+
Classifier: Framework :: FastAPI
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Security
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: fastapi<1,>=0.115
|
|
21
|
+
Requires-Dist: uvicorn<1,>=0.30
|
|
22
|
+
Requires-Dist: redis<7,>=5
|
|
23
|
+
Requires-Dist: cryptography<46,>=42
|
|
24
|
+
Requires-Dist: httpx<1,>=0.27
|
|
25
|
+
Requires-Dist: click<9,>=8.1
|
|
26
|
+
Requires-Dist: python-dotenv<2,>=1
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pytest<9,>=8; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-asyncio<2,>=0.24; extra == "test"
|
|
30
|
+
Provides-Extra: pii
|
|
31
|
+
Requires-Dist: presidio-analyzer<3,>=2.2; extra == "pii"
|
|
32
|
+
Requires-Dist: spacy<4,>=3.7; extra == "pii"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# AEGISMCP
|
|
36
|
+
|
|
37
|
+
**Developer-first security and privacy proxy for AI workflows.**
|
|
38
|
+
|
|
39
|
+
AEGISMCP is an OpenAI-compatible local proxy that detects selected secrets and personal data, replaces them with scoped placeholders before forwarding prompts, and restores values in responses locally. Its encrypted Redis vault stores temporary mappings with a short TTL.
|
|
40
|
+
|
|
41
|
+
> Phase 1 is an alpha prototype. Review the security notes below before using it with real data.
|
|
42
|
+
|
|
43
|
+
## Why AEGISMCP
|
|
44
|
+
|
|
45
|
+
Prompts can accidentally include API keys, credentials, or personal information. Once sent to an external model, that content has left the developer's environment. AEGISMCP aims to reduce that exposure while preserving prompt context: the model sees placeholders such as `[API_KEY_01]`, and the trusted proxy can restore them in the response.
|
|
46
|
+
|
|
47
|
+
## Detection coverage
|
|
48
|
+
|
|
49
|
+
The default detector runs locally and offline. Its rules cover common provider keys and tokens (OpenAI-style, AWS access keys, GitHub, GitLab, Slack, Stripe, Google API keys), bearer and Basic-auth credentials, JWTs, private-key blocks, labeled passwords/secrets, one-time/PIN codes, and credentials embedded in database or web URLs. It also checks for email addresses, phone numbers, payment cards (with Luhn validation), IBANs (with MOD-97 validation), UPI IDs, IP and MAC addresses, and labeled government IDs, dates of birth, and street addresses. India-specific rules include Aadhaar, PAN, and GSTIN formats; additional labeled rules cover identifiers such as SSNs, ITINs, passports, and driver's licenses.
|
|
50
|
+
|
|
51
|
+
To add local name and location recognition plus Presidio's larger regional recognizer set, install the optional PII extra and its small English spaCy model:
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
python -m pip install -e ".[pii]"
|
|
55
|
+
python -m spacy download en_core_web_sm
|
|
56
|
+
$env:AEGIS_PII_ENGINE = 'presidio'
|
|
57
|
+
aegismcp proxy --upstream-base-url https://api.openai.com/v1
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Presidio combines patterns, checksums, context, and named-entity recognition, and supports custom recognizers and country-specific entities. Its supported entity list varies by release and locale; see the [Presidio supported entities](https://microsoft.github.io/presidio/supported_entities/) and [Analyzer documentation](https://microsoft.github.io/presidio/analyzer/). For programmatic use, exact names and organization-specific identifiers can be added locally:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from aegismcp.detectors import PatternDetector
|
|
64
|
+
|
|
65
|
+
detector = PatternDetector(
|
|
66
|
+
known_names=["Ada Lovelace"],
|
|
67
|
+
custom_patterns={"EMPLOYEE_ID": r"\bEMP-\d{6}\b"},
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
No detector can find every sensitive fact in arbitrary text. Whether information identifies a person can depend on context and combinations of fields such as location and birth date, as NIST discusses in [SP 800-122](https://csrc.nist.gov/pubs/sp/800/122/final). Regex rules can miss unknown formats; NER can miss names or locations, especially across languages. The default mode does not send text to an external detection service. Test against your own data types and add organization-specific recognizers before relying on it.
|
|
72
|
+
|
|
73
|
+
## Quickstart
|
|
74
|
+
|
|
75
|
+
Requirements: Python 3.10+, Docker Desktop with Compose, and the repository checkout.
|
|
76
|
+
|
|
77
|
+
To install the published distribution from PyPI:
|
|
78
|
+
|
|
79
|
+
```powershell
|
|
80
|
+
python -m pip install aegis-privacy-proxy
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
1. **Prepare and start ephemeral local Redis.** Generate local TLS/ACL credentials once, then start Redis:
|
|
84
|
+
|
|
85
|
+
```powershell
|
|
86
|
+
python scripts/prepare_live_redis.py
|
|
87
|
+
docker compose up -d
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Keep the generated `.env.redis`, `docker/users.acl`, and `secrets/redis-tls/` files private. If you have already generated them, skip the setup script.
|
|
91
|
+
|
|
92
|
+
2. **Install AEGISMCP and its CLI.** A virtual environment is recommended:
|
|
93
|
+
|
|
94
|
+
```powershell
|
|
95
|
+
python -m venv .venv
|
|
96
|
+
.\.venv\Scripts\Activate.ps1
|
|
97
|
+
python -m pip install -e .
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
3. **Start the proxy.** Configure an upstream URL and provider first. For the local mock demo, use the URL below; for a real provider, set its API base URL instead.
|
|
101
|
+
|
|
102
|
+
```powershell
|
|
103
|
+
aegismcp proxy --upstream-base-url http://127.0.0.1:8101/v1
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The proxy listens on `http://127.0.0.1:8000`. In a second terminal, run the no-provider-key demo:
|
|
107
|
+
|
|
108
|
+
```powershell
|
|
109
|
+
python examples/chat_test.py
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The example starts a mock upstream, prints the sanitized prompt it receives, and then prints the response after local restoration. It uses only a fake key and does not call an external model.
|
|
113
|
+
|
|
114
|
+
## OpenAI-compatible client
|
|
115
|
+
|
|
116
|
+
Point an OpenAI SDK client at the local proxy. Keep the real provider credential in an environment variable; the proxy consumes `X-Upstream-Api-Key` and forwards it upstream.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
import os
|
|
120
|
+
from openai import OpenAI
|
|
121
|
+
|
|
122
|
+
client = OpenAI(
|
|
123
|
+
base_url="http://localhost:8000/v1",
|
|
124
|
+
api_key="proxy-placeholder", # Required by the SDK; proxy does not use this value.
|
|
125
|
+
default_headers={"X-Upstream-Api-Key": os.environ["MODEL_API_KEY"]},
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
result = client.chat.completions.create(
|
|
129
|
+
model="gpt-4o-mini",
|
|
130
|
+
messages=[{"role": "user", "content": "Summarize this text..."}],
|
|
131
|
+
)
|
|
132
|
+
print(result.choices[0].message.content)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The current ingress API is OpenAI-compatible `POST /v1/chat/completions`. OpenAI-compatible clients can use the proxy with OpenAI, Ollama, or the included basic Anthropic upstream adapter. The native Anthropic SDK `/v1/messages` ingress is not implemented; Anthropic upstream requests are made through AEGISMCP's OpenAI-compatible interface.
|
|
136
|
+
|
|
137
|
+
## Configuration
|
|
138
|
+
|
|
139
|
+
The proxy reads Redis and vault settings from `.env.redis` by default. Common settings can also be supplied as environment variables or CLI options:
|
|
140
|
+
|
|
141
|
+
```powershell
|
|
142
|
+
$env:AEGIS_UPSTREAM_PROVIDER = 'openai' # openai, anthropic, or ollama
|
|
143
|
+
$env:AEGIS_MODE = 'enforce' # enforce or warn
|
|
144
|
+
$env:AEGIS_UPSTREAM_BASE_URL = 'https://api.openai.com/v1'
|
|
145
|
+
aegismcp proxy
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
You can also pass `--provider`, `--mode`, `--host`, `--port`, and `--env-file` to `aegismcp proxy`. In `enforce` mode, tokenization and restoration errors fail closed. `warn` mode logs detected entity categories/counts and forwards original content unchanged; use it only with synthetic data.
|
|
149
|
+
|
|
150
|
+
## Security notes and limitations
|
|
151
|
+
|
|
152
|
+
- Regex and pattern-based detectors are experimental. They can miss sensitive values and produce false positives; names in particular are not reliably identified by regex alone.
|
|
153
|
+
- Optional Presidio detection runs locally when installed and enabled; it adds coverage but does not make detection exhaustive. The default detector remains offline and rule-based.
|
|
154
|
+
- The local Compose setup publishes Redis only on `127.0.0.1:6380` so a host-installed proxy can reach it; it still requires TLS/mTLS, ACLs, in-memory operation, and strict TTLs. Do not bind Redis to public interfaces. In production, place Redis on a private network beside the proxy. The Compose setup is a development example, not a production deployment blueprint.
|
|
155
|
+
- AEGISMCP is not a substitute for access control, secret management, or data-loss prevention. Audit detector behavior, proxy configuration, tenant identity handling, and failure modes before production use.
|
|
156
|
+
- The proxy process is inside the trusted boundary. Python cannot reliably zeroize immutable plaintext or key objects in memory.
|
|
157
|
+
- Multi-tenant deployments need authenticated tenant identity middleware. Do not derive tenant identity from prompt text or an untrusted request field.
|
|
158
|
+
|
|
159
|
+
## Tests
|
|
160
|
+
|
|
161
|
+
Run unit and mocked-upstream tests locally with the test extra:
|
|
162
|
+
|
|
163
|
+
```powershell
|
|
164
|
+
python -m pip install -e ".[test]"
|
|
165
|
+
python -m pytest -q
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
To run the real optional name/location NER test, install the PII extra and English model first. The test skips when that optional model is not installed:
|
|
169
|
+
|
|
170
|
+
```powershell
|
|
171
|
+
python -m pip install -e ".[test,pii]"
|
|
172
|
+
python -m spacy download en_core_web_sm
|
|
173
|
+
python -m pytest -q tests/test_detectors.py
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
To include the TLS Redis integration test in the Compose environment:
|
|
177
|
+
|
|
178
|
+
```powershell
|
|
179
|
+
docker compose --profile test run --rm redis-test
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Stop the local Redis service with `docker compose down` when finished.
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
AEGISMCP is released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
proxy_server.py
|
|
4
|
+
pyproject.toml
|
|
5
|
+
aegis_privacy_proxy.egg-info/PKG-INFO
|
|
6
|
+
aegis_privacy_proxy.egg-info/SOURCES.txt
|
|
7
|
+
aegis_privacy_proxy.egg-info/dependency_links.txt
|
|
8
|
+
aegis_privacy_proxy.egg-info/entry_points.txt
|
|
9
|
+
aegis_privacy_proxy.egg-info/requires.txt
|
|
10
|
+
aegis_privacy_proxy.egg-info/top_level.txt
|
|
11
|
+
aegismcp/__init__.py
|
|
12
|
+
aegismcp/cli.py
|
|
13
|
+
aegismcp/crypto.py
|
|
14
|
+
aegismcp/detectors.py
|
|
15
|
+
aegismcp/engine.py
|
|
16
|
+
aegismcp/redis_vault.py
|
|
17
|
+
aegismcp/vault.py
|
|
18
|
+
tests/test_detectors.py
|
|
19
|
+
tests/test_proxy.py
|
|
20
|
+
tests/test_redis_integration.py
|
|
21
|
+
tests/test_redis_vault.py
|
|
22
|
+
tests/test_tokenization.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Command-line entry point for AEGISMCP."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.group()
|
|
11
|
+
@click.version_option(package_name="aegis-privacy-proxy")
|
|
12
|
+
def main() -> None:
|
|
13
|
+
"""Developer-first security and privacy proxy for AI workflows."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@main.command("proxy")
|
|
17
|
+
@click.option("--host", default=lambda: os.getenv("AEGIS_PROXY_HOST", "127.0.0.1"), show_default=True)
|
|
18
|
+
@click.option("--port", type=click.IntRange(1, 65535),
|
|
19
|
+
default=lambda: int(os.getenv("AEGIS_PROXY_PORT", "8000")), show_default=True)
|
|
20
|
+
@click.option("--upstream-base-url", envvar="AEGIS_UPSTREAM_BASE_URL",
|
|
21
|
+
help="Provider URL, for example https://api.openai.com/v1.")
|
|
22
|
+
@click.option("--provider", type=click.Choice(["openai", "anthropic", "ollama"], case_sensitive=False),
|
|
23
|
+
default=lambda: os.getenv("AEGIS_UPSTREAM_PROVIDER", "openai"), show_default=True)
|
|
24
|
+
@click.option("--mode", type=click.Choice(["enforce", "warn"], case_sensitive=False),
|
|
25
|
+
default=lambda: os.getenv("AEGIS_MODE", "enforce"), show_default=True)
|
|
26
|
+
@click.option("--env-file", envvar="AEGIS_ENV_FILE", default=".env.redis", show_default=True,
|
|
27
|
+
help="Local file containing Redis and vault settings.")
|
|
28
|
+
@click.option("--reload", is_flag=True, help="Enable Uvicorn auto-reload for local development.")
|
|
29
|
+
def proxy(host: str, port: int, upstream_base_url: str | None, provider: str,
|
|
30
|
+
mode: str, env_file: str, reload: bool) -> None:
|
|
31
|
+
"""Start the local OpenAI-compatible proxy server."""
|
|
32
|
+
if upstream_base_url:
|
|
33
|
+
os.environ["AEGIS_UPSTREAM_BASE_URL"] = upstream_base_url
|
|
34
|
+
os.environ["AEGIS_UPSTREAM_PROVIDER"] = provider.lower()
|
|
35
|
+
os.environ["AEGIS_MODE"] = mode.lower()
|
|
36
|
+
os.environ["AEGIS_ENV_FILE"] = env_file
|
|
37
|
+
|
|
38
|
+
if not os.getenv("AEGIS_UPSTREAM_BASE_URL"):
|
|
39
|
+
raise click.UsageError("set --upstream-base-url or AEGIS_UPSTREAM_BASE_URL")
|
|
40
|
+
|
|
41
|
+
import uvicorn
|
|
42
|
+
|
|
43
|
+
click.echo(f"Starting AEGISMCP proxy on http://{host}:{port} ({mode} mode, {provider} upstream)")
|
|
44
|
+
uvicorn.run("proxy_server:app", host=host, port=port, reload=reload)
|