dpdp-scrub 0.0.1__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.
- dpdp_scrub-0.0.1/LICENSE +21 -0
- dpdp_scrub-0.0.1/PKG-INFO +164 -0
- dpdp_scrub-0.0.1/README.md +142 -0
- dpdp_scrub-0.0.1/pyproject.toml +35 -0
- dpdp_scrub-0.0.1/setup.cfg +4 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/__init__.py +23 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/data.py +41 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/detectors.py +311 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/integrations.py +73 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/policies.py +27 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/scrubber.py +158 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/spans.py +29 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/validators/__init__.py +28 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/validators/gstin.py +48 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/validators/luhn.py +31 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/validators/pan.py +47 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/validators/verhoeff.py +71 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub/vault.py +94 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub.egg-info/PKG-INFO +164 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub.egg-info/SOURCES.txt +29 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub.egg-info/dependency_links.txt +1 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub.egg-info/requires.txt +5 -0
- dpdp_scrub-0.0.1/src/dpdp_scrub.egg-info/top_level.txt +1 -0
- dpdp_scrub-0.0.1/tests/test_context.py +67 -0
- dpdp_scrub-0.0.1/tests/test_detect.py +99 -0
- dpdp_scrub-0.0.1/tests/test_detect_contact.py +83 -0
- dpdp_scrub-0.0.1/tests/test_detect_docs.py +52 -0
- dpdp_scrub-0.0.1/tests/test_integrations.py +87 -0
- dpdp_scrub-0.0.1/tests/test_policies.py +71 -0
- dpdp_scrub-0.0.1/tests/test_scrub.py +64 -0
- dpdp_scrub-0.0.1/tests/test_validators.py +141 -0
dpdp_scrub-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dpdp-scrub contributors
|
|
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.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dpdp-scrub
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Detect, validate, and redact Indian PII (Aadhaar, PAN, GSTIN, UPI, and more) — self-hosted, checksum-validated, DPDP-ready.
|
|
5
|
+
Author: Palkush Dave
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: pii,dpdp,aadhaar,pan,gstin,privacy,redaction,india
|
|
8
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Security
|
|
13
|
+
Classifier: Topic :: Text Processing
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
19
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
20
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# dpdp-scrub
|
|
24
|
+
|
|
25
|
+
**Detect, validate, and redact Indian PII before it reaches an LLM — self-hosted, checksum-validated, DPDP-ready.**
|
|
26
|
+
|
|
27
|
+
Your org keeps the keys; the LLM gets the placeholders.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
IN : Sir aadhaar 2345 6789 0124 hai, call karo 9876543210 pe, PAN ABCPE1234F
|
|
31
|
+
LLM : Sir aadhaar XXXX XXXX 0124 hai, call karo <PHONE_IN_1> pe, PAN <PAN_1>
|
|
32
|
+
BACK: Done! 9876543210 pe call schedule ho gaya. ← rehydrated, agent-side
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Why this exists
|
|
36
|
+
|
|
37
|
+
Every Indian company wiring LLMs into support, sales, and ops is streaming
|
|
38
|
+
Aadhaar numbers, PANs, GSTINs, UPI IDs, and phone numbers to third-party model
|
|
39
|
+
providers — and copying them into logs, vector DBs, and fine-tuning sets.
|
|
40
|
+
The DPDP Act's substantive obligations become enforceable in **May 2027**
|
|
41
|
+
(penalties up to ₹250 crore); UIDAI's Aadhaar-masking rules and RBI's card
|
|
42
|
+
rules already apply.
|
|
43
|
+
|
|
44
|
+
The redaction loop itself is well-established engineering (Presidio, Google
|
|
45
|
+
DLP). What didn't exist is **eyes that can see Indian PII** — validated,
|
|
46
|
+
context-aware, and open. Google Cloud DLP ships 3 Indian infoTypes, AWS
|
|
47
|
+
Comprehend 4, Presidio 6. dpdp-scrub detects **15**, most with mathematical
|
|
48
|
+
or reference-data validation:
|
|
49
|
+
|
|
50
|
+
| Entity | Validation |
|
|
51
|
+
|---|---|
|
|
52
|
+
| Aadhaar / Aadhaar VID | **Verhoeff checksum** + first-digit rule |
|
|
53
|
+
| GSTIN | **mod-36 check character** + embedded-PAN structure + state code |
|
|
54
|
+
| Credit/debit card | **Luhn checksum** |
|
|
55
|
+
| PAN | holder-type structure rule |
|
|
56
|
+
| UPI ID | handle verified against **known PSP list** (`@ybl`, `@oksbi`, …) |
|
|
57
|
+
| IFSC, phone, email, voter ID, passport | structural + context scoring |
|
|
58
|
+
| Vehicle registration | state/RTO code verified against reference list (incl. BH series) |
|
|
59
|
+
| Bank account, EPF UAN, ABHA | **context-required** (surface only with evidence like "A/c", "UAN") |
|
|
60
|
+
|
|
61
|
+
The context engine is what separates a phone number from an order ID:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
order 9876543210 ka status batao → nothing (suppressed by "order")
|
|
65
|
+
call karo 9876543210 pe → PHONE_IN 0.99 (boosted by "call")
|
|
66
|
+
mera a/c 34512345678901 hai → BANK_ACCOUNT (earned by "a/c")
|
|
67
|
+
code 34512345678901 likha hai → nothing
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from dpdp_scrub import Scrubber
|
|
74
|
+
|
|
75
|
+
s = Scrubber()
|
|
76
|
+
|
|
77
|
+
result = s.scrub("mera PAN ABCPE1234F hai, call 9876543210", session_id="ticket-42")
|
|
78
|
+
result.text # "mera PAN <PAN_1> hai, call <PHONE_IN_1>"
|
|
79
|
+
result.spans # typed spans: entity, offsets, confidence
|
|
80
|
+
|
|
81
|
+
reply = call_your_llm(result.text) # provider never sees real values
|
|
82
|
+
s.rehydrate(reply, "ticket-42") # real values restored, your side only
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Detection only:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from dpdp_scrub import detect
|
|
89
|
+
detect("payment 9876543210@ybl pe karo")
|
|
90
|
+
# [Span(entity='UPI_ID', start=8, end=22, ..., confidence=0.92)]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Zero runtime dependencies. Python 3.9+.
|
|
94
|
+
|
|
95
|
+
## Trust model
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
Ring 0: the vault (your Redis/memory) — real values, session-scoped, droppable
|
|
99
|
+
Ring 1: your org's services — placeholders + scoped right to resolve
|
|
100
|
+
Ring 2: LLM providers, logs, vector DBs — placeholders only, no resolution path
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- Same value → same placeholder within a session (multi-turn consistency).
|
|
104
|
+
- `vault.drop(session)` makes every old copy of its placeholders permanently
|
|
105
|
+
unresolvable — retroactive redaction for logs you already wrote.
|
|
106
|
+
- No cloud, no telemetry, no phoning home. This is a library, not a service:
|
|
107
|
+
**your data never leaves your infrastructure.**
|
|
108
|
+
|
|
109
|
+
Per-entity actions are policy: `tokenize` (reversible), `mask` (UIDAI-format
|
|
110
|
+
`XXXX XXXX 0124` for Aadhaar, last-4 for cards), `redact` (ABHA health IDs by
|
|
111
|
+
default), `ignore`.
|
|
112
|
+
|
|
113
|
+
## Benchmark
|
|
114
|
+
|
|
115
|
+
IndicPII-Bench v0 (in `bench/`): 500 synthetic messages — Hinglish, English,
|
|
116
|
+
Devanagari, OCR-noise spacing, multi-entity — with 20% traps (order IDs,
|
|
117
|
+
invoice refs, phones-in-txn-context). Presidio runs at its best
|
|
118
|
+
configuration — its IN_* recognizers explicitly registered (they are shipped
|
|
119
|
+
but **not loaded by default**). F1, value-level matching:
|
|
120
|
+
|
|
121
|
+
| entity | dpdp-scrub | presidio |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| AADHAAR | **1.000** | 1.000 |
|
|
124
|
+
| GSTIN | **1.000** | 0.971 |
|
|
125
|
+
| PAN | **1.000** | 0.383 |
|
|
126
|
+
| PHONE_IN | **1.000** | 0.602 |
|
|
127
|
+
| UPI_ID | **1.000** | 0.000 |
|
|
128
|
+
| IFSC | **1.000** | 0.000 |
|
|
129
|
+
| EMAIL | **1.000** | 1.000 |
|
|
130
|
+
| **OVERALL** | **1.000** | 0.595 |
|
|
131
|
+
| trap false positives | **0/100** | 200/100 |
|
|
132
|
+
|
|
133
|
+
Honest caveats: this is our own v0 corpus (templated, synthetic, Hinglish-
|
|
134
|
+
heavy) — a perfect self-score mainly means the corpus is still too easy, and
|
|
135
|
+
it will get harder (Devanagari, OCR noise, multi-entity). Presidio was not
|
|
136
|
+
built for code-mixed text; the 107 trap FPs come from it having no context
|
|
137
|
+
suppression (e.g. any 10-digit number near "txn" flags as phone). Reproduce:
|
|
138
|
+
`python3 bench/compare.py 500`.
|
|
139
|
+
|
|
140
|
+
## Status
|
|
141
|
+
|
|
142
|
+
Pre-alpha, moving fast. Built so far: 15 entities, checksum validators,
|
|
143
|
+
context-scoring engine, scrub/rehydrate loop with session vault — 86 tests,
|
|
144
|
+
all synthetic data. Roadmap:
|
|
145
|
+
|
|
146
|
+
- [ ] YAML policy profiles (`dpdp-strict`, `uidai-mask`, `audit-only`) + audit log
|
|
147
|
+
- [ ] `scrub_json()` for structured payloads
|
|
148
|
+
- [ ] Redis vault backend
|
|
149
|
+
- [ ] LiteLLM / LangChain / Presidio adapters
|
|
150
|
+
- [ ] **IndicPII-Bench** — a public benchmark for Indian PII detection
|
|
151
|
+
- [ ] Indic-script & code-mixed NER for names/addresses (AI4Bharat IndicNER)
|
|
152
|
+
|
|
153
|
+
## Contributing
|
|
154
|
+
|
|
155
|
+
The reference-data files are designed for one-line PRs: new UPI PSP handles,
|
|
156
|
+
RTO codes, context words (English/Hindi/regional). Entity requests welcome —
|
|
157
|
+
include format, any checksum, and public documentation.
|
|
158
|
+
|
|
159
|
+
All test data must be synthetic (checksum-generated) or published samples.
|
|
160
|
+
Never commit real PII, including your own.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# dpdp-scrub
|
|
2
|
+
|
|
3
|
+
**Detect, validate, and redact Indian PII before it reaches an LLM — self-hosted, checksum-validated, DPDP-ready.**
|
|
4
|
+
|
|
5
|
+
Your org keeps the keys; the LLM gets the placeholders.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
IN : Sir aadhaar 2345 6789 0124 hai, call karo 9876543210 pe, PAN ABCPE1234F
|
|
9
|
+
LLM : Sir aadhaar XXXX XXXX 0124 hai, call karo <PHONE_IN_1> pe, PAN <PAN_1>
|
|
10
|
+
BACK: Done! 9876543210 pe call schedule ho gaya. ← rehydrated, agent-side
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Why this exists
|
|
14
|
+
|
|
15
|
+
Every Indian company wiring LLMs into support, sales, and ops is streaming
|
|
16
|
+
Aadhaar numbers, PANs, GSTINs, UPI IDs, and phone numbers to third-party model
|
|
17
|
+
providers — and copying them into logs, vector DBs, and fine-tuning sets.
|
|
18
|
+
The DPDP Act's substantive obligations become enforceable in **May 2027**
|
|
19
|
+
(penalties up to ₹250 crore); UIDAI's Aadhaar-masking rules and RBI's card
|
|
20
|
+
rules already apply.
|
|
21
|
+
|
|
22
|
+
The redaction loop itself is well-established engineering (Presidio, Google
|
|
23
|
+
DLP). What didn't exist is **eyes that can see Indian PII** — validated,
|
|
24
|
+
context-aware, and open. Google Cloud DLP ships 3 Indian infoTypes, AWS
|
|
25
|
+
Comprehend 4, Presidio 6. dpdp-scrub detects **15**, most with mathematical
|
|
26
|
+
or reference-data validation:
|
|
27
|
+
|
|
28
|
+
| Entity | Validation |
|
|
29
|
+
|---|---|
|
|
30
|
+
| Aadhaar / Aadhaar VID | **Verhoeff checksum** + first-digit rule |
|
|
31
|
+
| GSTIN | **mod-36 check character** + embedded-PAN structure + state code |
|
|
32
|
+
| Credit/debit card | **Luhn checksum** |
|
|
33
|
+
| PAN | holder-type structure rule |
|
|
34
|
+
| UPI ID | handle verified against **known PSP list** (`@ybl`, `@oksbi`, …) |
|
|
35
|
+
| IFSC, phone, email, voter ID, passport | structural + context scoring |
|
|
36
|
+
| Vehicle registration | state/RTO code verified against reference list (incl. BH series) |
|
|
37
|
+
| Bank account, EPF UAN, ABHA | **context-required** (surface only with evidence like "A/c", "UAN") |
|
|
38
|
+
|
|
39
|
+
The context engine is what separates a phone number from an order ID:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
order 9876543210 ka status batao → nothing (suppressed by "order")
|
|
43
|
+
call karo 9876543210 pe → PHONE_IN 0.99 (boosted by "call")
|
|
44
|
+
mera a/c 34512345678901 hai → BANK_ACCOUNT (earned by "a/c")
|
|
45
|
+
code 34512345678901 likha hai → nothing
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from dpdp_scrub import Scrubber
|
|
52
|
+
|
|
53
|
+
s = Scrubber()
|
|
54
|
+
|
|
55
|
+
result = s.scrub("mera PAN ABCPE1234F hai, call 9876543210", session_id="ticket-42")
|
|
56
|
+
result.text # "mera PAN <PAN_1> hai, call <PHONE_IN_1>"
|
|
57
|
+
result.spans # typed spans: entity, offsets, confidence
|
|
58
|
+
|
|
59
|
+
reply = call_your_llm(result.text) # provider never sees real values
|
|
60
|
+
s.rehydrate(reply, "ticket-42") # real values restored, your side only
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Detection only:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from dpdp_scrub import detect
|
|
67
|
+
detect("payment 9876543210@ybl pe karo")
|
|
68
|
+
# [Span(entity='UPI_ID', start=8, end=22, ..., confidence=0.92)]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Zero runtime dependencies. Python 3.9+.
|
|
72
|
+
|
|
73
|
+
## Trust model
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Ring 0: the vault (your Redis/memory) — real values, session-scoped, droppable
|
|
77
|
+
Ring 1: your org's services — placeholders + scoped right to resolve
|
|
78
|
+
Ring 2: LLM providers, logs, vector DBs — placeholders only, no resolution path
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- Same value → same placeholder within a session (multi-turn consistency).
|
|
82
|
+
- `vault.drop(session)` makes every old copy of its placeholders permanently
|
|
83
|
+
unresolvable — retroactive redaction for logs you already wrote.
|
|
84
|
+
- No cloud, no telemetry, no phoning home. This is a library, not a service:
|
|
85
|
+
**your data never leaves your infrastructure.**
|
|
86
|
+
|
|
87
|
+
Per-entity actions are policy: `tokenize` (reversible), `mask` (UIDAI-format
|
|
88
|
+
`XXXX XXXX 0124` for Aadhaar, last-4 for cards), `redact` (ABHA health IDs by
|
|
89
|
+
default), `ignore`.
|
|
90
|
+
|
|
91
|
+
## Benchmark
|
|
92
|
+
|
|
93
|
+
IndicPII-Bench v0 (in `bench/`): 500 synthetic messages — Hinglish, English,
|
|
94
|
+
Devanagari, OCR-noise spacing, multi-entity — with 20% traps (order IDs,
|
|
95
|
+
invoice refs, phones-in-txn-context). Presidio runs at its best
|
|
96
|
+
configuration — its IN_* recognizers explicitly registered (they are shipped
|
|
97
|
+
but **not loaded by default**). F1, value-level matching:
|
|
98
|
+
|
|
99
|
+
| entity | dpdp-scrub | presidio |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| AADHAAR | **1.000** | 1.000 |
|
|
102
|
+
| GSTIN | **1.000** | 0.971 |
|
|
103
|
+
| PAN | **1.000** | 0.383 |
|
|
104
|
+
| PHONE_IN | **1.000** | 0.602 |
|
|
105
|
+
| UPI_ID | **1.000** | 0.000 |
|
|
106
|
+
| IFSC | **1.000** | 0.000 |
|
|
107
|
+
| EMAIL | **1.000** | 1.000 |
|
|
108
|
+
| **OVERALL** | **1.000** | 0.595 |
|
|
109
|
+
| trap false positives | **0/100** | 200/100 |
|
|
110
|
+
|
|
111
|
+
Honest caveats: this is our own v0 corpus (templated, synthetic, Hinglish-
|
|
112
|
+
heavy) — a perfect self-score mainly means the corpus is still too easy, and
|
|
113
|
+
it will get harder (Devanagari, OCR noise, multi-entity). Presidio was not
|
|
114
|
+
built for code-mixed text; the 107 trap FPs come from it having no context
|
|
115
|
+
suppression (e.g. any 10-digit number near "txn" flags as phone). Reproduce:
|
|
116
|
+
`python3 bench/compare.py 500`.
|
|
117
|
+
|
|
118
|
+
## Status
|
|
119
|
+
|
|
120
|
+
Pre-alpha, moving fast. Built so far: 15 entities, checksum validators,
|
|
121
|
+
context-scoring engine, scrub/rehydrate loop with session vault — 86 tests,
|
|
122
|
+
all synthetic data. Roadmap:
|
|
123
|
+
|
|
124
|
+
- [ ] YAML policy profiles (`dpdp-strict`, `uidai-mask`, `audit-only`) + audit log
|
|
125
|
+
- [ ] `scrub_json()` for structured payloads
|
|
126
|
+
- [ ] Redis vault backend
|
|
127
|
+
- [ ] LiteLLM / LangChain / Presidio adapters
|
|
128
|
+
- [ ] **IndicPII-Bench** — a public benchmark for Indian PII detection
|
|
129
|
+
- [ ] Indic-script & code-mixed NER for names/addresses (AI4Bharat IndicNER)
|
|
130
|
+
|
|
131
|
+
## Contributing
|
|
132
|
+
|
|
133
|
+
The reference-data files are designed for one-line PRs: new UPI PSP handles,
|
|
134
|
+
RTO codes, context words (English/Hindi/regional). Entity requests welcome —
|
|
135
|
+
include format, any checksum, and public documentation.
|
|
136
|
+
|
|
137
|
+
All test data must be synthetic (checksum-generated) or published samples.
|
|
138
|
+
Never commit real PII, including your own.
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
MIT
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dpdp-scrub"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "Detect, validate, and redact Indian PII (Aadhaar, PAN, GSTIN, UPI, and more) — self-hosted, checksum-validated, DPDP-ready."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [{ name = "Palkush Dave" }]
|
|
13
|
+
keywords = ["pii", "dpdp", "aadhaar", "pan", "gstin", "privacy", "redaction", "india"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Security",
|
|
20
|
+
"Topic :: Text Processing",
|
|
21
|
+
]
|
|
22
|
+
dependencies = []
|
|
23
|
+
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
dev = ["pytest>=8", "ruff>=0.4", "mypy>=1.10"]
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.packages.find]
|
|
28
|
+
where = ["src"]
|
|
29
|
+
|
|
30
|
+
[tool.pytest.ini_options]
|
|
31
|
+
testpaths = ["tests"]
|
|
32
|
+
|
|
33
|
+
[tool.ruff]
|
|
34
|
+
line-length = 100
|
|
35
|
+
src = ["src", "tests"]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""dpdp-scrub: detect, validate, and redact Indian PII.
|
|
2
|
+
|
|
3
|
+
Self-hosted, checksum-validated, DPDP-ready. The LLM never sees the real value;
|
|
4
|
+
your systems still do.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__version__ = "0.0.1"
|
|
8
|
+
|
|
9
|
+
from . import validators
|
|
10
|
+
from .detectors import detect
|
|
11
|
+
from .scrubber import Scrubber, ScrubResult
|
|
12
|
+
from .spans import Span
|
|
13
|
+
from .vault import MemoryVault
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"validators",
|
|
17
|
+
"detect",
|
|
18
|
+
"Scrubber",
|
|
19
|
+
"ScrubResult",
|
|
20
|
+
"MemoryVault",
|
|
21
|
+
"Span",
|
|
22
|
+
"__version__",
|
|
23
|
+
]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Reference data for detectors.
|
|
2
|
+
|
|
3
|
+
These are public identifiers of payment infrastructure (PSP handles), not PII.
|
|
4
|
+
Community-maintainable: adding a new UPI handle is a one-line PR.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Known UPI PSP handles (the part after '@' in a VPA). Not exhaustive —
|
|
8
|
+
# curated from NPCI's ecosystem. The handle list is what separates a UPI ID
|
|
9
|
+
# from an email-shaped string, so keep entries lowercase and dot-free.
|
|
10
|
+
UPI_PSP_HANDLES = frozenset(
|
|
11
|
+
{
|
|
12
|
+
# PhonePe
|
|
13
|
+
"ybl", "ibl", "axl",
|
|
14
|
+
# Google Pay
|
|
15
|
+
"okaxis", "okhdfcbank", "okicici", "oksbi",
|
|
16
|
+
# Paytm
|
|
17
|
+
"paytm", "ptyes", "ptaxis", "pthdfc", "ptsbi",
|
|
18
|
+
# Amazon Pay
|
|
19
|
+
"apl", "yapl", "rapl",
|
|
20
|
+
# WhatsApp Pay
|
|
21
|
+
"waaxis", "wahdfcbank", "waicici", "wasbi",
|
|
22
|
+
# Bank / app handles
|
|
23
|
+
"upi", "sbi", "hdfcbank", "icici", "axisbank", "barodampay",
|
|
24
|
+
"fbl", "idfcbank", "indus", "kotak", "dbs", "yesbank", "rbl",
|
|
25
|
+
"aubank", "bandhan", "federal", "uboi", "cnrb", "pnb", "boi",
|
|
26
|
+
# Apps
|
|
27
|
+
"freecharge", "mobikwik", "airtel", "jio", "slice", "jupiteraxis",
|
|
28
|
+
"naviaxis", "niyoicici", "tapicici", "timecosmos", "zoicici",
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# RTO state/UT codes for vehicle registration plates, plus the BH (Bharat)
|
|
33
|
+
# series. Includes legacy codes still on the road (OR, UA, TS).
|
|
34
|
+
VEHICLE_STATE_CODES = frozenset(
|
|
35
|
+
{
|
|
36
|
+
"AN", "AP", "AR", "AS", "BR", "CG", "CH", "DD", "DL", "DN", "GA",
|
|
37
|
+
"GJ", "HP", "HR", "JH", "JK", "KA", "KL", "LA", "LD", "MH", "ML",
|
|
38
|
+
"MN", "MP", "MZ", "NL", "OD", "OR", "PB", "PY", "RJ", "SK", "TN",
|
|
39
|
+
"TR", "TS", "TG", "UK", "UA", "UP", "WB",
|
|
40
|
+
}
|
|
41
|
+
)
|