Skip to main content

glpi-anonymizer

Strip personal data out of GLPI ticket exports — with real Moroccan identifiers (CIN, RIB, ICE, GSM) and check-digit validation.

CI PyPI Python License Typed

No dependencies. Nothing leaves your machine.


The problem

You want to analyse your helpdesk tickets — train a classifier, measure resolution times, share a sample with a vendor. The tickets are full of phone numbers, ID card numbers and bank details typed in by users, so you cannot.

Generic PII tools know about US Social Security numbers and miss a Moroccan CIN entirely. Tools that do match local formats tend to match too much: any 24-digit string becomes a "bank account", and your asset tags get shredded.

The approach: validate, don't just match

Every identifier that carries a check digit is verified before it is treated as personal data:

Identifier Shape Validated
RIB (Moroccan bank account) 24 digits ✅ mod-97 check key
IBAN MA + 26 chars ✅ ISO 7064 MOD-97-10
Card number 12–19 digits ✅ Luhn
ICE (company id) 15 digits pattern
CIN (national ID) 1–2 letters + 5–6 digits pattern
GSM / landline +212 / 0 + 5,6,7 + 8 digits pattern
Email · URL · IPv4 — pattern (IPv4 range-checked)

The effect: of 200 arbitrary 24-digit numbers, at least 190 are correctly left alone, because only about 1 in 97 can carry a valid key. Your inventory references survive; the bank details do not.

Installation

pip install glpi-anonymizer

Use it from the command line

# Straight redaction
glpi-anonymize tickets.json -o clean.json

# Keep records linkable without revealing anything
export GLPI_ANONYMIZER_KEY="a long random secret"
glpi-anonymize tickets.json -s pseudonymize -o clean.json --stats

# Leave a recognisable tail for support staff
glpi-anonymize tickets.json -s partial --keep 4 -o clean.json

It reads either a plain list of tickets or GLPI's {"data": [...]} envelope, and writes the same shape back. - reads stdin.

Use it from Python

from glpi_anonymizer import Anonymizer

anonymizer = Anonymizer()

result = anonymizer.anonymize("Call A123456 on 0612345678 or a.b@example.ma")
print(result.text)
# Call [CIN] on [PHONE] or [EMAIL]
print(result.counts_by_label())
# {<Label.CIN: 'CIN'>: 1, <Label.PHONE: 'PHONE'>: 1, <Label.EMAIL: 'EMAIL'>: 1}

clean_tickets, matches = anonymizer.anonymize_tickets(tickets)

Three replacement strategies

Strategy 0612345678 becomes Use when
Redact() (default) [PHONE] you just need the data gone
Pseudonymize(key=...) [PHONE:4f2a9c1b] you still need to count per person
PartialMask(keep=4) ******5678 a human has to recognise the record

Pseudonymize is an HMAC of the normalized value, so the same number always yields the same token — across tickets, across files, across runs — while the original cannot be recovered. Normalisation means 06 12 34 56 78 and 0612345678 collapse to one token.

Keep the key secret. Identifier spaces are small enough to enumerate: anyone holding the key can confirm whether a given CIN is in your dataset.

Works with glpi-rest

Pull tickets and clean them in one pass:

from glpi_rest import GLPIClient
from glpi_anonymizer import Anonymizer

anonymizer = Anonymizer()
with GLPIClient(url, app_token=..., user_token=...) as glpi:
    tickets = glpi.get_items("Ticket", range="0-999")
    clean, matches = anonymizer.anonymize_tickets(tickets)

print(f"{len(matches)} values removed from {len(clean)} tickets")

How it works

graph LR
    IN["Ticket text<br/><i>Call A123456 on 0612345678</i>"]

    subgraph DETECT["1 · Detect"]
        PAT["Patterns<br/>CIN · GSM · RIB · ICE<br/>IBAN · card · email · IP · URL"]
        CHK["Check digits<br/>mod-97 · Luhn<br/><b>rejects look-alikes</b>"]
    end

    RES["2 · Resolve overlaps<br/>longest match wins<br/>RIB before ICE"]

    subgraph REPL["3 · Replace"]
        R1["Redact<br/>[PHONE]"]
        R2["Pseudonymize<br/>[PHONE:4f2a9c1b]"]
        R3["PartialMask<br/>******5678"]
    end

    OUT["Clean text + audit trail<br/><i>Call [CIN] on [PHONE]</i>"]

    IN --> PAT --> CHK --> RES
    RES --> R1 & R2 & R3 --> OUT

    style DETECT fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px
    style REPL fill:#e6f4ea,stroke:#1e8e3e,stroke-width:2px
    style CHK fill:#fce8e6,stroke:#d93025,stroke-width:2px
    style OUT fill:#fef7e0,stroke:#f9ab00,stroke-width:2px

Overlaps are resolved before anything is replaced: the longest match wins, ties go to the higher-priority detector. That is why a 24-digit RIB is never carved up into a 15-digit "ICE".

Anonymizing an already-anonymized export is a no-op, so re-running the tool is safe.

Limitations — read before relying on this

This is a deterministic pattern matcher, not a language model. It does not detect:

  • Names of people, which need named-entity recognition;
  • addresses written in prose;
  • personal details described rather than written as an identifier ("the manager on the third floor");
  • identifiers split across lines or mangled by copy-paste.

Treat it as a strong first pass that removes structured identifiers reliably, not as a guarantee that a document is anonymous. Review a sample of the output before publishing anything. Under GDPR and Moroccan law 09-08, pseudonymized data is still personal data.

Security

No network access, no telemetry, no dependencies — the whole pipeline runs locally and the source is short enough to audit. See SECURITY.md.

Contributing

New detectors for other Maghreb identifiers are very welcome — see CONTRIBUTING.md.

git clone https://github.com/novagiosAI/glpi-anonymizer.git
cd glpi-anonymizer
python -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest

License

Apache License 2.0 — free for commercial use.


Built and maintained by Novagios — IT services, AI and ITSM.

Metadata

Release files for glpi-anonymizer 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for glpi-anonymizer 0.1.0
File Size Uploaded Provenance
glpi_anonymizer-0.1.0.tar.gz 21.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for glpi-anonymizer 0.1.0
File Interpreter ABI Platform
glpi_anonymizer-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.8 kB

Release files / glpi_anonymizer-0.1.0.tar.gz

Download URL glpi_anonymizer-0.1.0.tar.gz
Size 21.9 kB
Tags Source
SHA-256 checksum
How to use checksums
15b2cb6f6e71e5a2b9e0b1b961d37e82f9faff23174cc2dae6ec173531917285
BLAKE2b-256 checksum
How to use checksums
ddefac2cb1a4b4f6d6431d7795a1e1a9e7e84a1ded4155f924f85fa8c4a56067
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / glpi_anonymizer-0.1.0-py3-none-any.whl

Download URL glpi_anonymizer-0.1.0-py3-none-any.whl
Size 17.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3895b505a9fbfbf255eb33b2948acf8cfbd860a81ed399ffb3cffe7ac2b581c9
BLAKE2b-256 checksum
How to use checksums
add5b2cbd8976ca056a73a06044b19ca2cdddd9afaa4605cc67d6da8730578cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Security for glpi-anonymizer 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for glpi_anonymizer-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page