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.
@@ -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,9 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .ruff_cache/
8
+ .pytest_cache/
9
+ .claude/launch.json
@@ -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}")