robocop

Checks KYC attributes against sanction lists
Log | Files | Refs | Submodules | README | LICENSE

README.md (3997B)


      1 <!--
      2 SPDX-FileCopyrightText: 2025 Christian Grothoff
      3 
      4 SPDX-License-Identifier: GPL-3.0-or-later
      5 -->
      6 
      7 # Robocop
      8 
      9 Robocop is a Counter Terrorist Financing (CTF) sanction processing tool written in Rust. It can be used for compliance processes in software such as [GNU Taler](https://taler.net).
     10 
     11 ## Prepare for installation
     12 
     13 Download the repository containing all the [source files](https://git.taler.net/robocop.git/)
     14 
     15 Then make sure you have Rust and Cargo installed.
     16 
     17 ## Install and run
     18 
     19 The program version comes from `git describe --tags --always --abbrev=8` at
     20 build time. Git takes precedence over a `.version` file in the checkout.
     21 Before exporting a source archive, record the version with:
     22 
     23 ```sh
     24 git describe --tags --always --abbrev=8 > .version
     25 ```
     26 
     27 Include that file at the archive root. Builds without Git metadata read
     28 `.version` and fail if it is missing or does not contain a nonempty single-line
     29 version. The Cargo manifest version is dependency metadata, not the version
     30 reported by the program.
     31 
     32 Once Cargo is installed, we can install `robocop` with the command:
     33 
     34 ```
     35 $ cargo install --path .
     36 ```
     37 
     38 You can then run it by providing the sanction list in JSON format:
     39 
     40 ```
     41 $ ~/.cargo/bin/robocop swiss.json
     42 ```
     43 
     44 
     45 ## Converting official sanction lists to robocop's internal format
     46 
     47 `robocop` consumes its sanction list as a JSON **array of target records**. Each
     48 record has a string `ssid` (its identifier) plus any number of registry fields
     49 whose values are **arrays of strings** (e.g. `FULL_NAME`, `PERSON_FIRST_NAMES`,
     50 `PERSON_LAST_NAME`, `DATE_OF_BIRTH`, `NATIONALITY`, `PERSON_NATIONAL_ID`,
     51 `COMPANY_NAME`, `ADDRESS_*` / `REGISTERED_OFFICE_ADDRESS_*`). At match time
     52 `robocop` compares each field of an incoming query against the same-named field
     53 of every record (fuzzy, Levenshtein-based), so all converters emit the **same**
     54 registry field names regardless of source list.
     55 
     56 One converter is provided per source-list format. Each reads the official XML on
     57 stdin and writes the JSON array on stdout; pipe it through
     58 `robocop-json-postprocess` (which drops empty/`null` fields) to get the final
     59 list:
     60 
     61 | Converter | Source list | Official XML schema |
     62 |-----------|-------------|---------------------|
     63 | `robocop-ch-to-json`   | Switzerland — SECO | `swiss-sanctions-list` |
     64 | `robocop-eu-to-json`   | EU — Consolidated Financial Sanctions List | `export` / `sanctionEntity` |
     65 | `robocop-un-to-json`   | UN — Security Council Consolidated List | `CONSOLIDATED_LIST` |
     66 | `robocop-ofac-to-json` | US — OFAC SDN **and** Consolidated lists | legacy `sdnList` / `sdnEntry` |
     67 | `robocop-uk-to-json`   | UK — OFSI Consolidated List | `ArrayOfFinancialSanctionsTarget` |
     68 
     69 Each record's `ssid` is namespaced by authority (`EU-`, `UN-`, `OFAC-`, `GB-`,
     70 and the bare numeric Swiss id) so records stay unique if several lists are
     71 concatenated into one file.
     72 
     73 ```
     74 $ ./robocop-ch-to-json   < swiss.xml   | robocop-json-postprocess > swiss.json
     75 $ ./robocop-eu-to-json   < eu.xml      | robocop-json-postprocess > eu.json
     76 $ ./robocop-un-to-json   < un.xml      | robocop-json-postprocess > un.json
     77 $ ./robocop-ofac-to-json < SDN.XML | robocop-json-postprocess > ofac-sdn.json
     78 $ ./robocop-ofac-to-json --prefix OFAC-CONS- < CONSOLIDATED.XML \
     79       | robocop-json-postprocess > ofac-cons.json
     80 $ ./robocop-uk-to-json   < ConList.xml | robocop-json-postprocess > uk.json
     81 ```
     82 
     83 Note on the OFAC consolidated (non-SDN) list: OFAC serves it in the legacy
     84 `sdnList` format at `.../exports/CONSOLIDATED.XML`, and in the newer "advanced"
     85 format at `CONS_ADVANCED.XML`. `robocop-ofac-to-json` reads the **legacy** format,
     86 so a single converter handles both the SDN list and the consolidated list; use
     87 `CONSOLIDATED.XML` (not `CONS_ADVANCED.XML`, which robocop does not parse). Because
     88 OFAC reuses a few `uid`s across the two lists, pass `--prefix OFAC-CONS-` when
     89 converting the consolidated list if you intend to merge it with the SDN list into
     90 one file, so the records keep distinct `ssid`s.