redact0 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.
- redact0-1.0.0/.gitignore +31 -0
- redact0-1.0.0/PKG-INFO +129 -0
- redact0-1.0.0/README.md +110 -0
- redact0-1.0.0/pyproject.toml +31 -0
- redact0-1.0.0/src/redact0/__init__.py +51 -0
- redact0-1.0.0/src/redact0/cli.py +28 -0
- redact0-1.0.0/src/redact0/compat/__init__.py +3 -0
- redact0-1.0.0/src/redact0/compat/llm_guard.py +70 -0
- redact0-1.0.0/src/redact0/py.typed +3 -0
- redact0-1.0.0/src/redact0/rules.py +305 -0
- redact0-1.0.0/src/redact0/validators.py +223 -0
- redact0-1.0.0/src/redact0/vault.py +447 -0
- redact0-1.0.0/tests/test_redact0.py +70 -0
redact0-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
.pnp
|
|
4
|
+
.pnp.js
|
|
5
|
+
|
|
6
|
+
# Production build outputs
|
|
7
|
+
dist/
|
|
8
|
+
|
|
9
|
+
# Python artifacts
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.py[cod]
|
|
12
|
+
*$py.class
|
|
13
|
+
*.egg-info/
|
|
14
|
+
python/dist/
|
|
15
|
+
python/build/
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.venv/
|
|
18
|
+
venv/
|
|
19
|
+
|
|
20
|
+
# Logs & Environment
|
|
21
|
+
npm-debug.log*
|
|
22
|
+
yarn-debug.log*
|
|
23
|
+
yarn-error.log*
|
|
24
|
+
*.log
|
|
25
|
+
.env
|
|
26
|
+
.env.*
|
|
27
|
+
!.env.example
|
|
28
|
+
|
|
29
|
+
# OS files
|
|
30
|
+
.DS_Store
|
|
31
|
+
Thumbs.db
|
redact0-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: redact0
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Zero-dependency reversible PII, secret, FHIR HIPAA Safe Harbor, and streaming LLM boundary redactor. Drop-in migration for llm-guard.
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: ai,fhir,gdpr,hipaa,llm-guard,pii,redaction,secrets
|
|
7
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Security
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# redact0
|
|
21
|
+
|
|
22
|
+
Zero-runtime-dependency reversible PII, secret, FHIR Safe Harbor and streaming redaction for JavaScript/TypeScript and Python.
|
|
23
|
+
|
|
24
|
+
> Security note: this package is a best-effort detector/redactor, not a compliance certification or a substitute for a privacy/security review. Validate it against your own data and regulatory requirements before production use.
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- Node.js 18+ for the npm package
|
|
29
|
+
- Python 3.10+ for the PyPI package
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install redact0
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
python -m pip install redact0
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## JavaScript / TypeScript quick start
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { createVault, redact } from 'redact0';
|
|
45
|
+
|
|
46
|
+
const safe = redact({
|
|
47
|
+
email: 'alice@example.com',
|
|
48
|
+
message: 'Contact alice@example.com',
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const vault = createVault();
|
|
52
|
+
const scrubbed = vault.redact('Send the report to alice@example.com').value;
|
|
53
|
+
const restored = vault.restore(scrubbed);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Python quick start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from redact0 import Vault, redact
|
|
60
|
+
|
|
61
|
+
safe = redact({"email": "alice@example.com"})
|
|
62
|
+
vault = Vault()
|
|
63
|
+
scrubbed = vault.redact("Contact alice@example.com").value
|
|
64
|
+
restored = vault.restore(scrubbed)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Build and verify from this repository
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install
|
|
71
|
+
npm run typecheck
|
|
72
|
+
npm run build
|
|
73
|
+
npm test
|
|
74
|
+
npm run check:size
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Python checks (from the repository root):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python -m venv .venv
|
|
81
|
+
# Windows PowerShell: .venv\Scripts\Activate.ps1
|
|
82
|
+
# macOS/Linux: source .venv/bin/activate
|
|
83
|
+
python -m pip install -e ./python
|
|
84
|
+
python -m pip install pytest
|
|
85
|
+
python -m pytest python/tests
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The Python package itself declares no runtime dependencies. `pytest` is only needed to run its tests.
|
|
89
|
+
|
|
90
|
+
## CLI
|
|
91
|
+
|
|
92
|
+
After building the npm package:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
echo "email: alice@example.com" | node dist/cli.cjs
|
|
96
|
+
npx redact0 init
|
|
97
|
+
npx redact0 scan . --preset secrets
|
|
98
|
+
npx redact0 mcp
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For Python, after installation:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
echo "email: alice@example.com" | redact0
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Exports
|
|
108
|
+
|
|
109
|
+
The npm package defines these subpath exports:
|
|
110
|
+
|
|
111
|
+
- `redact0/stream`
|
|
112
|
+
- `redact0/fhir`
|
|
113
|
+
- `redact0/ai`
|
|
114
|
+
- `redact0/mcp`
|
|
115
|
+
- `redact0/logger`
|
|
116
|
+
|
|
117
|
+
The Python package includes `redact0.compat.llm_guard` for compatibility helpers.
|
|
118
|
+
|
|
119
|
+
## Project layout
|
|
120
|
+
|
|
121
|
+
- `src/`: TypeScript implementation and adapters
|
|
122
|
+
- `tests/`: TypeScript tests
|
|
123
|
+
- `python/src/redact0/`: Python implementation
|
|
124
|
+
- `python/tests/`: Python tests
|
|
125
|
+
- `llms.txt`, `llms-full.txt`, `context7.json`, `AGENTS.md`: AI-agent and documentation discovery resources
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT. See [LICENSE](LICENSE).
|
redact0-1.0.0/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# redact0
|
|
2
|
+
|
|
3
|
+
Zero-runtime-dependency reversible PII, secret, FHIR Safe Harbor and streaming redaction for JavaScript/TypeScript and Python.
|
|
4
|
+
|
|
5
|
+
> Security note: this package is a best-effort detector/redactor, not a compliance certification or a substitute for a privacy/security review. Validate it against your own data and regulatory requirements before production use.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js 18+ for the npm package
|
|
10
|
+
- Python 3.10+ for the PyPI package
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install redact0
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
python -m pip install redact0
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## JavaScript / TypeScript quick start
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { createVault, redact } from 'redact0';
|
|
26
|
+
|
|
27
|
+
const safe = redact({
|
|
28
|
+
email: 'alice@example.com',
|
|
29
|
+
message: 'Contact alice@example.com',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const vault = createVault();
|
|
33
|
+
const scrubbed = vault.redact('Send the report to alice@example.com').value;
|
|
34
|
+
const restored = vault.restore(scrubbed);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Python quick start
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from redact0 import Vault, redact
|
|
41
|
+
|
|
42
|
+
safe = redact({"email": "alice@example.com"})
|
|
43
|
+
vault = Vault()
|
|
44
|
+
scrubbed = vault.redact("Contact alice@example.com").value
|
|
45
|
+
restored = vault.restore(scrubbed)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Build and verify from this repository
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install
|
|
52
|
+
npm run typecheck
|
|
53
|
+
npm run build
|
|
54
|
+
npm test
|
|
55
|
+
npm run check:size
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Python checks (from the repository root):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
python -m venv .venv
|
|
62
|
+
# Windows PowerShell: .venv\Scripts\Activate.ps1
|
|
63
|
+
# macOS/Linux: source .venv/bin/activate
|
|
64
|
+
python -m pip install -e ./python
|
|
65
|
+
python -m pip install pytest
|
|
66
|
+
python -m pytest python/tests
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The Python package itself declares no runtime dependencies. `pytest` is only needed to run its tests.
|
|
70
|
+
|
|
71
|
+
## CLI
|
|
72
|
+
|
|
73
|
+
After building the npm package:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
echo "email: alice@example.com" | node dist/cli.cjs
|
|
77
|
+
npx redact0 init
|
|
78
|
+
npx redact0 scan . --preset secrets
|
|
79
|
+
npx redact0 mcp
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For Python, after installation:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
echo "email: alice@example.com" | redact0
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Exports
|
|
89
|
+
|
|
90
|
+
The npm package defines these subpath exports:
|
|
91
|
+
|
|
92
|
+
- `redact0/stream`
|
|
93
|
+
- `redact0/fhir`
|
|
94
|
+
- `redact0/ai`
|
|
95
|
+
- `redact0/mcp`
|
|
96
|
+
- `redact0/logger`
|
|
97
|
+
|
|
98
|
+
The Python package includes `redact0.compat.llm_guard` for compatibility helpers.
|
|
99
|
+
|
|
100
|
+
## Project layout
|
|
101
|
+
|
|
102
|
+
- `src/`: TypeScript implementation and adapters
|
|
103
|
+
- `tests/`: TypeScript tests
|
|
104
|
+
- `python/src/redact0/`: Python implementation
|
|
105
|
+
- `python/tests/`: Python tests
|
|
106
|
+
- `llms.txt`, `llms-full.txt`, `context7.json`, `AGENTS.md`: AI-agent and documentation discovery resources
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25.0"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "redact0"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Zero-dependency reversible PII, secret, FHIR HIPAA Safe Harbor, and streaming LLM boundary redactor. Drop-in migration for llm-guard."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dependencies = []
|
|
13
|
+
keywords = ["pii", "redaction", "secrets", "hipaa", "fhir", "llm-guard", "gdpr", "ai"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 5 - Production/Stable",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Security",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
redact0 = "redact0.cli:main"
|
|
29
|
+
|
|
30
|
+
[tool.hatch.build.targets.wheel]
|
|
31
|
+
packages = ["src/redact0"]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from .rules import BUILTIN_RULES, DetectorRule
|
|
2
|
+
from .validators import (
|
|
3
|
+
is_valid_aadhaar,
|
|
4
|
+
is_valid_de_tax_id,
|
|
5
|
+
is_valid_dea,
|
|
6
|
+
is_valid_iban,
|
|
7
|
+
is_valid_ipv4,
|
|
8
|
+
is_valid_jwt,
|
|
9
|
+
is_valid_luhn,
|
|
10
|
+
is_valid_mbi,
|
|
11
|
+
is_valid_nhs,
|
|
12
|
+
is_valid_npi,
|
|
13
|
+
is_valid_ssn,
|
|
14
|
+
shannon_entropy,
|
|
15
|
+
)
|
|
16
|
+
from .vault import (
|
|
17
|
+
Finding,
|
|
18
|
+
StreamRestorer,
|
|
19
|
+
Vault,
|
|
20
|
+
create_vault,
|
|
21
|
+
redact,
|
|
22
|
+
redact_detailed,
|
|
23
|
+
redact_fhir,
|
|
24
|
+
scan,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"BUILTIN_RULES",
|
|
29
|
+
"DetectorRule",
|
|
30
|
+
"Finding",
|
|
31
|
+
"StreamRestorer",
|
|
32
|
+
"Vault",
|
|
33
|
+
"create_vault",
|
|
34
|
+
"is_valid_aadhaar",
|
|
35
|
+
"is_valid_de_tax_id",
|
|
36
|
+
"is_valid_dea",
|
|
37
|
+
"is_valid_iban",
|
|
38
|
+
"is_valid_ipv4",
|
|
39
|
+
"is_valid_jwt",
|
|
40
|
+
"is_valid_luhn",
|
|
41
|
+
"is_valid_mbi",
|
|
42
|
+
"is_valid_nhs",
|
|
43
|
+
"is_valid_npi",
|
|
44
|
+
"is_valid_ssn",
|
|
45
|
+
"redact",
|
|
46
|
+
"redact_detailed",
|
|
47
|
+
"redact_fhir",
|
|
48
|
+
"scan",
|
|
49
|
+
"shannon_entropy",
|
|
50
|
+
]
|
|
51
|
+
__version__ = "1.0.0"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from .vault import redact_detailed, scan
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(argv: list[str] | None = None) -> int:
|
|
11
|
+
parser = argparse.ArgumentParser(prog="redact0", description="0-dep reversible PII & secret redactor")
|
|
12
|
+
parser.add_argument("--preset", default="default", choices=["default", "secrets", "hipaa", "gdpr", "strict"])
|
|
13
|
+
parser.add_argument("--scan", action="store_true", help="Output findings metadata as JSON without raw values")
|
|
14
|
+
args = parser.parse_args(argv)
|
|
15
|
+
|
|
16
|
+
text = sys.stdin.read()
|
|
17
|
+
if args.scan:
|
|
18
|
+
findings = [f.__dict__ for f in scan(text, preset=args.preset)]
|
|
19
|
+
print(json.dumps(findings, indent=2))
|
|
20
|
+
return 1 if findings else 0
|
|
21
|
+
|
|
22
|
+
res = redact_detailed(text, preset=args.preset)
|
|
23
|
+
sys.stdout.write(res.value)
|
|
24
|
+
return 0
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Drop-in zero-dependency compatibility layer for archived `llm-guard` (Protect AI).
|
|
3
|
+
Replaces Anonymize / Deanonymize / Sensitive / Vault / scan_prompt / scan_output
|
|
4
|
+
without PyTorch, spaCy, or presidio-anonymizer.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from ..vault import Vault as CoreVault
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Vault(CoreVault):
|
|
14
|
+
"""Drop-in replacement for `llm_guard.vault.Vault`."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Anonymize:
|
|
18
|
+
def __init__(self, vault: CoreVault | None = None, preset: str = "default", **kwargs: Any) -> None:
|
|
19
|
+
self.vault = vault if vault is not None else CoreVault(preset=preset, **kwargs)
|
|
20
|
+
|
|
21
|
+
def scan(self, prompt: str) -> tuple[str, bool, float]:
|
|
22
|
+
res = self.vault.redact_text(prompt)
|
|
23
|
+
is_valid = res.count == 0
|
|
24
|
+
risk_score = 0.0 if is_valid else 1.0
|
|
25
|
+
return res.value, is_valid, risk_score
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Deanonymize:
|
|
29
|
+
def __init__(self, vault: CoreVault) -> None:
|
|
30
|
+
self.vault = vault
|
|
31
|
+
|
|
32
|
+
def scan(self, _prompt: str, output: str) -> tuple[str, bool, float]:
|
|
33
|
+
restored = self.vault.restore(output)
|
|
34
|
+
return restored, True, 0.0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Sensitive:
|
|
38
|
+
def __init__(self, preset: str = "strict", **kwargs: Any) -> None:
|
|
39
|
+
self.vault = CoreVault(preset=preset, **kwargs)
|
|
40
|
+
|
|
41
|
+
def scan(self, _prompt: str, output: str) -> tuple[str, bool, float]:
|
|
42
|
+
res = self.vault.redact_text(output)
|
|
43
|
+
is_valid = res.count == 0
|
|
44
|
+
return res.value, is_valid, 0.0 if is_valid else 1.0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def scan_prompt(scanners: list[Any], prompt: str) -> tuple[str, dict[str, bool], dict[str, float]]:
|
|
48
|
+
current = prompt
|
|
49
|
+
results_valid: dict[str, bool] = {}
|
|
50
|
+
results_score: dict[str, float] = {}
|
|
51
|
+
for scanner in scanners:
|
|
52
|
+
name = type(scanner).__name__
|
|
53
|
+
current, is_valid, score = scanner.scan(current)
|
|
54
|
+
results_valid[name] = is_valid
|
|
55
|
+
results_score[name] = score
|
|
56
|
+
return current, results_valid, results_score
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def scan_output(
|
|
60
|
+
scanners: list[Any], prompt: str, output: str
|
|
61
|
+
) -> tuple[str, dict[str, bool], dict[str, float]]:
|
|
62
|
+
current = output
|
|
63
|
+
results_valid: dict[str, bool] = {}
|
|
64
|
+
results_score: dict[str, float] = {}
|
|
65
|
+
for scanner in scanners:
|
|
66
|
+
name = type(scanner).__name__
|
|
67
|
+
current, is_valid, score = scanner.scan(prompt, current)
|
|
68
|
+
results_valid[name] = is_valid
|
|
69
|
+
results_score[name] = score
|
|
70
|
+
return current, results_valid, results_score
|