Metadata-Version: 2.5
Name: dora-lei-check
Version: 0.1.0
Summary: Check the LEIs in your DORA Register of Information against GLEIF before you submit. Runs locally.
Project-URL: Homepage, https://github.com/kakoullig-hue/dora-lei-check
Project-URL: Issues, https://github.com/kakoullig-hue/dora-lei-check/issues
Author: George Kakoullis
License: MIT
License-File: LICENSE
Keywords: compliance,dora,gleif,lei,regtech,regulatory-reporting,xbrl
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# dora-lei-check

**Check every LEI in your DORA Register of Information against GLEIF before you submit it — on your own machine.**

A lapsed LEI is perfectly well-formed. It passes the checksum. It passes offline
XBRL validation. And it is a **hard rejection** when the ESAs run their business
checks against GLEIF after you submit.

That is a slow, expensive way to find out. This tool tells you in seconds.

```console
$ dora-lei-check register.zip

LEI                   VERDICT     GLEIF STATUS  LEGAL NAME
--------------------  ----------  ------------  ----------------------
254900ZD9J74PNOI5L11  NOT ISSUED  LAPSED        VARANDO LTD
5493001KJTIIGC8Y1R12  OK          ISSUED        Bloomberg Finance L.P.
5493001KJTIIGC8Y1R13  INVALID     invalid checksum  —
984500914ED4D50AZ405  NOT ISSUED  LAPSED        BONOCAP LTD

4 distinct LEI(s): 1 OK, 3 failing, 0 unverified

These will be rejected at submission:
  254900ZD9J74PNOI5L11  NOT ISSUED  found in b_05.01.csv:LEI of the ICT third-party service provider
  5493001KJTIIGC8Y1R13  INVALID     found in b_05.01.csv:LEI of the ICT third-party service provider
  984500914ED4D50AZ405  NOT ISSUED  found in b_05.01.csv:LEI of the ICT third-party service provider
```

Exit code `1` when something will be rejected, so it works as a pre-submission
gate in CI.

## Why this exists

In the ESAs' dry run, **93.5% of submissions carried at least one data error**
and only 6.5% passed all 116 data-quality checks. In the first live cycle,
supervisors reported **missing or invalid LEIs in roughly a third of
submissions** — one of the top hard-rejection causes.

The LEI-versus-GLEIF check is an *external lookup*. The ESAs run it on their
side, **after** you have submitted. Until then you are guessing.

## Your register never leaves your machine

This matters more than it sounds. Your Register of Information is a complete map
of your ICT third-party estate — every provider, every contract, every
criticality assessment. The other pre-submission validators are hosted web
tools: you upload that file to someone else's server.

`dora-lei-check` reads the register locally. The only thing that goes over the
wire is the public 20-character LEI codes, to GLEIF's free public API. With
`--offline` and GLEIF's daily bulk file, nothing goes over the wire at all.

## Install

```console
pip install dora-lei-check
```

Python 3.10+. **Zero dependencies** — nothing for your security team to vet.

## Use

```console
dora-lei-check register.zip              # a submitted xBRL-CSV package
dora-lei-check ./templates/              # a folder of RoI CSV templates
dora-lei-check b_05.01.csv               # a single template

dora-lei-check register.zip --json       # machine-readable, for pipelines
dora-lei-check register.zip --offline gleif-golden-copy.csv   # no network at all
```

| Exit code | Meaning |
|---|---|
| `0` | every LEI is issued and active |
| `1` | at least one LEI will be rejected |
| `2` | some LEIs could not be verified (network) — never silently a pass |
| `3` | the register could not be read |

Results are cached on disk, so re-runs during a correction cycle are instant.

### As a library

```python
from pathlib import Path
from dora_lei_check import extract, fetch, judge, Report

candidates = extract(Path("register.zip"))
report = Report([judge(c, fetch(c.lei)) for c in candidates])
print(report.failures)
```

## What it does and does not do

**Does:** finds every LEI-shaped value anywhere in the register, validates ISO
17442 format and the mod-97 checksum offline, then resolves each one against
GLEIF and reports anything that is not `ISSUED`.

**Does not:** validate the XBRL itself. Use
[Arelle](https://github.com/Arelle/Arelle) for the technical and DPM layers —
it is free, excellent, and this tool is not a replacement for it.

To be precise about the overlap, because it matters: Arelle's `validate/EBA`
plugin **does** check LEIs — but only their format and checksum, entirely
offline, and only for context entity identifiers. It contains no GLEIF
capability at all. A lapsed LEI passes Arelle and fails your submission. That
gap is the whole reason this exists.

## License

MIT.
