[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[exchange] branch master updated: add test and fix bugs for sanction lis
From: |
Admin |
Subject: |
[exchange] branch master updated: add test and fix bugs for sanction list check (for #9053) |
Date: |
Mon, 09 Jun 2025 00:06:34 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository exchange.
The following commit(s) were added to refs/heads/master by this push:
new 8ad5457d5 add test and fix bugs for sanction list check (for #9053)
8ad5457d5 is described below
commit 8ad5457d51d5089f4f6c7dfe5a81b7210dd28110
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Mon Jun 9 00:06:21 2025 +0200
add test and fix bugs for sanction list check (for #9053)
---
src/exchange/exchange.conf | 8 +-
src/exchange/taler-exchange-sanctionscheck.c | 58 ++++++++--
src/exchange/test_taler_exchange_httpd.sh | 5 +-
.../exchange_do_insert_sanction_list_hit.sql | 5 +
src/exchangedb/pg_insert_sanction_list_hit.c | 4 +-
src/kyclogic/kyclogic_sanctions.c | 119 ++++++++++++---------
.../taler-exchange-helper-measure-test-form | 10 +-
src/testing/Makefile.am | 7 +-
src/testing/sanction-list.json | 3 +
src/testing/test-sanctions.sh | 38 +++----
src/testing/test_kyc_api.c | 2 +-
src/testing/test_sanctions.conf | 2 +-
12 files changed, 163 insertions(+), 98 deletions(-)
diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf
index 4f3f43008..8624eb17c 100644
--- a/src/exchange/exchange.conf
+++ b/src/exchange/exchange.conf
@@ -138,17 +138,17 @@ MIN_ROW_FILENAME =
${TALER_CACHE_HOME}sanctionscheck-offset.bin
# Sanction list match rating that must be exceeded for an automated
# freeze of the account (without manual investigation first).
# Both this and the FREEZE_CONFIDENCE_LIMIT must be met.
-FREEZE_RATING_LIMIT = 0.95
+FREEZE_RATING_LIMIT = 0.9
# Sanction list confidence that must be exceeded for an automated
# freeze of the account (without manual investigation first).
# Both this and the FREEZE_RATING_LIMIT must be met.
-FREEZE_CONFIDENCE_LIMIT = 0.95
+FREEZE_CONFIDENCE_LIMIT = 0.9
# Value that the rating divided by the confidence must exceed to
-# trigger a (manual) investigation. At 0.95 (default), a modest
+# trigger a (manual) investigation. At 0.95, a modest
# 0.8 match with low 0.5 confidence will trigger (1.6), but a
# good 0.9 match with a super-high 1.0 confidence would not (0.9 < 0.95).
# OTOH, a bad 0.2 match with super-low 0.1 confidence would again
# trigger (2.0 > 0.95).
-INVESTIGATION_LIMIT = 0.95
\ No newline at end of file
+INVESTIGATION_LIMIT = 0.9
\ No newline at end of file
diff --git a/src/exchange/taler-exchange-sanctionscheck.c
b/src/exchange/taler-exchange-sanctionscheck.c
index 2a7bdeaca..431a9fac5 100644
--- a/src/exchange/taler-exchange-sanctionscheck.c
+++ b/src/exchange/taler-exchange-sanctionscheck.c
@@ -157,18 +157,18 @@ static bool in_transaction;
/**
* Match quality needed for instantly freezing an account.
*/
-static float freeze_rating_limit = 0.95;
+static float freeze_rating_limit = 0.9;
/**
* Match confidence needed for instantly freezing an account.
*/
-static float freeze_confidence_limit = 0.95;
+static float freeze_confidence_limit = 0.9;
/**
* Rating/confidence threshold that must be passed to begin
* an investigation.
*/
-static float investigation_limit = 0.95;
+static float investigation_limit = 0.9;
/**
* Write @a min_row_id to @a min_row_fd.
@@ -208,9 +208,9 @@ shutdown_task (void *cls)
struct Account *acc;
(void) cls;
- sync_row ();
if (-1 != min_row_fd)
{
+ sync_row ();
GNUNET_break (0 == close (min_row_fd));
min_row_fd = -1;
}
@@ -284,6 +284,17 @@ sanction_cb (void *cls,
bool freeze = false;
bool investigate = false;
+ if (TALER_EC_NONE != ec)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error %s (%d) when analyzing record\n",
+ TALER_ErrorCode_get_hint (ec),
+ (int) ec);
+ db_plugin->rollback (db_plugin->cls);
+ global_ret = 1;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
if ( (rating > (double) freeze_rating_limit) &&
(confidence > (double) freeze_confidence_limit) )
{
@@ -294,6 +305,16 @@ sanction_cb (void *cls,
{
investigate = true;
}
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Best match is %f/%f at `%s' will %s\n",
+ rating,
+ confidence,
+ best_match,
+ freeze || investigate
+ ? (freeze
+ ? "freeze"
+ : "investigate")
+ : "do nothing");
if (freeze || investigate)
{
static const char *freeze_event[] = {
@@ -320,9 +341,10 @@ sanction_cb (void *cls,
"INVESTIGATION_PENDING"),
GNUNET_JSON_pack_string ("AML_INVESTIGATION_TIGGER",
"SANCTION_LIST_MATCH"));
- GNUNET_assert (0 ==
- json_object_update_missing (properties,
- acc->properties));
+ if (NULL != acc->properties)
+ GNUNET_assert (0 ==
+ json_object_update_missing (properties,
+ acc->properties));
qs = db_plugin->insert_sanction_list_hit (db_plugin->cls,
&acc->h_payto,
investigate,
@@ -420,6 +442,14 @@ account_cb (void *cls,
(unsigned long long) row_id);
return true;
}
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Found KYC data %llu\n",
+ (unsigned long long) row_id);
+#if DEBUG
+ json_dumpf (attributes,
+ stderr,
+ JSON_INDENT (2));
+#endif
acc = GNUNET_new (struct Account);
acc->row_id = row_id;
acc->h_payto = *h_payto;
@@ -697,6 +727,7 @@ run (void *cls,
"exchange-sanctionscheck",
"MIN_ROW_FILENAME");
global_ret = EXIT_NOTCONFIGURED;
+ GNUNET_SCHEDULER_shutdown ();
return;
}
if (reset &&
@@ -708,6 +739,18 @@ run (void *cls,
min_row_fn);
GNUNET_free (min_row_fn);
global_ret = EXIT_NOPERMISSION;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_DISK_directory_create_for_file (min_row_fn))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "open",
+ min_row_fn);
+ GNUNET_free (min_row_fn);
+ global_ret = EXIT_NOPERMISSION;
+ GNUNET_SCHEDULER_shutdown ();
return;
}
min_row_fd = open (min_row_fn,
@@ -720,6 +763,7 @@ run (void *cls,
min_row_fn);
GNUNET_free (min_row_fn);
global_ret = EXIT_NOTCONFIGURED;
+ GNUNET_SCHEDULER_shutdown ();
return;
}
if (sizeof (r) !=
diff --git a/src/exchange/test_taler_exchange_httpd.sh
b/src/exchange/test_taler_exchange_httpd.sh
index 0fe71f3ad..988b7c54f 100755
--- a/src/exchange/test_taler_exchange_httpd.sh
+++ b/src/exchange/test_taler_exchange_httpd.sh
@@ -35,7 +35,7 @@ PREFIX=
taler-exchange-dbinit -c test_taler_exchange_httpd.conf &> /dev/null || exit 77
# Run Exchange HTTPD (in background)
$PREFIX taler-exchange-httpd -c test_taler_exchange_httpd.conf 2>
test-exchange.log &
-
+EPID=$!
# Give HTTP time to start
for n in `seq 1 100`
@@ -74,8 +74,7 @@ echo -n .
cat test_taler_exchange_httpd.get | grep -v ^\# | awk '{ print "curl -H
\"Accept: */plain\" http://localhost:8081" $1 }' | bash &> /dev/null
echo " DONE"
-# $! is the last backgrounded process, hence the exchange
-kill -TERM $!
+kill -TERM "${EPID}"
wait $!
# Return status code from exchange for this script
exit $?
diff --git a/src/exchangedb/exchange_do_insert_sanction_list_hit.sql
b/src/exchangedb/exchange_do_insert_sanction_list_hit.sql
index 265c25973..e86210b18 100644
--- a/src/exchangedb/exchange_do_insert_sanction_list_hit.sql
+++ b/src/exchangedb/exchange_do_insert_sanction_list_hit.sql
@@ -32,6 +32,11 @@ DECLARE
ini_event TEXT;
BEGIN
+-- Disable all previous legitimization outcomes.
+UPDATE legitimization_outcomes
+ SET is_active=FALSE
+ WHERE h_payto=in_h_normalized_payto;
+
INSERT INTO legitimization_outcomes
(h_payto
,decision_time
diff --git a/src/exchangedb/pg_insert_sanction_list_hit.c
b/src/exchangedb/pg_insert_sanction_list_hit.c
index 3a59cc3ab..ee5e4d6c1 100644
--- a/src/exchangedb/pg_insert_sanction_list_hit.c
+++ b/src/exchangedb/pg_insert_sanction_list_hit.c
@@ -76,8 +76,8 @@ TEH_PG_insert_sanction_list_hit (
PREPARE (pg,
"do_insert_sanction_list_hit",
"SELECT"
- " out_outcome_serial_id"
- " FROM exchange_insert_sanction_list_hit"
+ " out_outcome_serial_id AS outcome_serial_id"
+ " FROM exchange_do_insert_sanction_list_hit"
"($1,$2,$3,$4,$5,$6,$7,$8);");
qs = GNUNET_PQ_eval_prepared_singleton_select (
pg->conn,
diff --git a/src/kyclogic/kyclogic_sanctions.c
b/src/kyclogic/kyclogic_sanctions.c
index 3ce169076..ab591bdb4 100644
--- a/src/kyclogic/kyclogic_sanctions.c
+++ b/src/kyclogic/kyclogic_sanctions.c
@@ -51,7 +51,7 @@ struct TALER_KYCLOGIC_EvaluationEntry
/**
* Buffer with data we need to send to the helper.
*/
- void *write_buf;
+ char *write_buf;
/**
* Total length of @e write_buf.
@@ -167,7 +167,10 @@ fail_hard (struct TALER_KYCLOGIC_SanctionRater *sr)
NULL,
1.0,
0.0);
- free (ee->write_buf);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to send %u bytes to child\n",
+ (unsigned int) (ee->write_size - ee->write_pos));
+ GNUNET_free (ee->write_buf);
GNUNET_free (ee);
}
}
@@ -192,6 +195,7 @@ process_buffer (struct TALER_KYCLOGIC_SanctionRater *sr)
if ( (NULL == end) &&
(sr->read_pos < 2048) )
return true;
+ end++;
buf_len = end - sr->read_buf;
while (0 != buf_len)
{
@@ -204,9 +208,14 @@ process_buffer (struct TALER_KYCLOGIC_SanctionRater *sr)
nl = memchr (buf,
'\n',
buf_len);
- GNUNET_assert (NULL != nl);
+ if (NULL == nl)
+ {
+ /* no newline in 2048 bytes? not allowed */
+ GNUNET_break (0);
+ return false;
+ }
*nl = '\0';
- line_len = nl - buf;
+ line_len = nl - buf + 1;
if (3 !=
sscanf (buf,
"%lf %lf %1023s",
@@ -231,7 +240,7 @@ process_buffer (struct TALER_KYCLOGIC_SanctionRater *sr)
best_match,
rating,
confidence);
- free (ee->write_buf);
+ GNUNET_free (ee->write_buf);
GNUNET_free (ee);
}
buf += line_len;
@@ -347,54 +356,56 @@ write_cb (void *cls)
ssize_t ret;
sr->write_task = NULL;
- while (ee->write_size > ee->write_pos)
+ while ( (NULL != ee) &&
+ (ee->write_size == ee->write_pos) )
+ ee = ee->prev;
+ while (NULL != ee)
{
- ret = GNUNET_DISK_file_write (sr->chld_stdin,
- ee->write_buf + ee->write_pos,
- ee->write_size - ee->write_pos);
- if (ret < 0)
+ while (ee->write_size > ee->write_pos)
{
- if ( (EAGAIN != errno) &&
- (EINTR != errno) )
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
- "write");
- break;
+ ret = GNUNET_DISK_file_write (sr->chld_stdin,
+ ee->write_buf + ee->write_pos,
+ ee->write_size - ee->write_pos);
+ if (ret < 0)
+ {
+ if ( (EAGAIN != errno) &&
+ (EINTR != errno) )
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "write");
+ /* helper must have died */
+ fail_hard (sr);
+ return;
+ }
+ break;
+ }
+ if (0 == ret)
+ {
+ GNUNET_break (0);
+ break;
+ }
+ GNUNET_assert (ee->write_size >= ee->write_pos + ret);
+ ee->write_pos += ret;
}
- if (0 == ret)
+ if ( (ee->write_size > ee->write_pos) &&
+ ( (EAGAIN == errno) ||
+ (EWOULDBLOCK == errno) ||
+ (EINTR == errno) ) )
{
- GNUNET_break (0);
- break;
- }
- GNUNET_assert (ee->write_size >= ee->write_pos + ret);
- ee->write_pos += ret;
- }
- if (ee->write_size == ee->write_pos)
- {
- free (ee->write_buf);
- GNUNET_CONTAINER_DLL_remove (sr->ee_head,
- sr->ee_tail,
- ee);
- GNUNET_free (ee);
- ee = sr->ee_tail;
- if (NULL == ee)
+ sr->write_task
+ = GNUNET_SCHEDULER_add_write_file (
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ sr->chld_stdin,
+ &write_cb,
+ sr);
return;
- }
- if ( (ee->write_size > ee->write_pos) &&
- ( (EAGAIN == errno) ||
- (EWOULDBLOCK == errno) ||
- (EINTR == errno) ) )
- {
- sr->write_task
- = GNUNET_SCHEDULER_add_write_file (
- GNUNET_TIME_UNIT_FOREVER_REL,
- sr->chld_stdin,
- &write_cb,
- sr);
- return;
- }
- /* helper must have died */
- GNUNET_break (0);
- fail_hard (sr);
+ }
+ if (ee->write_size == ee->write_pos)
+ {
+ GNUNET_free (ee->write_buf);
+ ee = ee->prev;
+ }
+ } /* while (NULL != ee) */
}
@@ -485,6 +496,7 @@ TALER_KYCLOGIC_sanction_rater_eval (struct
TALER_KYCLOGIC_SanctionRater *sr,
void *cb_cls)
{
struct TALER_KYCLOGIC_EvaluationEntry *ee;
+ char *js;
if (NULL == sr->read_task)
return NULL;
@@ -494,12 +506,13 @@ TALER_KYCLOGIC_sanction_rater_eval (struct
TALER_KYCLOGIC_SanctionRater *sr,
GNUNET_CONTAINER_DLL_insert (sr->ee_head,
sr->ee_tail,
ee);
- ee->write_buf = json_dumps (attributes,
- JSON_COMPACT);
+ js = json_dumps (attributes,
+ JSON_COMPACT);
+ GNUNET_asprintf (&ee->write_buf,
+ "%s\n",
+ js);
+ free (js);
ee->write_size = strlen (ee->write_buf);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Passing %llu bytes to JSON conversion tool\n",
- (unsigned long long) ee->write_size);
if (NULL == sr->write_task)
sr->write_task
= GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
diff --git a/src/kyclogic/taler-exchange-helper-measure-test-form
b/src/kyclogic/taler-exchange-helper-measure-test-form
index 349e8d661..aada52ab5 100755
--- a/src/kyclogic/taler-exchange-helper-measure-test-form
+++ b/src/kyclogic/taler-exchange-helper-measure-test-form
@@ -34,9 +34,9 @@ do
case "$OPTION" in
a)
# This AML program expects as inputs a full_name
- # and a birthdate.
- echo "full_name"
- echo "birthdate"
+ # and a date of birth.
+ echo "FULL_NAME"
+ echo "DATE_OF_BIRTH"
exit 0
;;
c)
@@ -90,8 +90,8 @@ J=$(echo "$A" | jq -r 'def get($k):
then .[$k]
else error("attribute missing")
end;
- {"full_name":get("full_name"),
- "birthdate":get("birthdate")}')
+ {"FULL_NAME":get("FULL_NAME"),
+ "DATE_OF_BIRTH":get("DATE_OF_BIRTH")}')
# Here we could use those values...
echo "$J" >> /dev/null
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index d1c970adf..d653ab276 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -185,9 +185,12 @@ endif
# test_exchange_api_revocation_cs
# test_exchange_api_revocation_rsa
+check_SCRIPTS = \
+ test-sanctions.sh
TESTS = \
- $(check_PROGRAMS)
+ $(check_PROGRAMS) \
+ $(check_SCRIPTS)
test_auditor_api_cs_SOURCES = \
test_auditor_api.c
@@ -559,9 +562,11 @@ test_kyc_api_LDADD = \
EXTRA_DIST = \
$(bin_SCRIPTS) \
+ $(check_SCRIPTS) \
valgrind.h \
coins-cs.conf \
coins-rsa.conf \
+ sanction-list.json \
test_exchange_api_home/.local/share/taler-auditor/offline-keys/auditor.priv \
test_exchange_api_home/.local/share/taler-exchange/offline/master.priv \
test_auditor_api-cs.conf \
diff --git a/src/testing/sanction-list.json b/src/testing/sanction-list.json
new file mode 100644
index 000000000..665c37625
--- /dev/null
+++ b/src/testing/sanction-list.json
@@ -0,0 +1,3 @@
+[{"ssid":"1","FULL_NAME":["Bob"],"DATE_OF_BIRTH":["6.7.1980"]},
+ {"ssid":"2","FULL_NAME":["Alice"],"DATE_OF_BIRTH":["5.7.1980"]},
+ {"ssid":"3","FULL_NAME":["Carol"],"DATE_OF_BIRTH":["5.7.1980"]}]
diff --git a/src/testing/test-sanctions.sh b/src/testing/test-sanctions.sh
index 699018ae1..2bc59e149 100755
--- a/src/testing/test-sanctions.sh
+++ b/src/testing/test-sanctions.sh
@@ -32,6 +32,10 @@ function my_cleanup()
fi
}
+echo -n "Testing for robocop"
+robocop -h > /dev/null || exit_skip " robocop required"
+echo " FOUND"
+
. setup.sh
@@ -67,7 +71,7 @@ ID=$(jq -r .requirements[0].id < "$LAST_RESPONSE")
echo -n "Submitting KYC form..." >&2
STATUS=$(curl -H "Content-Type: application/json" -X POST \
"http://localhost:8081/kyc-upload/$ID" \
- -d '{"full_name":"Bob","birthdate":"5.7.1980"}' \
+ -d '{"FULL_NAME":"Bob","DATE_OF_BIRTH":"5.7.1980"}' \
-w "%{http_code}" -s -o "$LAST_RESPONSE")
echo $STATUS
@@ -77,30 +81,22 @@ then
exit_fail "Expected 204, KYC data submitted. got: $STATUS"
fi
+taler-exchange-sanctionscheck \
+ -L INFO \
+ -c test_sanctions.conf.edited \
+ --reset \
+ --test \
+ robocop sanction-list.json
+PROP=$(echo 'SELECT jproperties FROM exchange.legitimization_outcomes WHERE
is_active;' | psql talercheck -Aqt)
-bash
-
-# => begin KYC process
-# => submit KYC data
-# => run sanction list tool!
-
+MATCH=$(echo "$PROP" | jq -r .SANCTION_LIST_BEST_MATCH)
+if [ "$MATCH" != "1" ]
+then
+ exit_fail "Sanction checker failed to find Bob"
+fi
echo "Test PASSED"
exit 0
-
-
-echo -n "Creating order to test auth is ok..." >&2
-STATUS=$(curl -H "Content-Type: application/json" -X POST \
- 'http://localhost:9966/private/orders' \
- -H 'Authorization: Bearer '"$NEW_SECRET" \
- -d '{"order":{"amount":"TESTKUDOS:1","summary":"payme"}}' \
- -w "%{http_code}" -s -o "$LAST_RESPONSE")
-
-if [ "$STATUS" != "200" ]
-then
- cat "$LAST_RESPONSE" >&2
- exit_fail "Expected 200, order created. got: $STATUS"
-fi
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index 5d0eff9c4..dbb5ffb43 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -771,7 +771,7 @@ run (void *cls,
"get-kyc-info-form",
0, /* requirement index */
"application/json",
-
"{\"form_id\":\"test\",\"full_name\":\"Bob\",\"birthdate\":\"1990-00-00\"}",
+
"{\"form_id\":\"test\",\"FULL_NAME\":\"Bob\",\"DATE_OF_BIRTH\":\"1990-00-00\"}",
MHD_HTTP_NO_CONTENT),
/* now this should be allowed */
TALER_TESTING_cmd_wallet_kyc_get (
diff --git a/src/testing/test_sanctions.conf b/src/testing/test_sanctions.conf
index 2c37f2da9..12db30d56 100644
--- a/src/testing/test_sanctions.conf
+++ b/src/testing/test_sanctions.conf
@@ -40,7 +40,7 @@ FALLBACK = manual-freeze
# This check runs on oauth2
FORM_NAME = full_name_and_birthdate
# Outputs from this check
-OUTPUTS = full_name birthdate
+OUTPUTS = FULL_NAME DATE_OF_BIRTH
# This is the "default" setting for an account if
# it has not yet triggered anything.
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [exchange] branch master updated: add test and fix bugs for sanction list check (for #9053),
Admin <=