safeclaw-guard 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.
- safeclaw_guard-0.1.0/.claude/settings.local.json +20 -0
- safeclaw_guard-0.1.0/.gitignore +9 -0
- safeclaw_guard-0.1.0/PKG-INFO +263 -0
- safeclaw_guard-0.1.0/README.md +232 -0
- safeclaw_guard-0.1.0/default.config.yaml +69 -0
- safeclaw_guard-0.1.0/demo.py +62 -0
- safeclaw_guard-0.1.0/pyproject.toml +60 -0
- safeclaw_guard-0.1.0/src/safeclaw/__init__.py +27 -0
- safeclaw_guard-0.1.0/src/safeclaw/__main__.py +5 -0
- safeclaw_guard-0.1.0/src/safeclaw/cli.py +265 -0
- safeclaw_guard-0.1.0/src/safeclaw/config.py +90 -0
- safeclaw_guard-0.1.0/src/safeclaw/hook.py +107 -0
- safeclaw_guard-0.1.0/src/safeclaw/mcp_server.py +79 -0
- safeclaw_guard-0.1.0/src/safeclaw/models.py +110 -0
- safeclaw_guard-0.1.0/src/safeclaw/patterns/__init__.py +16 -0
- safeclaw_guard-0.1.0/src/safeclaw/patterns/base.py +61 -0
- safeclaw_guard-0.1.0/src/safeclaw/patterns/credentials.py +104 -0
- safeclaw_guard-0.1.0/src/safeclaw/patterns/financial.py +66 -0
- safeclaw_guard-0.1.0/src/safeclaw/patterns/personal.py +57 -0
- safeclaw_guard-0.1.0/src/safeclaw/pipeline.py +104 -0
- safeclaw_guard-0.1.0/src/safeclaw/redactor.py +80 -0
- safeclaw_guard-0.1.0/src/safeclaw/server.py +83 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npm install:*)",
|
|
5
|
+
"Bash(/usr/local/bin/npm install:*)",
|
|
6
|
+
"Bash(/opt/homebrew/bin/npm install:*)",
|
|
7
|
+
"Read(//usr/local/bin/**)",
|
|
8
|
+
"Read(//opt/homebrew/bin/**)",
|
|
9
|
+
"Read(//Users/jayanthsattineni/Documents/Projects/Safeclaw/$HOME/.nvm/versions/**)",
|
|
10
|
+
"Read(//Users/jayanthsattineni/Documents/Projects/Safeclaw/$HOME/.volta/**)",
|
|
11
|
+
"Read(//usr/bin/**)",
|
|
12
|
+
"Bash(ls /opt/homebrew/bin/python3*)",
|
|
13
|
+
"Bash(ls /usr/local/bin/python3*)",
|
|
14
|
+
"Bash(/opt/homebrew/bin/python3.13 --version)",
|
|
15
|
+
"Bash(/opt/homebrew/bin/python3.13 -m venv /Users/jayanthsattineni/Documents/Projects/Safeclaw/.venv)",
|
|
16
|
+
"Bash(.venv/bin/safeclaw scan:*)",
|
|
17
|
+
"Bash(echo \"EXIT: $?\")"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: safeclaw-guard
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Universal outbound data guard for AI agents — regex-first NER pipeline, zero ML weight, runs everywhere.
|
|
5
|
+
Project-URL: Repository, https://github.com/safeclaw/safeclaw
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: ai-agent,claude-code,data-guard,mcp,ner,pii,security
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
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: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Classifier: Topic :: Security
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: fastapi>=0.110
|
|
20
|
+
Requires-Dist: mcp>=1.0
|
|
21
|
+
Requires-Dist: pydantic>=2.0
|
|
22
|
+
Requires-Dist: pyyaml>=6.0
|
|
23
|
+
Requires-Dist: typer[all]>=0.9
|
|
24
|
+
Requires-Dist: uvicorn[standard]>=0.27
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.3; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Safeclaw
|
|
33
|
+
|
|
34
|
+
**Universal outbound data guard for AI agents.**
|
|
35
|
+
|
|
36
|
+
Safeclaw catches sensitive data (API keys, passwords, emails, credit cards) before an AI agent accidentally leaks it. Runs on-premise with zero external calls — works for local dev, CI/CD pipelines, and enterprise deployments alike.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install safeclaw-guard
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Why This Exists
|
|
45
|
+
|
|
46
|
+
AI agents have access to your codebase, `.env` files, databases, and configs. When they generate output — a shell command, a file, an API call — they can accidentally include secrets in plaintext. The agent doesn't know it's leaking. Safeclaw stops that at the exit.
|
|
47
|
+
|
|
48
|
+
```mermaid
|
|
49
|
+
flowchart LR
|
|
50
|
+
ENV["Your secrets\n.env files, API keys\npasswords, customer data"]
|
|
51
|
+
AGENT["AI Agent\nClaude Code, Cursor, etc."]
|
|
52
|
+
SCAN["SAFECLAW\nscans outbound message"]
|
|
53
|
+
PASS["Pass through"]
|
|
54
|
+
REDACT["Redact PII"]
|
|
55
|
+
BLOCK["Block secrets"]
|
|
56
|
+
OUT["Outside world\nterminal, files, APIs"]
|
|
57
|
+
|
|
58
|
+
ENV --> AGENT
|
|
59
|
+
AGENT --> SCAN
|
|
60
|
+
SCAN -- clean --> PASS
|
|
61
|
+
SCAN -- email, phone --> REDACT
|
|
62
|
+
SCAN -- API key, password --> BLOCK
|
|
63
|
+
PASS --> OUT
|
|
64
|
+
REDACT --> OUT
|
|
65
|
+
|
|
66
|
+
style ENV fill:#6c757d,stroke:#333,color:#fff
|
|
67
|
+
style AGENT fill:#4a90d9,stroke:#333,color:#fff
|
|
68
|
+
style SCAN fill:#e8943a,stroke:#333,color:#fff
|
|
69
|
+
style PASS fill:#5cb85c,stroke:#333,color:#fff
|
|
70
|
+
style REDACT fill:#f0ad4e,stroke:#333,color:#fff
|
|
71
|
+
style BLOCK fill:#d9534f,stroke:#333,color:#fff
|
|
72
|
+
style OUT fill:#6c757d,stroke:#333,color:#fff
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**In plain English:** The AI agent reads your secrets to do its job. Safeclaw makes sure those secrets don't appear in the output.
|
|
76
|
+
|
|
77
|
+
### Block vs Redact
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
Input: "Deploy with key sk-ant-api03-realkey123..."
|
|
81
|
+
Output: "[SAFECLAW BLOCKED] contains sensitive data: Anthropic API Key"
|
|
82
|
+
|
|
83
|
+
Input: "Send report to john@acme.com and call 555-867-5309"
|
|
84
|
+
Output: "Send report to [REDACTED:EMAIL] and call [REDACTED:PHONE]"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Configurable per entity type — API keys block, emails redact. Your call.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Get Started
|
|
92
|
+
|
|
93
|
+
### Claude Code (1 command)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install safeclaw-guard
|
|
97
|
+
safeclaw install
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Every tool call is now auto-scanned.
|
|
101
|
+
|
|
102
|
+
### Python library
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from safeclaw import guard
|
|
106
|
+
|
|
107
|
+
result = guard("Contact john@acme.com with key sk-ant-api03-abc123...")
|
|
108
|
+
print(result.safe) # False
|
|
109
|
+
print(result.blocked) # True — API key detected
|
|
110
|
+
print(result.text) # [SAFECLAW BLOCKED] ...
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### HTTP server (any language)
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
safeclaw serve # starts on localhost:18791
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
curl -X POST http://127.0.0.1:18791/scan \
|
|
121
|
+
-H "X-Safeclaw-Secret: <secret>" \
|
|
122
|
+
-d '{"text": "your text here"}'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### MCP server (any MCP-compatible agent)
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
safeclaw install --mcp
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## What It Detects
|
|
134
|
+
|
|
135
|
+
| Entity | Default | Examples |
|
|
136
|
+
|--------|---------|---------|
|
|
137
|
+
| API Keys | 🔴 Block | `sk-ant-...`, `AKIA...`, `ghp_...`, `sk_live_...` |
|
|
138
|
+
| Private Keys | 🔴 Block | PEM-encoded RSA/EC keys |
|
|
139
|
+
| Passwords | 🔴 Block | `password = "..."`, `postgres://user:pass@host` |
|
|
140
|
+
| Credit Cards | 🔴 Block | Visa, Mastercard, Amex (Luhn-validated) |
|
|
141
|
+
| SSNs | 🔴 Block | `123-45-6789` |
|
|
142
|
+
| JWTs | 🟡 Redact | `eyJhbG...` base64 tokens |
|
|
143
|
+
| Emails | 🟡 Redact | `user@domain.com` |
|
|
144
|
+
| Phone Numbers | 🟡 Redact | US and international formats |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Architecture
|
|
149
|
+
|
|
150
|
+
```mermaid
|
|
151
|
+
graph TB
|
|
152
|
+
subgraph "Safeclaw Core"
|
|
153
|
+
P["Pipeline"]
|
|
154
|
+
R["RegexDetector"]
|
|
155
|
+
M["MLDetector (pluggable)"]
|
|
156
|
+
P --> R
|
|
157
|
+
P --> M
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
subgraph "Integration Layer"
|
|
161
|
+
CLI["CLI (stdin/stdout)"]
|
|
162
|
+
HOOK["Claude Code Hook"]
|
|
163
|
+
MCP["MCP Server (stdio)"]
|
|
164
|
+
HTTP["HTTP Server (FastAPI)"]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
subgraph "Policy Engine"
|
|
168
|
+
CFG["safeclaw.yaml config"]
|
|
169
|
+
RED["Redactor"]
|
|
170
|
+
GUARD["Guard"]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
P --> GUARD
|
|
174
|
+
CFG --> GUARD
|
|
175
|
+
GUARD --> RED
|
|
176
|
+
|
|
177
|
+
CLI --> P
|
|
178
|
+
HOOK --> P
|
|
179
|
+
MCP --> P
|
|
180
|
+
HTTP --> P
|
|
181
|
+
|
|
182
|
+
style P fill:#4a90d9,stroke:#333,color:#fff
|
|
183
|
+
style R fill:#5cb85c,stroke:#333,color:#fff
|
|
184
|
+
style M fill:#5cb85c,stroke:#333,color:#fff,stroke-dasharray: 5 5
|
|
185
|
+
style GUARD fill:#e8943a,stroke:#333,color:#fff
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
- **Pipeline pattern** (spaCy/sklearn-inspired) — pluggable detectors. Ships with `RegexDetector`, drop in an ML model later without changing any code.
|
|
189
|
+
- **Pydantic v2 models** — typed `Span`, `Entity`, `GuardResult` following NER conventions.
|
|
190
|
+
- **Confidence scoring** — every match has a score (0.0–1.0). Only flags above your threshold.
|
|
191
|
+
- **Overlap resolution** — when two patterns match the same span, highest confidence wins.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Configuration
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
safeclaw init # creates .safeclaw.yaml
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
threshold: 0.75 # confidence cutoff
|
|
203
|
+
fail_open: true # if error: pass through (true) or block (false)
|
|
204
|
+
|
|
205
|
+
rules:
|
|
206
|
+
api_key: { action: block, enabled: true }
|
|
207
|
+
email: { action: redact, enabled: true }
|
|
208
|
+
phone: { action: redact, enabled: true }
|
|
209
|
+
ip_address: { action: redact, enabled: false } # too noisy
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Commands
|
|
215
|
+
|
|
216
|
+
| Command | What it does |
|
|
217
|
+
|---------|-------------|
|
|
218
|
+
| `safeclaw scan` | Scan stdin (also works as Claude Code hook) |
|
|
219
|
+
| `safeclaw serve` | HTTP server on localhost |
|
|
220
|
+
| `safeclaw mcp` | MCP stdio server |
|
|
221
|
+
| `safeclaw install` | Add to Claude Code |
|
|
222
|
+
| `safeclaw uninstall` | Remove from Claude Code |
|
|
223
|
+
| `safeclaw init` | Create config file |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Try It
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
git clone https://github.com/wassupjay/SafeClaw.git && cd SafeClaw
|
|
231
|
+
python -m venv .venv && source .venv/bin/activate
|
|
232
|
+
pip install -e .
|
|
233
|
+
python demo.py
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
<details>
|
|
237
|
+
<summary>Demo output</summary>
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
Clean text → ✅ PASS
|
|
241
|
+
Email → 🟡 REDACT [REDACTED:EMAIL]
|
|
242
|
+
Phone → 🟡 REDACT [REDACTED:PHONE]
|
|
243
|
+
JWT → 🟡 REDACT [REDACTED:JWT]
|
|
244
|
+
OpenAI key → 🔴 BLOCK
|
|
245
|
+
Anthropic key → 🔴 BLOCK
|
|
246
|
+
AWS key → 🔴 BLOCK
|
|
247
|
+
GitHub token → 🔴 BLOCK
|
|
248
|
+
Stripe key → 🔴 BLOCK
|
|
249
|
+
Password → 🔴 BLOCK
|
|
250
|
+
Credentials in URL → 🔴 BLOCK
|
|
251
|
+
SSN → 🔴 BLOCK
|
|
252
|
+
Credit card → 🔴 BLOCK
|
|
253
|
+
PEM private key → 🔴 BLOCK
|
|
254
|
+
16/16 tests passed
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
</details>
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
MIT
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Safeclaw
|
|
2
|
+
|
|
3
|
+
**Universal outbound data guard for AI agents.**
|
|
4
|
+
|
|
5
|
+
Safeclaw catches sensitive data (API keys, passwords, emails, credit cards) before an AI agent accidentally leaks it. Runs on-premise with zero external calls — works for local dev, CI/CD pipelines, and enterprise deployments alike.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install safeclaw-guard
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Why This Exists
|
|
14
|
+
|
|
15
|
+
AI agents have access to your codebase, `.env` files, databases, and configs. When they generate output — a shell command, a file, an API call — they can accidentally include secrets in plaintext. The agent doesn't know it's leaking. Safeclaw stops that at the exit.
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart LR
|
|
19
|
+
ENV["Your secrets\n.env files, API keys\npasswords, customer data"]
|
|
20
|
+
AGENT["AI Agent\nClaude Code, Cursor, etc."]
|
|
21
|
+
SCAN["SAFECLAW\nscans outbound message"]
|
|
22
|
+
PASS["Pass through"]
|
|
23
|
+
REDACT["Redact PII"]
|
|
24
|
+
BLOCK["Block secrets"]
|
|
25
|
+
OUT["Outside world\nterminal, files, APIs"]
|
|
26
|
+
|
|
27
|
+
ENV --> AGENT
|
|
28
|
+
AGENT --> SCAN
|
|
29
|
+
SCAN -- clean --> PASS
|
|
30
|
+
SCAN -- email, phone --> REDACT
|
|
31
|
+
SCAN -- API key, password --> BLOCK
|
|
32
|
+
PASS --> OUT
|
|
33
|
+
REDACT --> OUT
|
|
34
|
+
|
|
35
|
+
style ENV fill:#6c757d,stroke:#333,color:#fff
|
|
36
|
+
style AGENT fill:#4a90d9,stroke:#333,color:#fff
|
|
37
|
+
style SCAN fill:#e8943a,stroke:#333,color:#fff
|
|
38
|
+
style PASS fill:#5cb85c,stroke:#333,color:#fff
|
|
39
|
+
style REDACT fill:#f0ad4e,stroke:#333,color:#fff
|
|
40
|
+
style BLOCK fill:#d9534f,stroke:#333,color:#fff
|
|
41
|
+
style OUT fill:#6c757d,stroke:#333,color:#fff
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**In plain English:** The AI agent reads your secrets to do its job. Safeclaw makes sure those secrets don't appear in the output.
|
|
45
|
+
|
|
46
|
+
### Block vs Redact
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Input: "Deploy with key sk-ant-api03-realkey123..."
|
|
50
|
+
Output: "[SAFECLAW BLOCKED] contains sensitive data: Anthropic API Key"
|
|
51
|
+
|
|
52
|
+
Input: "Send report to john@acme.com and call 555-867-5309"
|
|
53
|
+
Output: "Send report to [REDACTED:EMAIL] and call [REDACTED:PHONE]"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Configurable per entity type — API keys block, emails redact. Your call.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Get Started
|
|
61
|
+
|
|
62
|
+
### Claude Code (1 command)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install safeclaw-guard
|
|
66
|
+
safeclaw install
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Every tool call is now auto-scanned.
|
|
70
|
+
|
|
71
|
+
### Python library
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from safeclaw import guard
|
|
75
|
+
|
|
76
|
+
result = guard("Contact john@acme.com with key sk-ant-api03-abc123...")
|
|
77
|
+
print(result.safe) # False
|
|
78
|
+
print(result.blocked) # True — API key detected
|
|
79
|
+
print(result.text) # [SAFECLAW BLOCKED] ...
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### HTTP server (any language)
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
safeclaw serve # starts on localhost:18791
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
curl -X POST http://127.0.0.1:18791/scan \
|
|
90
|
+
-H "X-Safeclaw-Secret: <secret>" \
|
|
91
|
+
-d '{"text": "your text here"}'
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### MCP server (any MCP-compatible agent)
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
safeclaw install --mcp
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## What It Detects
|
|
103
|
+
|
|
104
|
+
| Entity | Default | Examples |
|
|
105
|
+
|--------|---------|---------|
|
|
106
|
+
| API Keys | 🔴 Block | `sk-ant-...`, `AKIA...`, `ghp_...`, `sk_live_...` |
|
|
107
|
+
| Private Keys | 🔴 Block | PEM-encoded RSA/EC keys |
|
|
108
|
+
| Passwords | 🔴 Block | `password = "..."`, `postgres://user:pass@host` |
|
|
109
|
+
| Credit Cards | 🔴 Block | Visa, Mastercard, Amex (Luhn-validated) |
|
|
110
|
+
| SSNs | 🔴 Block | `123-45-6789` |
|
|
111
|
+
| JWTs | 🟡 Redact | `eyJhbG...` base64 tokens |
|
|
112
|
+
| Emails | 🟡 Redact | `user@domain.com` |
|
|
113
|
+
| Phone Numbers | 🟡 Redact | US and international formats |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Architecture
|
|
118
|
+
|
|
119
|
+
```mermaid
|
|
120
|
+
graph TB
|
|
121
|
+
subgraph "Safeclaw Core"
|
|
122
|
+
P["Pipeline"]
|
|
123
|
+
R["RegexDetector"]
|
|
124
|
+
M["MLDetector (pluggable)"]
|
|
125
|
+
P --> R
|
|
126
|
+
P --> M
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
subgraph "Integration Layer"
|
|
130
|
+
CLI["CLI (stdin/stdout)"]
|
|
131
|
+
HOOK["Claude Code Hook"]
|
|
132
|
+
MCP["MCP Server (stdio)"]
|
|
133
|
+
HTTP["HTTP Server (FastAPI)"]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
subgraph "Policy Engine"
|
|
137
|
+
CFG["safeclaw.yaml config"]
|
|
138
|
+
RED["Redactor"]
|
|
139
|
+
GUARD["Guard"]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
P --> GUARD
|
|
143
|
+
CFG --> GUARD
|
|
144
|
+
GUARD --> RED
|
|
145
|
+
|
|
146
|
+
CLI --> P
|
|
147
|
+
HOOK --> P
|
|
148
|
+
MCP --> P
|
|
149
|
+
HTTP --> P
|
|
150
|
+
|
|
151
|
+
style P fill:#4a90d9,stroke:#333,color:#fff
|
|
152
|
+
style R fill:#5cb85c,stroke:#333,color:#fff
|
|
153
|
+
style M fill:#5cb85c,stroke:#333,color:#fff,stroke-dasharray: 5 5
|
|
154
|
+
style GUARD fill:#e8943a,stroke:#333,color:#fff
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- **Pipeline pattern** (spaCy/sklearn-inspired) — pluggable detectors. Ships with `RegexDetector`, drop in an ML model later without changing any code.
|
|
158
|
+
- **Pydantic v2 models** — typed `Span`, `Entity`, `GuardResult` following NER conventions.
|
|
159
|
+
- **Confidence scoring** — every match has a score (0.0–1.0). Only flags above your threshold.
|
|
160
|
+
- **Overlap resolution** — when two patterns match the same span, highest confidence wins.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Configuration
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
safeclaw init # creates .safeclaw.yaml
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
threshold: 0.75 # confidence cutoff
|
|
172
|
+
fail_open: true # if error: pass through (true) or block (false)
|
|
173
|
+
|
|
174
|
+
rules:
|
|
175
|
+
api_key: { action: block, enabled: true }
|
|
176
|
+
email: { action: redact, enabled: true }
|
|
177
|
+
phone: { action: redact, enabled: true }
|
|
178
|
+
ip_address: { action: redact, enabled: false } # too noisy
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Commands
|
|
184
|
+
|
|
185
|
+
| Command | What it does |
|
|
186
|
+
|---------|-------------|
|
|
187
|
+
| `safeclaw scan` | Scan stdin (also works as Claude Code hook) |
|
|
188
|
+
| `safeclaw serve` | HTTP server on localhost |
|
|
189
|
+
| `safeclaw mcp` | MCP stdio server |
|
|
190
|
+
| `safeclaw install` | Add to Claude Code |
|
|
191
|
+
| `safeclaw uninstall` | Remove from Claude Code |
|
|
192
|
+
| `safeclaw init` | Create config file |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Try It
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
git clone https://github.com/wassupjay/SafeClaw.git && cd SafeClaw
|
|
200
|
+
python -m venv .venv && source .venv/bin/activate
|
|
201
|
+
pip install -e .
|
|
202
|
+
python demo.py
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
<details>
|
|
206
|
+
<summary>Demo output</summary>
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
Clean text → ✅ PASS
|
|
210
|
+
Email → 🟡 REDACT [REDACTED:EMAIL]
|
|
211
|
+
Phone → 🟡 REDACT [REDACTED:PHONE]
|
|
212
|
+
JWT → 🟡 REDACT [REDACTED:JWT]
|
|
213
|
+
OpenAI key → 🔴 BLOCK
|
|
214
|
+
Anthropic key → 🔴 BLOCK
|
|
215
|
+
AWS key → 🔴 BLOCK
|
|
216
|
+
GitHub token → 🔴 BLOCK
|
|
217
|
+
Stripe key → 🔴 BLOCK
|
|
218
|
+
Password → 🔴 BLOCK
|
|
219
|
+
Credentials in URL → 🔴 BLOCK
|
|
220
|
+
SSN → 🔴 BLOCK
|
|
221
|
+
Credit card → 🔴 BLOCK
|
|
222
|
+
PEM private key → 🔴 BLOCK
|
|
223
|
+
16/16 tests passed
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
</details>
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Safeclaw configuration
|
|
2
|
+
# Copy this file to .safeclaw.yaml in your project or home directory.
|
|
3
|
+
# Run `safeclaw init` to create a copy in the current directory.
|
|
4
|
+
#
|
|
5
|
+
# Reference: https://github.com/your-org/safeclaw
|
|
6
|
+
|
|
7
|
+
version: 1
|
|
8
|
+
|
|
9
|
+
# Minimum confidence score (0.0–1.0) to flag an entity.
|
|
10
|
+
# Lower = more sensitive but more false positives.
|
|
11
|
+
# Higher = fewer false positives but may miss lower-confidence matches.
|
|
12
|
+
threshold: 0.75
|
|
13
|
+
|
|
14
|
+
# fail_open: true → if scanning throws an error, pass the message through (default, safer for uptime)
|
|
15
|
+
# fail_open: false → if scanning throws an error, block the message
|
|
16
|
+
fail_open: true
|
|
17
|
+
|
|
18
|
+
# Per-entity-type rules.
|
|
19
|
+
# action: "block" — replace the entire message with a warning
|
|
20
|
+
# action: "redact" — replace only the sensitive span with [REDACTED:TYPE]
|
|
21
|
+
# enabled: false — skip this entity type entirely
|
|
22
|
+
rules:
|
|
23
|
+
api_key:
|
|
24
|
+
action: block
|
|
25
|
+
enabled: true
|
|
26
|
+
|
|
27
|
+
private_key:
|
|
28
|
+
action: block
|
|
29
|
+
enabled: true
|
|
30
|
+
|
|
31
|
+
jwt:
|
|
32
|
+
action: redact # JWTs are common in logs; redact rather than hard-block
|
|
33
|
+
enabled: true
|
|
34
|
+
|
|
35
|
+
password:
|
|
36
|
+
action: block
|
|
37
|
+
enabled: true
|
|
38
|
+
|
|
39
|
+
email:
|
|
40
|
+
action: redact
|
|
41
|
+
enabled: true
|
|
42
|
+
|
|
43
|
+
phone:
|
|
44
|
+
action: redact
|
|
45
|
+
enabled: true
|
|
46
|
+
|
|
47
|
+
ssn:
|
|
48
|
+
action: block
|
|
49
|
+
enabled: true
|
|
50
|
+
|
|
51
|
+
passport:
|
|
52
|
+
action: redact
|
|
53
|
+
enabled: true
|
|
54
|
+
|
|
55
|
+
ip_address:
|
|
56
|
+
action: redact
|
|
57
|
+
enabled: false # Disabled by default — IP addresses are often benign in agent context
|
|
58
|
+
|
|
59
|
+
credit_card:
|
|
60
|
+
action: block
|
|
61
|
+
enabled: true
|
|
62
|
+
|
|
63
|
+
bank_account:
|
|
64
|
+
action: block
|
|
65
|
+
enabled: true
|
|
66
|
+
|
|
67
|
+
# HTTP server settings (used by `safeclaw serve`)
|
|
68
|
+
server:
|
|
69
|
+
port: 18791
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Safeclaw Demo — run this to see every detection and action mode in action."""
|
|
2
|
+
|
|
3
|
+
from safeclaw import guard, Pipeline, load_config
|
|
4
|
+
from safeclaw.pipeline import RegexDetector
|
|
5
|
+
|
|
6
|
+
config = load_config()
|
|
7
|
+
pipeline = Pipeline([RegexDetector()])
|
|
8
|
+
|
|
9
|
+
# ── Test cases ────────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
TESTS = [
|
|
12
|
+
("Clean text (should pass through)", "Hello, this is a normal message with no secrets."),
|
|
13
|
+
("Email → redact", "Please contact john.doe@company.com for onboarding."),
|
|
14
|
+
("Phone → redact", "Call me at (555) 867-5309 or +44 20 7946 0958."),
|
|
15
|
+
("Email + Phone → redact both", "Reach out to admin@startup.io or call 415-555-0199."),
|
|
16
|
+
("JWT → redact", "Bearer token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U"),
|
|
17
|
+
("OpenAI key → block", "Set OPENAI_API_KEY=sk-proj-abc123def456ghi789jkl012mno345"),
|
|
18
|
+
("Anthropic key → block", "Use sk-ant-api03-abcdefghijklmnop12345-xyz as the key."),
|
|
19
|
+
("AWS key → block", "Access key: AKIAIOSFODNN7EXAMPLE"),
|
|
20
|
+
("GitHub token → block", "ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"),
|
|
21
|
+
("Stripe key → block", "sk" + "_live_" + "FAKEKEYFORTESTING00000000000000"),
|
|
22
|
+
("Password in config → block", "password = SuperSecret123!@#xyz"),
|
|
23
|
+
("Credentials in URL → block", "Connect to postgres://admin:p4ssw0rd_secret@db.internal:5432/app"),
|
|
24
|
+
("SSN → block", "SSN: 123-45-6789"),
|
|
25
|
+
("Credit card (Visa) → block", "Card: 4111111111111111"),
|
|
26
|
+
("PEM private key → block", "-----BEGIN RSA PRIVATE KEY-----\nMIIBogIBAAJBALRiMLAH...base64data...==\n-----END RSA PRIVATE KEY-----"),
|
|
27
|
+
("Mixed: redact + block", "Email support@acme.com, key is sk-ant-api03-realkey1234567890abcd-xyz"),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# ── Run ───────────────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
WIDTH = 80
|
|
33
|
+
print("=" * WIDTH)
|
|
34
|
+
print(" SAFECLAW DEMO".center(WIDTH))
|
|
35
|
+
print("=" * WIDTH)
|
|
36
|
+
|
|
37
|
+
passed = 0
|
|
38
|
+
for label, text in TESTS:
|
|
39
|
+
result = guard(text, config=config, pipeline=pipeline)
|
|
40
|
+
|
|
41
|
+
if result.safe:
|
|
42
|
+
status = "\033[92mPASS\033[0m"
|
|
43
|
+
elif result.blocked:
|
|
44
|
+
status = "\033[91mBLOCK\033[0m"
|
|
45
|
+
else:
|
|
46
|
+
status = "\033[93mREDACT\033[0m"
|
|
47
|
+
|
|
48
|
+
print(f"\n{'─' * WIDTH}")
|
|
49
|
+
print(f" Test: {label}")
|
|
50
|
+
print(f" Status: {status}")
|
|
51
|
+
print(f" Input: {text[:70]}{'...' if len(text) > 70 else ''}")
|
|
52
|
+
print(f" Output: {result.text[:70]}{'...' if len(result.text) > 70 else ''}")
|
|
53
|
+
|
|
54
|
+
if result.entities:
|
|
55
|
+
for e in result.entities:
|
|
56
|
+
print(f" → {e.entity_type.value:15} | conf={e.confidence:.2f} | action={e.action.value:6} | {e.label}")
|
|
57
|
+
|
|
58
|
+
passed += 1
|
|
59
|
+
|
|
60
|
+
print(f"\n{'=' * WIDTH}")
|
|
61
|
+
print(f" {passed}/{len(TESTS)} tests completed")
|
|
62
|
+
print(f"{'=' * WIDTH}")
|