cgh-pii
PII and secret detection for cgh. Once installed, every indexed file is scanned inline for personal data and credentials, and the results land in the finding store:
pip install cgh-pii
cgh index
cgh findings --key pii. # emails, phones, IBANs, cards per file
cgh findings --severity block # private keys, cloud credentials
Detected keys and their severities:
| Key | What | Severity |
|---|---|---|
pii.email |
email addresses | warn |
pii.phone |
international-format phone numbers | warn |
pii.iban |
IBANs, mod-97 validated | warn |
pii.card |
payment card numbers, Luhn validated | warn |
secret.aws_key |
AWS access key ids | block |
secret.private_key |
PEM private key blocks | block |
secret.assignment |
password = "..." style hardcoded credentials |
warn |
Two deliberate properties:
- Finding values never contain the matched data. A finding stores the match count and the first line number, not the email or the IBAN itself: findings feed the full-text index and must not spread what they detect.
- Validation over recall. Cards must pass Luhn, IBANs must pass mod 97, so a random digit run does not flag a file.
The optional NER tier (person names, locations) installs with
pip install "cgh-pii[ner]" and activates with ner = true under
[plugin.pii]; it runs deferred, off the indexing hot path.
The optional LLM tier
A third tier probes each file with a local or configured LLM and flags
the PII the regex and NER tiers miss: names in unusual formats,
quasi-identifiers, postal addresses, context-bound identifiers. It needs
no extra package (a stdlib HTTP client), only a reachable model. Turn it
on under [plugin.pii]:
[plugin.pii]
llm = true
llm_ollama_url = "http://127.0.0.1:11434" # default; a loopback URL
llm_model = "qwen2.5:3b" # any text model you have
# or an OpenAI-compatible endpoint instead of Ollama:
# llm_openai_base_url = "https://llm.internal.acme/v1"
# llm_openai_model = "acme-cor"
# llm_openai_api_key_env = "ACME_LLM_KEY"
Like NER, it runs deferred, never on the inline hot path (an LLM call
per file is heavy), and its findings carry only a count
(pii.llm.person, pii.llm.other, ...), never the matched text.
Egress is gated. Probing a file sends its content to the model. A
loopback endpoint stays on the machine and is free. A non-loopback
endpoint (an enterprise LLM) is egress: it is refused unless you set
pii_llm_allow_remote = true, and every probe, allowed or denied, is
written to the activity log. The endpoint scheme is pinned to http/https.
This mirrors the fetch_and_index egress gate: nothing leaves without an
explicit opt-in, and every departure is audited.
Try it on one file before trusting it, without redacting anything:
cgh pii probe contract.md # lists what the LLM tier would flag
cgh pii redact contract.md --llm --out contract.anon.md
A quote the model invents (not present verbatim in the file) redacts
nothing, so a hallucination can never anonymize the wrong bytes. On the
redact path the LLM categories fold into the redactor's set, with a
catch-all other ([OTHER_1]) for id numbers, org names and
credentials. --llm is wired for text and markdown; docx redaction still
uses the regex and NER tiers only.
Redacting a document
Beyond detecting PII, cgh-pii can produce an anonymized copy of a text or markdown file:
cgh pii redact contract.md --only person --out contract.anon.md
cgh pii redact notes.txt --mode pseudonym --in-place
cgh pii redact report.docx --only person --out report.anon.docx
--only limits the categories (person, location, email,
phone, iban, card, aws_key, private_key; default: all).
--mode placeholder (default) writes numbered tags [PERSON_1],
distinct within the document; --mode pseudonym writes a keyed
<pii.person:hex>, the same token for the same value across documents
when you export a stable CGH_REDACT_SECRET (16+ chars). From code:
codegraph.sdk.redact_text(text, only=["person"]).
Two things to know:
- Names need the NER tier (
pip install "cgh-pii[ner]"). The regex tier does not detect person names; requestingpersonorlocationwithout NER fails with a clear message. Once a name is detected, every literal re-occurrence of it is redacted too, since NER can miss repeat mentions. - Text, markdown and docx. Word documents are redacted with the
docxextra (pip install "cgh-pii[docx]"), body paragraphs and table cells, one shared token map across the whole file. Formatting inside a changed paragraph is flattened (it is the only way to redact PII split across runs, like a bold surname); unchanged paragraphs keep their formatting. A docx needs--outor--in-place. PDF is not supported: real pdf redaction needs an AGPL library; extract the pdf text (see cgh-docs) and redact that.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cgh_pii-0.3.1.tar.gz.
File metadata
- Download URL: cgh_pii-0.3.1.tar.gz
- Upload date:
- Size: 24.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf4dae39a9a6711642b34ed705f709f6e06a21fa2be62b6c629ee348deb70e4b
|
|
| MD5 |
35883f85286d08d35923fe7107ef5108
|
|
| BLAKE2b-256 |
46caf2b03ccef66793518ae5caa90ff369824e9764f0bfb7f4b178015b3426c0
|
Provenance
The following attestation bundles were made for cgh_pii-0.3.1.tar.gz:
Publisher:
release.yml on altikva/cgh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cgh_pii-0.3.1.tar.gz -
Subject digest:
bf4dae39a9a6711642b34ed705f709f6e06a21fa2be62b6c629ee348deb70e4b - Sigstore transparency entry: 2468026009
- Sigstore integration time:
-
Permalink:
altikva/cgh@4f56dc1fc43842b4450bc5bf94136f1dc3db4701 -
Branch / Tag:
refs/tags/v0.11.4 - Owner: https://github.com/altikva
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4f56dc1fc43842b4450bc5bf94136f1dc3db4701 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cgh_pii-0.3.1-py3-none-any.whl.
File metadata
- Download URL: cgh_pii-0.3.1-py3-none-any.whl
- Upload date:
- Size: 21.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a91406adb20204d5182d588a07f49fd7fa770bb9302ba1f2ccb1a0082ae1a0c
|
|
| MD5 |
51df7405a44f8e3a84e73032c4a45222
|
|
| BLAKE2b-256 |
af8c05956e47fea30d20f31a9195bd6a64d356b438ebed83805c1de91177f39e
|
Provenance
The following attestation bundles were made for cgh_pii-0.3.1-py3-none-any.whl:
Publisher:
release.yml on altikva/cgh
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cgh_pii-0.3.1-py3-none-any.whl -
Subject digest:
0a91406adb20204d5182d588a07f49fd7fa770bb9302ba1f2ccb1a0082ae1a0c - Sigstore transparency entry: 2468026017
- Sigstore integration time:
-
Permalink:
altikva/cgh@4f56dc1fc43842b4450bc5bf94136f1dc3db4701 -
Branch / Tag:
refs/tags/v0.11.4 - Owner: https://github.com/altikva
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4f56dc1fc43842b4450bc5bf94136f1dc3db4701 -
Trigger Event:
push
-
Statement type: