Class: ActiveSanction::Sources::OfacConsolidated
- Extended by:
- T::Sig
- Defined in:
- lib/active_sanction/sources/ofac_consolidated.rb,
lib/active_sanction/sources/ofac_consolidated/record.rb
Overview
OFAC's Consolidated (non-SDN) list: everything the US sanctions that is not a Specially Designated National.
snapshot = ActiveSanction::Sources[:ofac_consolidated].new.sync
It is small -- 481 entities against the SDN list's 19,321 -- and it is screened anyway, because being on it still carries real legal weight. A Chinese semiconductor firm on the CMIC list cannot be invested in; a Russian bank on the SSI list can be transacted with but not lent to beyond a tenor the directive sets. Neither is a blocking sanction, and both are prohibitions a compliance team has to act on.
One file, several lists
OFAC ships the non-SDN lists as one set of three CSVs in the same shape as the SDN files -- the reading is Ofac's, and this adapter adds no parsing of its own -- but the rows in it belong to six different lists:
Sectoral Sanctions Identifications (SSI) the Russia/Ukraine directives
Non-SDN CMIC Chinese military-industrial firms
Non-SDN Palestinian Legislative Council NS-PLC
Non-SDN Menu-Based Sanctions (NS-MBS) HKAA, CAATSA, EO 14024 directives
CAPTA foreign financial institutions
FSE foreign sanctions evaders
A hit on CMIC and a hit on NS-PLC are different findings with different consequences, so which one a record is on has to survive the parse. #lists answers it for any entity this adapter produced:
ActiveSanction::Sources::OfacConsolidated.lists(entity) # => [:cmic]
ActiveSanction::Sources::OfacConsolidated.names(entity) # => ["Non-SDN CMIC List"]
It is a function of entity.programs, which is a canonical Entity member
-- so it keeps working on a record that has been stored, serialized and
read back, with no per-source column anywhere downstream. The names are
also appended to remarks behind the [source fields] marker, which is
where a compliance report reads them from.
Why the programs and not a column
There is no list column. CONS_PRIM.CSV has the same twelve columns as
SDN.CSV, and the only thing in it that names a list is the program code
-- CMIC-EO13959, NS-PLC, HKAA. OFAC states the membership
explicitly in CONS_ADVANCED.XML, a 4.5 MB re-publication of the same 481
records, and downloading the list twice to read one attribute off the
second copy is a poor trade. So the program code is what LISTS maps.
Checked against that XML's own attribution, the mapping is exact for 478 of the 481 published records. The three it is not are all the same ambiguity, and SHARED is where it lives.
Instance Attribute Summary
Attributes inherited from Base
#cache, #fetcher, #instrumenter, #logger
Class Method Summary collapse
-
.lists(programs) ⇒ Array<Symbol>
Which sub-lists a record is on, as an Array of the keys NAMES uses.
-
.names(programs) ⇒ Array<String>
The same answer as OFAC spells it, which is what goes in a report.
Methods inherited from Base
#authority, #column_shapes, #column_tallies, #file_key, #floors, #format, #fresh?, #initialize, #inspect, #jurisdiction, #key, #parse, #parse_argument, published_remarks, #retrieve, #snapshot, #source_version, #stale?, #sync, #url, #urls, #warnings
Methods included from Definition
#authority, #declarations, #declared?, #declared_floors, #declared_urls, #file_key, #floor, #floors, #format, #jurisdiction, #key, key!, #licence_notice, #licence_url, #multi_url?, #to_h, #url, #urls
Class Method Details
.lists(programs) ⇒ Array<Symbol>
Which sub-lists a record is on, as an Array of the keys NAMES uses. Takes an Entity, or the programs themselves.
OfacConsolidated.lists(entity) # => [:ssi]
OfacConsolidated.lists(%w[UKRAINE-EO13662 RUSSIA-EO14024]) # => [:ssi]
OfacConsolidated.lists(%w[RUSSIA-EO14024]) # => [:ns_mbs]
Empty for a record whose programs name no list this adapter knows, which is what #parse warns about.
161 162 163 164 165 166 167 |
# File 'lib/active_sanction/sources/ofac_consolidated.rb', line 161 def self.lists(programs) codes = programs.respond_to?(:programs) ? programs.programs : Array(programs) certain = codes.filter_map { |code| LISTS[code] }.uniq shared = codes.filter_map { |code| SHARED[code] } .map { |rule| certain.include?(rule[:with]) ? rule[:with] : rule[:alone] } (certain + shared).uniq end |
.names(programs) ⇒ Array<String>
The same answer as OFAC spells it, which is what goes in a report.
171 |
# File 'lib/active_sanction/sources/ofac_consolidated.rb', line 171 def self.names(programs) = lists(programs).map { |list| NAMES.fetch(list) } |