code-airlock 0.1.0__tar.gz → 1.0.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.
Files changed (25) hide show
  1. code_airlock-1.0.0/LICENSE +21 -0
  2. {code_airlock-0.1.0/code_airlock.egg-info → code_airlock-1.0.0}/PKG-INFO +308 -208
  3. code_airlock-0.1.0/PKG-INFO → code_airlock-1.0.0/README.md +269 -208
  4. code_airlock-1.0.0/pyproject.toml +56 -0
  5. {code_airlock-0.1.0 → code_airlock-1.0.0}/setup.cfg +4 -4
  6. code_airlock-1.0.0/src/code_airlock/__init__.py +7 -0
  7. code_airlock-1.0.0/src/code_airlock/__main__.py +6 -0
  8. {code_airlock-0.1.0 → code_airlock-1.0.0/src/code_airlock}/engine.py +199 -183
  9. {code_airlock-0.1.0 → code_airlock-1.0.0/src/code_airlock}/mcp_server.py +2 -2
  10. {code_airlock-0.1.0 → code_airlock-1.0.0/src/code_airlock}/proxy.py +13 -3
  11. code_airlock-1.0.0/src/code_airlock.egg-info/PKG-INFO +308 -0
  12. code_airlock-1.0.0/src/code_airlock.egg-info/SOURCES.txt +17 -0
  13. code_airlock-1.0.0/src/code_airlock.egg-info/entry_points.txt +4 -0
  14. {code_airlock-0.1.0 → code_airlock-1.0.0/src}/code_airlock.egg-info/requires.txt +8 -0
  15. code_airlock-1.0.0/src/code_airlock.egg-info/top_level.txt +1 -0
  16. code_airlock-1.0.0/tests/test_mcp.py +66 -0
  17. code_airlock-1.0.0/tests/test_proxy.py +84 -0
  18. code_airlock-0.1.0/README.md +0 -192
  19. code_airlock-0.1.0/benchmark.py +0 -132
  20. code_airlock-0.1.0/code_airlock.egg-info/SOURCES.txt +0 -13
  21. code_airlock-0.1.0/code_airlock.egg-info/entry_points.txt +0 -2
  22. code_airlock-0.1.0/code_airlock.egg-info/top_level.txt +0 -5
  23. code_airlock-0.1.0/pyproject.toml +0 -27
  24. {code_airlock-0.1.0 → code_airlock-1.0.0/src/code_airlock}/sanitizer.py +0 -0
  25. {code_airlock-0.1.0 → code_airlock-1.0.0/src}/code_airlock.egg-info/dependency_links.txt +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sarthak Maurya
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.
@@ -1,208 +1,308 @@
1
- Metadata-Version: 2.4
2
- Name: code-airlock
3
- Version: 0.1.0
4
- Summary: Low-latency OpenAI-compatible PII Redaction & Rehydration Gateway and FastMCP Server
5
- Author: code-airlock team
6
- Requires-Python: >=3.10
7
- Description-Content-Type: text/markdown
8
- Requires-Dist: gliner>=0.2.13
9
- Requires-Dist: torch>=2.0.0
10
- Requires-Dist: numpy>=1.24.0
11
- Requires-Dist: mcp<2,>=1.0
12
- Requires-Dist: fastapi>=0.110
13
- Requires-Dist: uvicorn>=0.27
14
- Requires-Dist: httpx>=0.27
15
- Requires-Dist: pytest>=8.0
16
-
17
- # 🛡️ Code-Airlock
18
-
19
- **Low-Latency AI Privacy, Secret/PII Redaction & Streaming Rehydration Gateway (`OpenAI Proxy` + `FastMCP Server`)**
20
-
21
- `code-airlock` is a zero-trust privacy layer for LLMs and agentic coding harnesses. It intercepts sensitive credentials, financial identifiers, and personal data before they leave your machine, replaces them with deterministic session tokens (`<API_KEY_1>`, `<PERSON_1>`), and seamlessly rehydrates them back into real-time Server-Sent Events (SSE) token streams or local file writes.
22
-
23
- * **Dual Deployment Modes:** Run as a drop-in **OpenAI-compatible `/v1/chat/completions` reverse proxy** or as a **Model Context Protocol (MCP) server** (`stdio`) for OpenCode, Cursor, and Claude Code.
24
- * **2-Stage Hybrid Cascade:** Combines sub-millisecond deterministic regex + mathematical checksums (**Luhn, Verhoeff $D_5$, ISO 7064 MOD-97**) with contextual neural NER (`urchade/gliner_small-v2.1`) and a 93-term developer allowlist.
25
- * **Zero-Delay Streaming Rehydration:** Stateful sliding-window SSE parser reassembles split tokens across arbitrary 2-byte network chunks without delaying code comparison or bitwise operators (`<`, `<<`, `template <typename T>`).
26
- * **Minimalist Systems Footprint:** ~770 lines of flat, auditable Python across 7 files (`engine.py`, `sanitizer.py`, `proxy.py`, `mcp_server.py`, `benchmark.py`, and test suites).
27
-
28
- ---
29
-
30
- ## 🏗️ System Architecture
31
-
32
- ```mermaid
33
- flowchart TB
34
- classDef client fill:#1e293b,stroke:#64748b,stroke-width:2px,color:#f8fafc
35
- classDef stage1 fill:#064e3b,stroke:#10b981,stroke-width:2px,color:#ecfdf5
36
- classDef stage2 fill:#1e3a8a,stroke:#3b82f6,stroke-width:2px,color:#eff6ff
37
- classDef merger fill:#312e81,stroke:#8b5cf6,stroke-width:2px,color:#f5f3ff
38
- classDef vault fill:#7c2d12,stroke:#f97316,stroke-width:2px,color:#fff7ed
39
- classDef stream fill:#4c1d95,stroke:#a855f7,stroke-width:2px,color:#faf5ff
40
-
41
- Client(["🖥️ Client SDK / Agent Harness<br/>(OpenAI SDK, OpenCode, Cursor, Claude Code)"]):::client
42
-
43
- subgraph Airlock["🛡️ CODE-AIRLOCK (proxy.py / mcp_server.py)"]
44
- direction TB
45
- subgraph Cascade["engine.py — 2-Stage Hybrid Cascade"]
46
- S1["⚡ Stage 1: Deterministic Fast-Pass (~0.44ms)<br/>• Regex: API_KEY, AUTH_TOKEN, EMAIL, PHONE, IPv4<br/>• Checksums: Luhn (Card), Verhoeff (ID), MOD-97 (IBAN)"]:::stage1
47
- S2["🧠 Stage 2: Guarded Neural NER (GLiNER-small)<br/>• Entities: PERSON, ORGANIZATION, LOCATION<br/>• Guards: 93-term TECH_ALLOWLIST + Code/Pronoun Filter"]:::stage2
48
- Merger{"⚖️ Span Conflict Resolver<br/>Stage 1 Overrides Stage 2<br/>Longest Span Wins"}:::merger
49
- S1 & S2 --> Merger
50
- end
51
-
52
- Vault[("🗄️ Ephemeral Session Vault<br/>sanitizer.py (VaultSession)<br/>Right-to-Left Tagging")]:::vault
53
- Rehydrator["🪟 StreamRehydrator<br/>Stateful Sliding-Window SSE & File Parser"]:::stream
54
-
55
- Merger --> Vault
56
- Vault -.->|"O(1) Token Lookup"| Rehydrator
57
- end
58
-
59
- LLM(["☁️ Upstream LLM Provider<br/>*Sees Only &lt;ENTITY_n&gt; Tokens*"]):::client
60
-
61
- Client -->|"1. Raw Prompt / File Read"| Cascade
62
- Vault -->|"2. Sanitized Payload"| LLM
63
- LLM -->|"3. Fragmented SSE Stream / Tool Patch"| Rehydrator
64
- Rehydrator -->|"4. Restored Plaintext"| Client
65
- ```
66
-
67
- ---
68
-
69
- ## 📊 Gold-Set Benchmark (`gold_set.jsonl`)
70
-
71
- Evaluated on **285 developer prompts** (sampled from `CodeAlpaca_20K` and `OpenCodeInstruct` with injected `.env` blocks, ticket escalations, billing metadata, and C++ template syntax) totaling **744 ground-truth PII spans** across 11 categories:
72
-
73
- | Metric / Entity Category | Strict (P / R / F1) | Partial (P / R / F1) | Latency / Verification |
74
- | :--- | :---: | :---: | :--- |
75
- | **Overall Benchmark (744 Spans)** | **96.5% / 99.1% / 97.7%** | **97.0% / 99.6% / 98.3%** | **285 / 285 SSE Round-Trip Pass** |
76
- | **Stage 1 Latency (Deterministic)** | — | — | **0.44 ms (p50)** / 0.78 ms (p95) |
77
- | **Total Cascade Latency (CPU/GPU)** | — | — | **14.6–42.5 ms (p50)** |
78
- | `API_KEY` *(OpenAI, AWS, GitHub, Slack, Anthropic)* | 100 / 100 / **100%** | 100 / 100 / **100%** | Prefix + length/charset bounds |
79
- | `AUTH_TOKEN` *(JWT, Bearer, PEM Private Keys)* | 100 / 100 / **100%** | 100 / 100 / **100%** | 3-part Base64URL + PEM headers |
80
- | `CREDIT_CARD` *(13–19 digits)* | 100 / 100 / **100%** | 100 / 100 / **100%** | Pure-Python **Luhn Checksum** |
81
- | `GOVT_ID` *(SSN, PAN, 12-Digit National ID)* | 100 / 100 / **100%** | 100 / 100 / **100%** | **Verhoeff $D_5$ Checksum** |
82
- | `IBAN_CRYPTO` *(IBAN, ETH `0x...`)* | 100 / 100 / **100%** | 100 / 100 / **100%** | **ISO 7064 MOD-97** Checksum |
83
- | `EMAIL` & `PHONE` | 100 / 100 / **100%** | 100 / 100 / **100%** | Negative lookbehind for order IDs |
84
- | `IP_ADDRESS` *(IPv4)* | 94 / 100 / **97%** | 94 / 100 / **97%** | Octet range `0..255` (rejects `.300`) |
85
- | `PERSON` | 99 / 99 / **99%** | 99 / 99 / **99%** | Pronoun + code-identifier stopword guard |
86
- | `ORGANIZATION` | 89 / 95 / **92%** | 91 / 97 / **94%** | Filtered via 93-term `TECH_ALLOWLIST` |
87
- | `LOCATION` | 88 / 98 / **93%** | 90 / 100 / **95%** | Adjacent comma-span coalescing |
88
-
89
- * **Hard-Negative Suite:** **61/61 Passed** (100% rejection of non-Luhn 16-digit order IDs, Verhoeff-invalid 12-digit numbers, MOD-97-invalid IBANs, and `v192.168.1.300` version strings).
90
- * **Tech Allowlist Check:** **30/30 Passed** (`FastAPI`, `Docker`, `Kubernetes`, `Redis`, `Postgres`, `AWS`, `Heroku`, etc. produce zero false positives).
91
-
92
- ---
93
-
94
- ## 🚀 Quickstart & MCP Setup
95
-
96
- ### Option 1: Zero-Install via `uvx` (Recommended)
97
-
98
- No cloning, manual virtual environments, or path debugging. Anyone with Astral's [`uv`](https://github.com/astral-sh/uv) can run `code-airlock` directly from GitHub (or PyPI once published):
99
-
100
- #### 🤖 Claude Code (CLI)
101
- ```bash
102
- claude mcp add code-airlock -- uvx --from git+https://github.com/sarthexe/code-airlock code-airlock
103
- ```
104
-
105
- #### 💻 OpenCode (`opencode.json`)
106
- ```json
107
- {
108
- "$schema": "https://opencode.ai/config.json",
109
- "mcp": {
110
- "code-airlock": {
111
- "type": "local",
112
- "command": ["uvx", "--from", "git+https://github.com/sarthexe/code-airlock", "code-airlock"],
113
- "enabled": true
114
- }
115
- }
116
- }
117
- ```
118
-
119
- #### 🖱️ Cursor (`.cursor/mcp.json`)
120
- ```json
121
- {
122
- "mcpServers": {
123
- "code-airlock": {
124
- "command": "uvx",
125
- "args": ["--from", "git+https://github.com/sarthexe/code-airlock", "code-airlock"]
126
- }
127
- }
128
- }
129
- ```
130
-
131
- #### 🖥️ Claude Desktop (`claude_desktop_config.json`) & Windsurf (`~/.codeium/windsurf/mcp_config.json`)
132
- ```json
133
- {
134
- "mcpServers": {
135
- "code-airlock": {
136
- "command": "uvx",
137
- "args": ["--from", "git+https://github.com/sarthexe/code-airlock", "code-airlock"]
138
- }
139
- }
140
- }
141
- ```
142
-
143
- *(Once published to PyPI, the args simplify to just `["uvx", "code-airlock"]`)*.
144
-
145
- ---
146
-
147
- ### Option 2: Local Development / Manual Git Clone
148
-
149
- ```bash
150
- git clone https://github.com/sarthexe/code-airlock.git
151
- cd code-airlock
152
- pip install -r requirements.txt
153
- pip install -e .
154
-
155
- # Test tools locally over stdio
156
- python mcp_server.py
157
- ```
158
-
159
- ---
160
-
161
- ### Option 3: OpenAI-Compatible Reverse Proxy (`/v1/chat/completions`)
162
-
163
- Run as a transparent privacy gateway intercepting HTTP requests:
164
-
165
- ```bash
166
- # Run with built-in zero-leak mock upstream (offline validation)
167
- uvicorn proxy:app --port 8000
168
-
169
- # Or point to a live upstream provider (OpenAI, Ollama, OpenRouter, vLLM)
170
- export AIRLOCK_UPSTREAM_URL="https://api.openai.com"
171
- uvicorn proxy:app --port 8000
172
- ```
173
-
174
- ---
175
-
176
- ## 🧠 Guiding Your Agent (`.cursorrules` / System Prompt)
177
-
178
- To ensure your coding agent actually leverages the airlock tools instead of raw file reads, include this rule in your `.cursorrules`, `CLAUDE.md`, or system instructions:
179
-
180
- ```markdown
181
- # Code-Airlock Agent Guardrails
182
- 1. When reading `.env`, configuration, or log files, NEVER use standard read tools. ALWAYS call `airlock_read_file(path)` so secrets and PII are redacted into `<ENTITY_n>` tokens before hitting context.
183
- 2. When creating or editing configs, write the `<ENTITY_n>` tokens directly and call `airlock_write_file(path, content)`. The airlock will rehydrate the real secrets locally on disk without ever sending them through the LLM.
184
- 3. Call `airlock_vault_status()` to inspect active pseudonymized tokens safely (never returns plaintext values).
185
- ```
186
-
187
- ---
188
-
189
- ## 📦 PyPI Publishing (Trusted Publishing via GitHub Actions)
190
-
191
- This repository includes a turnkey GitHub Actions workflow (`.github/workflows/publish.yml`) configured for **PyPI Trusted Publishing (OIDC)**:
192
- 1. Create a project named `code-airlock` on [pypi.org](https://pypi.org/manage/account/publishing/).
193
- 2. Add a **Trusted Publisher** pointing to `sarthexe/code-airlock` and workflow `publish.yml`.
194
- 3. Create a GitHub Release on this repository — the workflow will build the wheel and publish automatically with zero API tokens or manual steps.
195
-
196
- ---
197
-
198
- ## 📁 Repository Structure
199
-
200
- | File | Lines | Responsibility |
201
- | :--- | :---: | :--- |
202
- | `engine.py` | 183 | Stage 1 regex/checksum validators + Stage 2 GLiNER-small + `TECH_ALLOWLIST` + span merger |
203
- | `sanitizer.py` | 93 | Session-consistent `VaultSession` dehydrator + stateful `StreamRehydrator` SSE parser |
204
- | `proxy.py` | 143 | FastAPI `/v1/chat/completions` gateway with SSE streaming rehydration & telemetry headers |
205
- | `mcp_server.py` | 71 | FastMCP `stdio` server exposing 5 zero-leak text and file tools for agentic harnesses |
206
- | `benchmark.py` | 132 | Strict/Partial overlap evaluator, p50/p95 latency timer, and hard-negative verifier |
207
- | `test_proxy.py` | 85 | End-to-end proxy tests (11-entity zero-leak check, 2-char SSE split rehydration, C++ syntax) |
208
- | `test_mcp.py` | 66 | MCP tool verification (`.env` $\rightarrow$ `config.json` zero-leak file migration & vault safety) |
1
+ Metadata-Version: 2.4
2
+ Name: code-airlock
3
+ Version: 1.0.0
4
+ Summary: Low-latency OpenAI-compatible PII redaction gateway and FastMCP server for coding agents
5
+ Author: Sarthak Maurya
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/sarthexe/code-airlock
8
+ Project-URL: Repository, https://github.com/sarthexe/code-airlock
9
+ Project-URL: Issues, https://github.com/sarthexe/code-airlock/issues
10
+ Project-URL: Dataset, https://huggingface.co/datasets/sarthax/pii-airlock-bench
11
+ Keywords: pii,privacy,secrets,dlp,mcp,llm,security
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Security
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: gliner>=0.2.13
25
+ Requires-Dist: torch>=2.0.0
26
+ Requires-Dist: numpy>=1.24.0
27
+ Requires-Dist: mcp<2,>=1.0
28
+ Requires-Dist: fastapi>=0.110
29
+ Requires-Dist: uvicorn>=0.27
30
+ Requires-Dist: httpx>=0.27
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0; extra == "dev"
33
+ Requires-Dist: build>=1.2; extra == "dev"
34
+ Requires-Dist: twine>=5.0; extra == "dev"
35
+ Provides-Extra: benchmark
36
+ Requires-Dist: datasets>=2.18; extra == "benchmark"
37
+ Requires-Dist: huggingface_hub>=0.23; extra == "benchmark"
38
+ Dynamic: license-file
39
+
40
+ # 🛡️ Code-Airlock
41
+
42
+ **Low-Latency AI Privacy, Secret/PII Redaction & Streaming Rehydration Gateway (`OpenAI Proxy` + `FastMCP Server`)**
43
+
44
+ `code-airlock` is a zero-trust privacy layer for LLMs and agentic coding harnesses. It intercepts sensitive credentials, financial identifiers, and personal data before they leave your machine, replaces them with deterministic session tokens (`<API_KEY_1>`, `<PERSON_1>`), and seamlessly rehydrates them back into real-time Server-Sent Events (SSE) token streams or local file writes.
45
+
46
+ * **Dual Deployment Modes:** Run as a drop-in **OpenAI-compatible `/v1/chat/completions` reverse proxy** or as a **Model Context Protocol (MCP) server** (`stdio`) for OpenCode, Cursor, and Claude Code.
47
+ * **2-Stage Hybrid Cascade:** Combines sub-millisecond deterministic regex + mathematical checksums (**Luhn, Verhoeff $D_5$, ISO 7064 MOD-97**) with contextual neural NER (`urchade/gliner_small-v2.1`) and a curated developer allowlist.
48
+ * **Zero-Delay Streaming Rehydration:** Stateful sliding-window SSE parser reassembles split tokens across arbitrary 2-byte network chunks without delaying code comparison or bitwise operators (`<`, `<<`, `template <typename T>`).
49
+ * **Minimalist Systems Footprint:** ~500 lines of core runtime code (`src/code_airlock/engine.py`, `sanitizer.py`, `proxy.py`, `mcp_server.py`) plus a deterministic 2,000-row benchmark harness.
50
+
51
+ ---
52
+
53
+ ## 🏗️ System Architecture
54
+
55
+ ```mermaid
56
+ flowchart TB
57
+ classDef client fill:#1e293b,stroke:#64748b,stroke-width:2px,color:#f8fafc
58
+ classDef stage1 fill:#064e3b,stroke:#10b981,stroke-width:2px,color:#ecfdf5
59
+ classDef stage2 fill:#1e3a8a,stroke:#3b82f6,stroke-width:2px,color:#eff6ff
60
+ classDef merger fill:#312e81,stroke:#8b5cf6,stroke-width:2px,color:#f5f3ff
61
+ classDef vault fill:#7c2d12,stroke:#f97316,stroke-width:2px,color:#fff7ed
62
+ classDef stream fill:#4c1d95,stroke:#a855f7,stroke-width:2px,color:#faf5ff
63
+
64
+ Client(["🖥️ Client SDK / Agent Harness<br/>(OpenAI SDK, OpenCode, Cursor, Claude Code)"]):::client
65
+
66
+ subgraph Airlock["🛡️ CODE-AIRLOCK (proxy.py / mcp_server.py)"]
67
+ direction TB
68
+ subgraph Cascade["engine.py — 2-Stage Hybrid Cascade"]
69
+ S1["⚡ Stage 1: Deterministic Fast-Pass (~0.44ms)<br/>• Regex: API_KEY, AUTH_TOKEN, EMAIL, PHONE, IPv4<br/>• Checksums: Luhn (Card), Verhoeff (ID), MOD-97 (IBAN)"]:::stage1
70
+ S2["🧠 Stage 2: Guarded Neural NER (GLiNER-small)<br/>• Entities: PERSON, ORGANIZATION, LOCATION<br/>• Guards: 93-term TECH_ALLOWLIST + Code/Pronoun Filter"]:::stage2
71
+ Merger{"⚖️ Span Conflict Resolver<br/>Stage 1 Overrides Stage 2<br/>Longest Span Wins"}:::merger
72
+ S1 & S2 --> Merger
73
+ end
74
+
75
+ Vault[("🗄️ Ephemeral Session Vault<br/>sanitizer.py (VaultSession)<br/>Right-to-Left Tagging")]:::vault
76
+ Rehydrator["🪟 StreamRehydrator<br/>Stateful Sliding-Window SSE & File Parser"]:::stream
77
+
78
+ Merger --> Vault
79
+ Vault -.->|"O(1) Token Lookup"| Rehydrator
80
+ end
81
+
82
+ LLM(["☁️ Upstream LLM Provider<br/>*Sees Only &lt;ENTITY_n&gt; Tokens*"]):::client
83
+
84
+ Client -->|"1. Raw Prompt / File Read"| Cascade
85
+ Vault -->|"2. Sanitized Payload"| LLM
86
+ LLM -->|"3. Fragmented SSE Stream / Tool Patch"| Rehydrator
87
+ Rehydrator -->|"4. Restored Plaintext"| Client
88
+ ```
89
+
90
+ ---
91
+
92
+ ## 📊 Gold-Set Benchmark (`benchmarks/gold_set.jsonl`)
93
+
94
+ Evaluated on **285 developer prompts** (sampled from `CodeAlpaca_20K` and `OpenCodeInstruct` with injected `.env` blocks, ticket escalations, billing metadata, and C++ template syntax) totaling **744 ground-truth PII spans** across 11 categories:
95
+
96
+ | Metric / Entity Category | Strict (P / R / F1) | Partial (P / R / F1) | Latency / Verification |
97
+ | :--- | :---: | :---: | :--- |
98
+ | **Overall Benchmark (744 Spans)** | **96.5% / 99.1% / 97.7%** | **97.0% / 99.6% / 98.3%** | **285 / 285 SSE Round-Trip Pass** |
99
+ | **Stage 1 Latency (Deterministic)** | — | — | **0.44 ms (p50)** / 0.78 ms (p95) |
100
+ | **Total Cascade Latency (CPU/GPU)** | — | — | **14.6–42.5 ms (p50)** |
101
+ | `API_KEY` *(OpenAI, AWS, GitHub, Slack, Anthropic)* | 100 / 100 / **100%** | 100 / 100 / **100%** | Prefix + length/charset bounds |
102
+ | `AUTH_TOKEN` *(JWT, Bearer, PEM Private Keys)* | 100 / 100 / **100%** | 100 / 100 / **100%** | 3-part Base64URL + PEM headers |
103
+ | `CREDIT_CARD` *(13–19 digits)* | 100 / 100 / **100%** | 100 / 100 / **100%** | Pure-Python **Luhn Checksum** |
104
+ | `GOVT_ID` *(SSN, PAN, 12-Digit National ID)* | 100 / 100 / **100%** | 100 / 100 / **100%** | **Verhoeff $D_5$ Checksum** |
105
+ | `IBAN_CRYPTO` *(IBAN, ETH `0x...`)* | 100 / 100 / **100%** | 100 / 100 / **100%** | **ISO 7064 MOD-97** Checksum |
106
+ | `EMAIL` & `PHONE` | 100 / 100 / **100%** | 100 / 100 / **100%** | Negative lookbehind for order IDs |
107
+ | `IP_ADDRESS` *(IPv4)* | 94 / 100 / **97%** | 94 / 100 / **97%** | Octet range `0..255` (rejects `.300`) |
108
+ | `PERSON` | 99 / 99 / **99%** | 99 / 99 / **99%** | Pronoun + code-identifier stopword guard |
109
+ | `ORGANIZATION` | 89 / 95 / **92%** | 91 / 97 / **94%** | Filtered via 93-term `TECH_ALLOWLIST` |
110
+ | `LOCATION` | 88 / 98 / **93%** | 90 / 100 / **95%** | Adjacent comma-span coalescing |
111
+
112
+ * **Hard-Negative Suite:** **61/61 Passed** (100% rejection of non-Luhn 16-digit order IDs, Verhoeff-invalid 12-digit numbers, MOD-97-invalid IBANs, and `v192.168.1.300` version strings).
113
+ * **Tech Allowlist Check:** **30/30 Passed** (`FastAPI`, `Docker`, `Kubernetes`, `Redis`, `Postgres`, `AWS`, `Heroku`, etc. produce zero false positives).
114
+
115
+ ---
116
+
117
+ ## 🧪 Unified 2,000-Row Benchmark Matrix
118
+
119
+ `benchmarks/build_benchmarks.py` deterministically generates four stratified splits into the git-ignored `benchmarks/` directory (`seed=42`). `benchmarks/benchmark.py` evaluates them and writes [`benchmarks/BENCHMARK_RESULTS.md`](benchmarks/BENCHMARK_RESULTS.md).
120
+
121
+ | Split | Rows | Positive | Clean / Hard-neg | Ground-truth spans |
122
+ | :--- | ---: | ---: | ---: | ---: |
123
+ | `dev_prompts` | 1,000 | 600 | 300 / 100 | 2,400 |
124
+ | `git_leaks` | 500 | 350 | 0 / 150 | 1,400 |
125
+ | `mcp_configs` | 250 | 200 | 50 / 0 | 800 |
126
+ | `adversarial_sse` | 250 | 250 | 0 / 0 | 1,217 |
127
+ | **Total** | **2,000** | **1,400** | **350 / 250** | **5,817** |
128
+
129
+ Reference result (strict exact-span matching, `code-airlock` v0.1.0):
130
+
131
+ | Split | Strict P / R / F1 | Hard-neg | Clean 0-FP | SSE 1/2/7-byte |
132
+ | :--- | :---: | :---: | :---: | :---: |
133
+ | `dev_prompts` | 100% / 100% / 100% | 100/100 | 300/300 | 1000/1000 |
134
+ | `git_leaks` | 100% / 100% / 100% | 150/150 | — | 500/500 |
135
+ | `mcp_configs` | 100% / 100% / 100% | — | 50/50 | 250/250 |
136
+ | `adversarial_sse` | 100% / 100% / 100% | — | — | 250/250 |
137
+ | **Combined** | **100% / 100% / 100%** | **250/250** | **350/350** | **2000/2000** |
138
+
139
+ - Latency: **0.194 ms** p50 / 0.355 ms p95 Stage 1; **30.349 ms** p50 / 39.391 ms p95 Stage 2; **30.391 ms** p50 / 39.554 ms p95 total cascade.
140
+ - Per-entity support: `API_KEY` 756, `AUTH_TOKEN` 467, `CREDIT_CARD` 440, `EMAIL` 754, `PHONE` 465, `IP_ADDRESS` 442, `GOVT_ID` 465, `IBAN_CRYPTO` 465, `PERSON` 729, `ORGANIZATION` 417, `LOCATION` 417. Every entity is at **100% P/R/F1**.
141
+ - Invariants: MCP JSON parse **100/100**, JSON round-trip **100/100**, adversarial SSE **2,000/2,000**, hard negatives **250/250**, clean rows **350/350 with zero false positives**.
142
+
143
+ These are **synthetic, template-composed fixtures**, so the perfect headline is a regression/invariant result, not a claim of real-world accuracy. The older real-world suites (`benchmarks/gold_set.jsonl`: 96.7/99.1/97.9; Gitleaks artifacts: 100/88.5/93.9) remain the honest field tests.
144
+
145
+ ### 🤗 Published Dataset
146
+
147
+ One command publishes all four splits and the auto-generated card:
148
+
149
+ ```bash
150
+ python benchmarks/export_hf.py --repo-id sarthexe/pii-airlock-bench
151
+ ```
152
+
153
+ Dataset: [**sarthax/pii-airlock-bench**](https://huggingface.co/datasets/sarthax/pii-airlock-bench) (the token owner namespace is resolved automatically).
154
+
155
+ ```python
156
+ from datasets import load_dataset
157
+ ds = load_dataset("sarthax/pii-airlock-bench")
158
+ ```
159
+
160
+ ---
161
+
162
+ ## 🚀 Quickstart & MCP Setup
163
+
164
+ ### Option 1: Zero-Install via `uvx` (Recommended)
165
+
166
+ No cloning, manual virtual environments, or path debugging. Anyone with Astral's [`uv`](https://github.com/astral-sh/uv) can run `code-airlock` directly from PyPI:
167
+
168
+ #### 🤖 Claude Code (CLI)
169
+ ```bash
170
+ claude mcp add code-airlock -- uvx code-airlock
171
+ ```
172
+
173
+ #### 💻 OpenCode (`opencode.json`)
174
+ ```json
175
+ {
176
+ "$schema": "https://opencode.ai/config.json",
177
+ "mcp": {
178
+ "code-airlock": {
179
+ "type": "local",
180
+ "command": ["uvx", "code-airlock"],
181
+ "enabled": true
182
+ }
183
+ }
184
+ }
185
+ ```
186
+
187
+ #### 🖱️ Cursor (`.cursor/mcp.json`)
188
+ ```json
189
+ {
190
+ "mcpServers": {
191
+ "code-airlock": {
192
+ "command": "uvx",
193
+ "args": ["code-airlock"]
194
+ }
195
+ }
196
+ }
197
+ ```
198
+
199
+ #### 🖥️ Claude Desktop (`claude_desktop_config.json`) & Windsurf (`~/.codeium/windsurf/mcp_config.json`)
200
+ ```json
201
+ {
202
+ "mcpServers": {
203
+ "code-airlock": {
204
+ "command": "uvx",
205
+ "args": ["code-airlock"]
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ *(You can also run directly from source via `uvx --from git+https://github.com/sarthexe/code-airlock code-airlock`)*.
212
+
213
+ For a local editable checkout, use the package entrypoint instead of an
214
+ absolute path:
215
+
216
+ ```json
217
+ {
218
+ "mcpServers": {
219
+ "code-airlock": {
220
+ "command": "python",
221
+ "args": ["-m", "code_airlock.mcp_server"]
222
+ }
223
+ }
224
+ }
225
+ ```
226
+
227
+ `python -m code_airlock` starts the same MCP server.
228
+
229
+ ---
230
+
231
+ ### Option 2: Local Development / Manual Git Clone
232
+
233
+ ```bash
234
+ git clone https://github.com/sarthexe/code-airlock.git
235
+ cd code-airlock
236
+ pip install -e ".[dev,benchmark]"
237
+
238
+ # Test tools locally over stdio
239
+ python -m code_airlock
240
+
241
+ # Or run the explicit MCP entrypoint
242
+ code-airlock-mcp
243
+ ```
244
+
245
+ ---
246
+
247
+ ### Option 3: OpenAI-Compatible Reverse Proxy (`/v1/chat/completions`)
248
+
249
+ Run as a transparent privacy gateway intercepting HTTP requests:
250
+
251
+ ```bash
252
+ # Run with built-in zero-leak mock upstream (offline validation)
253
+ code-airlock-proxy
254
+
255
+ # Or point to a live upstream provider (OpenAI, Ollama, OpenRouter, vLLM)
256
+ export AIRLOCK_UPSTREAM_URL="https://api.openai.com"
257
+ code-airlock-proxy
258
+ ```
259
+
260
+ The proxy binds to `127.0.0.1:8000` by default. Override with
261
+ `AIRLOCK_HOST` / `AIRLOCK_PORT`.
262
+
263
+ ---
264
+
265
+ ## 🧠 Guiding Your Agent (`.cursorrules` / System Prompt)
266
+
267
+ To ensure your coding agent actually leverages the airlock tools instead of raw file reads, include this rule in your `.cursorrules`, `CLAUDE.md`, or system instructions:
268
+
269
+ ```markdown
270
+ # Code-Airlock Agent Guardrails
271
+ 1. When reading `.env`, configuration, or log files, NEVER use standard read tools. ALWAYS call `airlock_read_file(path)` so secrets and PII are redacted into `<ENTITY_n>` tokens before hitting context.
272
+ 2. When creating or editing configs, write the `<ENTITY_n>` tokens directly and call `airlock_write_file(path, content)`. The airlock will rehydrate the real secrets locally on disk without ever sending them through the LLM.
273
+ 3. Call `airlock_vault_status()` to inspect active pseudonymized tokens safely (never returns plaintext values).
274
+ ```
275
+
276
+ ## 📁 Repository Structure
277
+
278
+ | File | Lines | Responsibility |
279
+ | :--- | :---: | :--- |
280
+ | `src/code_airlock/engine.py` | 199 | Stage 1 regex/checksum validators (incl. 20+ developer key formats) + Stage 2 GLiNER-small + `TECH_ALLOWLIST` + span merger |
281
+ | `src/code_airlock/sanitizer.py` | 93 | Session-consistent `VaultSession` dehydrator + stateful `StreamRehydrator` SSE parser |
282
+ | `src/code_airlock/proxy.py` | 153 | FastAPI `/v1/chat/completions` gateway, SSE rehydration, telemetry headers, `main()` |
283
+ | `src/code_airlock/mcp_server.py` | 71 | FastMCP `stdio` server exposing 5 zero-leak text and file tools |
284
+ | `src/code_airlock/__init__.py` | 7 | Public API: `CascadeEngine`, `VaultSession`, `StreamRehydrator`, `__version__` |
285
+ | `src/code_airlock/__main__.py` | 6 | `python -m code_airlock` → MCP server |
286
+ | `tests/test_proxy.py` | 84 | End-to-end proxy tests (11-entity zero-leak check, 2-char SSE split, C++ syntax) |
287
+ | `tests/test_mcp.py` | 66 | MCP tool verification (`.env` → `config.json` zero-leak migration) |
288
+ | `benchmarks/benchmark.py` | 162 | Unified 4-suite evaluator → `benchmarks/BENCHMARK_RESULTS.md` |
289
+ | `benchmarks/build_benchmarks.py` | 239 | Deterministic 2,000-row generator (`seed=42`) |
290
+ | `benchmarks/export_hf.py` | 88 | Publishes all 4 splits plus the auto-generated dataset card |
291
+ | `benchmarks/BENCHMARK_RESULTS.md` | — | Generated metrics-only scorecard |
292
+ | `benchmarks/gold_set.jsonl` | — | 285-row real-world regression corpus |
293
+ | `benchmarks/*.jsonl` | — | Generated 4-split fixtures (git-ignored) |
294
+ | `pyproject.toml` | — | Package metadata, src discovery, entrypoints, extras, pytest config |
295
+ | `LICENSE` / `SECURITY.md` | — | MIT license and disclosure policy |
296
+ | `.github/workflows/` | — | CI test workflow + PyPI Trusted Publishing |
297
+
298
+ ---
299
+
300
+ ## 🔐 Security
301
+
302
+ Detection is best-effort and local-only. It reduces exposure but is not a
303
+ guarantee that every secret is removed. See [SECURITY.md](SECURITY.md) for the
304
+ threat model, known gaps, and private disclosure instructions.
305
+
306
+ ## 📜 License
307
+
308
+ MIT © 2026 Sarthak Maurya. See [LICENSE](LICENSE).