phi-gate 0.2.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.
- phi_gate-0.2.0/LICENSE +21 -0
- phi_gate-0.2.0/PKG-INFO +344 -0
- phi_gate-0.2.0/README.md +316 -0
- phi_gate-0.2.0/pyproject.toml +59 -0
- phi_gate-0.2.0/setup.cfg +4 -0
- phi_gate-0.2.0/src/phi_gate/__init__.py +3 -0
- phi_gate-0.2.0/src/phi_gate/__main__.py +5 -0
- phi_gate-0.2.0/src/phi_gate/audit.py +330 -0
- phi_gate-0.2.0/src/phi_gate/cli.py +410 -0
- phi_gate-0.2.0/src/phi_gate/config.py +600 -0
- phi_gate-0.2.0/src/phi_gate/detectors.py +1086 -0
- phi_gate-0.2.0/src/phi_gate/globs.py +227 -0
- phi_gate-0.2.0/src/phi_gate/hooks.py +644 -0
- phi_gate-0.2.0/src/phi_gate/policy.py +97 -0
- phi_gate-0.2.0/src/phi_gate/py.typed +0 -0
- phi_gate-0.2.0/src/phi_gate/redact.py +236 -0
- phi_gate-0.2.0/src/phi_gate/scanner.py +776 -0
- phi_gate-0.2.0/src/phi_gate/shell.py +1582 -0
- phi_gate-0.2.0/src/phi_gate.egg-info/PKG-INFO +344 -0
- phi_gate-0.2.0/src/phi_gate.egg-info/SOURCES.txt +36 -0
- phi_gate-0.2.0/src/phi_gate.egg-info/dependency_links.txt +1 -0
- phi_gate-0.2.0/src/phi_gate.egg-info/entry_points.txt +2 -0
- phi_gate-0.2.0/src/phi_gate.egg-info/requires.txt +5 -0
- phi_gate-0.2.0/src/phi_gate.egg-info/top_level.txt +1 -0
- phi_gate-0.2.0/tests/test_bypasses.py +356 -0
- phi_gate-0.2.0/tests/test_changes.py +349 -0
- phi_gate-0.2.0/tests/test_cli.py +68 -0
- phi_gate-0.2.0/tests/test_config_hardening.py +791 -0
- phi_gate-0.2.0/tests/test_detector_hardening.py +445 -0
- phi_gate-0.2.0/tests/test_detectors.py +203 -0
- phi_gate-0.2.0/tests/test_gates.py +376 -0
- phi_gate-0.2.0/tests/test_globs.py +183 -0
- phi_gate-0.2.0/tests/test_hooks.py +359 -0
- phi_gate-0.2.0/tests/test_integration_hardening.py +91 -0
- phi_gate-0.2.0/tests/test_properties.py +180 -0
- phi_gate-0.2.0/tests/test_redact.py +114 -0
- phi_gate-0.2.0/tests/test_shell_hardening.py +359 -0
- phi_gate-0.2.0/tests/test_stress.py +81 -0
phi_gate-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 obutuz
|
|
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.
|
phi_gate-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: phi-gate
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Fail-closed PHI guardrails for AI coding agents (Claude Code hooks, CLI, git pre-commit)
|
|
5
|
+
Author: obutuz
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/obutuz/phi-gate
|
|
8
|
+
Project-URL: Issues, https://github.com/obutuz/phi-gate/issues
|
|
9
|
+
Keywords: hipaa,phi,pii,redaction,claude-code,healthcare,dlp
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Security
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Classifier: Intended Audience :: Developers
|
|
19
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: hypothesis>=6.100; extra == "dev"
|
|
25
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# phi-gate
|
|
30
|
+
|
|
31
|
+
**Fail-closed PHI guardrails for AI coding agents.** A Claude Code plugin, a CLI and a
|
|
32
|
+
git pre-commit hook that stop patient identifiers from reaching the model, your code,
|
|
33
|
+
your commits, or the tools your agent talks to.
|
|
34
|
+
|
|
35
|
+
[](https://github.com/obutuz/phi-gate/actions/workflows/ci.yml)
|
|
36
|
+

|
|
37
|
+
[](https://github.com/obutuz/phi-gate/actions/workflows/codeql.yml)
|
|
38
|
+

|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
AI coding agents read whatever is in the working tree and send it to a model. On a
|
|
42
|
+
healthcare codebase that working tree often holds an eligibility export someone
|
|
43
|
+
dropped in `data/`, an 835 remittance file used to debug a parser, an HL7 feed sample,
|
|
44
|
+
or seed data that started life as a production query. One `cat` and the agent has sent
|
|
45
|
+
patient records to a vendor that may not be covered by your BAA.
|
|
46
|
+
|
|
47
|
+
phi-gate puts a checkpoint on every path that data can take through an agent session,
|
|
48
|
+
and when it cannot run, it blocks instead of letting things through.
|
|
49
|
+
|
|
50
|
+
## What it guards
|
|
51
|
+
|
|
52
|
+
| Boundary | How | What happens |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| Your prompts | `UserPromptSubmit` hook | A prompt with an SSN, DOB, MRN, member ID... is stopped before it reaches the model (you can deliberately override one prompt, see [Configuration](#configuration)) |
|
|
55
|
+
| File reads | `PreToolUse` on `Read`, `NotebookRead`, `Grep` and `Bash` | Denied for files containing PHI. Shell analysis follows `cd` and `pushd`, variables, globs, braces, redirections, `bash -c`, copies, recursive `grep`/`rg`/`find`/`tar`, and paths inside `python -c` or `node -e`. A path it cannot resolve is refused when the project holds PHI |
|
|
56
|
+
| Git history | `PreToolUse` on `git show`, `log -p`, `diff`, `stash show`, `grep`, `archive`, ... | The objects the command would print are scanned first, so a deleted file cannot be read back from history |
|
|
57
|
+
| Writes and edits | `PreToolUse` on `Write`, `Edit`, `MultiEdit`, `NotebookEdit` | PHI never lands in source, fixtures, seed files or logs |
|
|
58
|
+
| Commits | `PreToolUse` on `git commit` and other commit-making commands, plus an optional git pre-commit hook | Each changed file is scanned whole and the commit is judged by the PHI it introduces, so rows appended under an old table header are caught. `--no-verify` (any spelling), aliases, plumbing and `core.hooksPath` overrides are covered |
|
|
59
|
+
| Outbound and other tools | `PreToolUse` on every tool: `WebFetch`, `WebSearch`, MCP tools, sub-agent prompts | No identifiers in Slack messages, tickets, URLs, search queries or delegated tasks; files a tool names are scanned too |
|
|
60
|
+
| Sending data off the machine | `PreToolUse` on `Bash` | `curl`, `scp`, `nc` and similar are refused when what they send could not be checked |
|
|
61
|
+
| Tool output | `PostToolUse` on every tool | Output with PHI is flagged; the agent is told not to propagate it and to tell you |
|
|
62
|
+
| Its own rules | `PreToolUse` | The agent cannot edit phi-gate's configuration or audit log, Claude Code settings, `.mcp.json`, or git hooks, so it cannot loosen or switch off its own guardrails |
|
|
63
|
+
|
|
64
|
+
Every block, warning and override is written to a hash-chained log at
|
|
65
|
+
`.phi-gate/audit.jsonl` with the event, tool, target and the categories found. Never
|
|
66
|
+
values, never hashes of values, and file names are recorded as keyed hashes by default.
|
|
67
|
+
See [data handling](docs/DATA-HANDLING.md).
|
|
68
|
+
|
|
69
|
+
## How a Claude Code session goes
|
|
70
|
+
|
|
71
|
+
1. Claude tries `head -5 data/denials-export.csv`. The `PreToolUse` hook scans the file,
|
|
72
|
+
finds a patient table, and denies the command with a message telling Claude why and
|
|
73
|
+
what to do instead.
|
|
74
|
+
2. Claude runs `phi-gate redact data/denials-export.csv > copy.csv`. phi-gate's own
|
|
75
|
+
read-only commands are allowed, and the copy keeps the table's shape: identifier
|
|
76
|
+
columns become `[PATIENT_NAME_1]`, `[DOB_1]`, `[MEMBER_ID_1]`, while payer, CARC code
|
|
77
|
+
and amount stay as they were.
|
|
78
|
+
3. Claude totals the copy and answers. Everything it saw went through phi-gate first.
|
|
79
|
+
|
|
80
|
+
## Install
|
|
81
|
+
|
|
82
|
+
### Claude Code plugin
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
/plugin marketplace add obutuz/phi-gate
|
|
86
|
+
/plugin install phi-gate@phi-gate
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Needs `python3` (3.11 or newer), `bash` and `git` on the machine. No packages to install.
|
|
90
|
+
|
|
91
|
+
The plugin adds:
|
|
92
|
+
|
|
93
|
+
- the hooks above
|
|
94
|
+
- the `hipaa-aware-dev` skill: minimum-necessary access, PHI-free logging and error
|
|
95
|
+
reporting, audit trails, synthetic data, vendor/BAA boundaries, with code for
|
|
96
|
+
Next.js, React, Svelte and Python
|
|
97
|
+
- `/phi-gate:scan`, `/phi-gate:redact` and `/phi-gate:status`
|
|
98
|
+
- a `phi-gate` command on the agent's `PATH`
|
|
99
|
+
|
|
100
|
+
### CLI and git hook (any editor or agent: Codex, Cursor, Copilot, plain git)
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pipx install git+https://github.com/obutuz/phi-gate
|
|
104
|
+
phi-gate install-git-hook # blocks commits that introduce PHI
|
|
105
|
+
phi-gate scan . # exit 1 if anything would be blocked
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
With the [pre-commit](https://pre-commit.com) framework (this blocks on any PHI in the
|
|
109
|
+
files being committed, including PHI committed earlier, where `install-git-hook` judges
|
|
110
|
+
only what the commit introduces):
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
repos:
|
|
114
|
+
- repo: https://github.com/obutuz/phi-gate
|
|
115
|
+
rev: v0.2.0
|
|
116
|
+
hooks:
|
|
117
|
+
- id: phi-gate
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Other agents can be pointed at the CLI with a rule in their instructions file; see
|
|
121
|
+
[`examples/AGENTS.md`](examples/AGENTS.md).
|
|
122
|
+
|
|
123
|
+
## Try it without an API key
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
git clone https://github.com/obutuz/phi-gate && cd phi-gate
|
|
127
|
+
./demo/run-demo.sh
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The script replays the hook calls Claude Code makes against a throwaway project with
|
|
131
|
+
synthetic data and prints each decision, then the audit log:
|
|
132
|
+
|
|
133
|
+

|
|
134
|
+
|
|
135
|
+
## The CLI
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
phi-gate scan src/ data/ # human output: path:line:col severity category
|
|
139
|
+
phi-gate scan --staged --json # machine output for CI
|
|
140
|
+
phi-gate redact export.csv # placeholder copy on stdout
|
|
141
|
+
phi-gate redact export.csv --map m.json && phi-gate restore --map m.json < answer.txt
|
|
142
|
+
phi-gate status # config and recent audit events
|
|
143
|
+
phi-gate audit verify # exit 1 if the audit log was altered
|
|
144
|
+
phi-gate explain # every detector and the decision rules
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Scan** a project. Output names the file, line, severity and category, never the value:
|
|
148
|
+
|
|
149
|
+

|
|
150
|
+
|
|
151
|
+
**Redact** a file or a stream. Placeholders are typed and consistent within a file, tables
|
|
152
|
+
keep their columns, and clinical and financial columns are left alone so the copy is still
|
|
153
|
+
useful for analysis:
|
|
154
|
+
|
|
155
|
+

|
|
156
|
+
|
|
157
|
+
**Commit** checks run in the git pre-commit hook, for any editor or agent:
|
|
158
|
+
|
|
159
|
+

|
|
160
|
+
|
|
161
|
+
**Audit**: every block, warning and override is logged with event, tool, target and category:
|
|
162
|
+
|
|
163
|
+

|
|
164
|
+
|
|
165
|
+
## How detection works
|
|
166
|
+
|
|
167
|
+
Pure Python standard library, no network calls, no model. Detectors are patterns with
|
|
168
|
+
validation (check digits, issued ranges, labelled context), plus parsers for the
|
|
169
|
+
formats healthcare data actually arrives in. Text files are read as UTF-8, UTF-16 or
|
|
170
|
+
UTF-32, and matched on a normalised view, so invisible characters, Unicode dashes and
|
|
171
|
+
spaces, fullwidth letters and look-alike letters do not hide an identifier. Every pattern
|
|
172
|
+
runs in linear time. Containers are opened and their contents scanned: `.xlsx`, `.docx`, `.pptx`,
|
|
173
|
+
OpenDocument files, zip and gzip archives, and SQLite databases (header plus the first
|
|
174
|
+
500 rows of each table), because exports are how patient lists actually travel. The scanner,
|
|
175
|
+
`phi-gate redact` and the commit gate all read them the same way. A container that cannot
|
|
176
|
+
be parsed is blocked, not skipped, and so is a DICOM image, whose header holds the patient's
|
|
177
|
+
name.
|
|
178
|
+
|
|
179
|
+
| Blocks on its own (HIGH) | Blocks next to a clinical fact (MEDIUM) | Informational (LOW) |
|
|
180
|
+
|---|---|---|
|
|
181
|
+
| SSN (issued ranges), labelled 9-digit SSN | Labelled names | Provider NPI (check digit) |
|
|
182
|
+
| Medicare MBI | Phone numbers | DEA number (checksum) |
|
|
183
|
+
| Labelled MRN, patient ID, chart number | Email addresses | Public IP addresses |
|
|
184
|
+
| Labelled member, subscriber, Medicaid, Medicare IDs | Street addresses, city/state/ZIP | |
|
|
185
|
+
| Labelled date of birth | Labelled diagnosis codes (ICD-10) | |
|
|
186
|
+
| Patient-labelled names (`patientName`, `Patient Name:`) | Labelled admission, discharge, service dates | |
|
|
187
|
+
| Labelled account numbers, Luhn-valid payment cards | | |
|
|
188
|
+
| X12 EDI `NM1*QC` / `NM1*IL` and `DMG*D8` segments (835/837) | | |
|
|
189
|
+
| HL7 v2 `PID` segments, FHIR `Patient` resources (JSON and XML) | | |
|
|
190
|
+
| CSV/TSV/pipe tables with patient identifier columns and data rows | | |
|
|
191
|
+
| Labelled values in XML elements (`<SSN>`, `<MemberId>`, `<DateOfBirth>`) | | |
|
|
192
|
+
|
|
193
|
+
**Decision rules.** Any HIGH finding blocks. A clinical fact (diagnosis code, date of
|
|
194
|
+
service) within 400 characters of a name, phone, email or address blocks, because
|
|
195
|
+
identity plus health information is what PHI is. Other MEDIUM findings only warn: a
|
|
196
|
+
name next to an email is usually a `package.json` author field or a staff directory.
|
|
197
|
+
LOW findings never block.
|
|
198
|
+
|
|
199
|
+
**Synthetic values pass by design.** These cannot belong to a real person, so they are
|
|
200
|
+
never flagged and fixtures written with them just work:
|
|
201
|
+
|
|
202
|
+
- SSNs in never-issued ranges: `000-`, `666-`, `9xx-` (Synthea uses `999-`), and
|
|
203
|
+
well-known dummies such as `123-45-6789`, `078-05-1120` and repeated digits
|
|
204
|
+
(`111-22-3333`)
|
|
205
|
+
- phone numbers `555-0100` to `555-0199`, and toll-free numbers
|
|
206
|
+
- emails at `example.com`, `example.org`, `example.net`, `.test`, `.example`, `.invalid`
|
|
207
|
+
- processor test cards (`4242 4242 4242 4242`, `4111 1111 1111 1111`, ...)
|
|
208
|
+
|
|
209
|
+
Generated records are different: a Synthea CSV or FHIR bundle still has the shape of a
|
|
210
|
+
patient record (name and birth-date columns, `Patient` resources), and phi-gate cannot
|
|
211
|
+
tell it from a real export. Keep generator output under a folder listed in `allow_paths`.
|
|
212
|
+
|
|
213
|
+
### Measured false-positive rate
|
|
214
|
+
|
|
215
|
+
Blocking ordinary code would get the plugin uninstalled in a day, so this is measured,
|
|
216
|
+
not hoped for. Across 4,725 files (69.3 MB: the CPython 3.13 standard library with NumPy
|
|
217
|
+
and other installed packages), phi-gate blocked **1 file, or 0.02%**: a 19-digit integer
|
|
218
|
+
in NumPy test data that passes the payment card check. Average cost: about 7 ms per
|
|
219
|
+
file. Reproduce it on your own code:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
python3 bench/false_positive_sweep.py path/to/your/repo
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Configuration
|
|
226
|
+
|
|
227
|
+
Optional `.phi-gate.toml` at the project root. Everything has a safe default. The
|
|
228
|
+
annotated version is [`examples/.phi-gate.toml`](examples/.phi-gate.toml).
|
|
229
|
+
|
|
230
|
+
```toml
|
|
231
|
+
[phi-gate]
|
|
232
|
+
mode = "block" # block | warn | audit
|
|
233
|
+
allow_paths = ["tests/fixtures/**"] # synthetic data lives here (gitignore-style globs)
|
|
234
|
+
allow_values = ["1EG4-TE5-MK73"] # known test values (exact; prefix "re:" for a regex)
|
|
235
|
+
disable = [] # categories to switch off
|
|
236
|
+
opaque = "allow" # or "block": refuse formats phi-gate cannot read
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The [configuration reference](docs/CONFIGURATION.md) covers every key, how patterns
|
|
240
|
+
match, and how layers combine.
|
|
241
|
+
|
|
242
|
+
Start with `mode = "audit"` on an existing repo to see what would be blocked, then
|
|
243
|
+
switch to `block`.
|
|
244
|
+
|
|
245
|
+
**Prompt override.** A prompt that starts with `#phi-ok` is sent even if it contains
|
|
246
|
+
identifiers, and the override is logged. Only a person can type a prompt, so the agent
|
|
247
|
+
cannot use it. Use it only where your organisation has a BAA covering the model provider,
|
|
248
|
+
or switch it off with `prompt_override_token = ""`.
|
|
249
|
+
|
|
250
|
+
**Managed policy.** A security team can install a policy that every repository on a machine
|
|
251
|
+
must meet and none can loosen; a `.phi-gate.toml` in a subfolder can only tighten the
|
|
252
|
+
rules. See the [deployment guide](docs/DEPLOYMENT.md).
|
|
253
|
+
|
|
254
|
+
## Fail-closed by design
|
|
255
|
+
|
|
256
|
+
- An action is allowed only when the checker exits 0 and confirms the decision with a
|
|
257
|
+
token on a separate file descriptor. If the checker crashes, the interpreter is missing
|
|
258
|
+
or replaced, or the payload is malformed, empty or for the wrong event, the action is
|
|
259
|
+
blocked.
|
|
260
|
+
- Claude Code lets an action through when a hook times out, so phi-gate never relies on
|
|
261
|
+
that timeout: detectors are linear-time (tested against adversarial inputs), an
|
|
262
|
+
internal 15-second deadline blocks first, and the wrapper stops the checker at 25
|
|
263
|
+
seconds, before the 30-second hook timeout set in `hooks.json`.
|
|
264
|
+
- A typo in `.phi-gate.toml` (unknown key, bad value, invalid regex) blocks with a clear
|
|
265
|
+
error instead of being ignored. An ignored typo in an allowlist is a silent hole.
|
|
266
|
+
- Files over `max_bytes` are blocked unscanned unless you choose `oversize = "scan_head"`.
|
|
267
|
+
- The hook runs Python in isolated mode (`-I`), so a `phi_gate/` folder in the project
|
|
268
|
+
cannot shadow the real one.
|
|
269
|
+
- Findings carry positions, never values, so no message, log line or audit entry can
|
|
270
|
+
leak what was found.
|
|
271
|
+
- `PHI_GATE_FAIL_OPEN=1` exists as an explicit, visible escape hatch for a broken
|
|
272
|
+
install. It is off by default, and a managed policy switches it off entirely.
|
|
273
|
+
|
|
274
|
+
## Limitations
|
|
275
|
+
|
|
276
|
+
Be clear-eyed about what a pattern scanner on a developer machine can and cannot do.
|
|
277
|
+
|
|
278
|
+
- **It is not a de-identification tool.** It catches structured identifiers and common
|
|
279
|
+
healthcare formats. It misses names in free-text clinical notes without a label,
|
|
280
|
+
identifiers in PDFs, images, legacy `.doc`/`.xls`, 7z/rar, Parquet and nested
|
|
281
|
+
archives (these are not inspected, or are refused with `opaque = "block"`), and non-US
|
|
282
|
+
identifiers.
|
|
283
|
+
- **Shell analysis is static.** Bash is a programming language. phi-gate resolves the
|
|
284
|
+
routes in the table above and refuses what it cannot resolve when the project holds
|
|
285
|
+
PHI, but a program or script file that opens files itself (`python tool.py`, a query
|
|
286
|
+
against a database server) is only checked after it runs, through the output scan. In
|
|
287
|
+
the other direction it is conservative: a recursive `grep` over a folder that holds a
|
|
288
|
+
PHI file is refused until that file is moved, removed or allowlisted.
|
|
289
|
+
- **`PostToolUse` cannot un-send.** When output arrives through a route phi-gate could
|
|
290
|
+
not see in advance (a database query, a program that opens files itself), the data is
|
|
291
|
+
already in context. phi-gate then tells the agent to contain it, tells you, and logs
|
|
292
|
+
it. It never sees data a command sent somewhere else.
|
|
293
|
+
- **It protects against agent mistakes, not a determined insider.** A user can disable
|
|
294
|
+
the plugin. Pair it with real controls: no production PHI on developer machines,
|
|
295
|
+
least-privilege database access, and your organisation's DLP.
|
|
296
|
+
- **"HIPAA-aware", not "HIPAA compliant".** Compliance is a property of an
|
|
297
|
+
organisation's safeguards, policies and agreements, not of a tool. Nothing here is
|
|
298
|
+
legal advice.
|
|
299
|
+
- Claude Code shows a blocked prompt back to you so you can edit it. That copy stays
|
|
300
|
+
on your machine; the prompt is not sent to the model.
|
|
301
|
+
- This is a Claude Code plugin. claude.ai and Cowork do not install plugins that ship a
|
|
302
|
+
`bin/` folder.
|
|
303
|
+
|
|
304
|
+
The [threat model](docs/THREAT-MODEL.md) sets out what phi-gate defends against and where
|
|
305
|
+
that stops. The [deployment guide](docs/DEPLOYMENT.md) covers rolling it out across a team,
|
|
306
|
+
and [data handling](docs/DATA-HANDLING.md) what phi-gate stores and where.
|
|
307
|
+
|
|
308
|
+
## Roadmap
|
|
309
|
+
|
|
310
|
+
- Optional named-entity recognition for names in free text, behind a flag, keeping the
|
|
311
|
+
standard-library default
|
|
312
|
+
- Remaining Safe Harbor identifiers: license, vehicle and device numbers
|
|
313
|
+
- Pluggable detector packs for non-US identifiers
|
|
314
|
+
- Windows support, which today is blocked by the bash hook wrapper
|
|
315
|
+
- Direct audit shipping to a SIEM
|
|
316
|
+
- Publishing to PyPI, and an independent security review before 1.0
|
|
317
|
+
|
|
318
|
+
## Development
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
python3 -m unittest discover -s tests # unit, hook, git, property and stress tests
|
|
322
|
+
./demo/run-demo.sh # exits 1 if any decision changes
|
|
323
|
+
claude plugin validate . --strict
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full checks.
|
|
327
|
+
|
|
328
|
+
Layout:
|
|
329
|
+
|
|
330
|
+
```text
|
|
331
|
+
.claude-plugin/ plugin.json and marketplace.json (this repo is its own marketplace)
|
|
332
|
+
hooks/ hooks.json and the fail-closed run.sh wrapper
|
|
333
|
+
bin/phi-gate CLI, put on the agent's PATH by Claude Code
|
|
334
|
+
src/phi_gate/ detectors, policy, scanner, shell analysis, redaction, audit, hooks, CLI
|
|
335
|
+
skills/ hipaa-aware-dev skill and references
|
|
336
|
+
commands/ /phi-gate:scan, /phi-gate:redact, /phi-gate:status
|
|
337
|
+
tests/ unit, hook, git, property and stress tests (synthetic data only)
|
|
338
|
+
bench/ false-positive sweep
|
|
339
|
+
docs/ threat model, deployment, configuration, data handling, screenshots (synthetic data only)
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## License
|
|
343
|
+
|
|
344
|
+
MIT
|