commit 3903c8bae8dadb0887cb9347bcc719b03a2c73a1
parent 5845596472d3a265d16836f5b0e401f34b74531c
Author: Christian Grothoff <christian@grothoff.org>
Date: Wed, 5 Aug 2026 23:00:43 +0200
fix send_kyc_notification stored procedure that still referenced removed merchant_serial column
Diffstat:
2 files changed, 96 insertions(+), 9 deletions(-)
diff --git a/src/backenddb/pg_merchant_send_kyc_notification.sql b/src/backenddb/pg_merchant_send_kyc_notification.sql
@@ -13,8 +13,8 @@
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
--- @file pg_merchant_kyc_trigger.sql
--- @brief Fix trigger logic
+-- @file pg_merchant_send_kyc_notification.sql
+-- @brief Queue a report to alert the merchant about a KYC status change
-- @author Christian Grothoff
@@ -67,10 +67,16 @@ BEGIN
RETURN;
END IF;
- my_report_token = random_bytea(32);
+ -- Note: random_bytea(), uri_escape() and base32_crockford() live in the
+ -- 'merchant' schema, while this procedure runs with a search_path that
+ -- contains only the per-instance schema (see set_instance.c), so they
+ -- MUST be schema-qualified here.
+ my_report_token = merchant.random_bytea(32);
+ -- Note: merchant_reports is the per-instance table; it lost its
+ -- 'merchant_serial' column when the tables were moved into per-instance
+ -- schemata (merchant-0036).
INSERT INTO merchant_reports (
- merchant_serial
- ,report_program_section
+ report_program_section
,report_description
,mime_type
,report_token
@@ -81,13 +87,12 @@ BEGIN
,next_transmission
,one_shot_hidden
) VALUES (
- my_instance_serial
- ,'email'
+ 'email'
,'automatically triggered KYC alert'
,'text/plain'
,my_report_token
- ,'/private/kyc?exchange_url=' || uri_escape(in_exchange_url)
- || '&h_wire=' || base32_crockford (my_h_wire)
+ ,'/private/kyc?exchange_url=' || merchant.uri_escape(in_exchange_url)
+ || '&h_wire=' || merchant.base32_crockford (my_h_wire)
,my_email
,0
,0
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
@@ -191,6 +191,66 @@ static struct TALER_MERCHANTDB_PostgresContext *pg;
} while (0)
+/**
+ * Runs @a sql directly on the database connection of the test. Used to
+ * set up or inspect state that has no dedicated MERCHANTDB entry point,
+ * such as the notification settings of an instance or the rows queued by
+ * a trigger.
+ *
+ * @param sql the SQL statement(s) to execute
+ * @return 0 on success, 1 otherwise.
+ */
+static int
+exec_sql (const char *sql)
+{
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_execute (sql),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+
+ TEST_COND_RET_ON_FAIL (GNUNET_OK ==
+ GNUNET_PQ_exec_statements (pg->conn,
+ es),
+ "Direct SQL execution failed\n");
+ return 0;
+}
+
+
+/**
+ * Evaluates @a sql, which must be a parameter-less query returning
+ * exactly one row with a single INT8 column named "num".
+ *
+ * @param sql the query to run
+ * @param[out] num set to the value returned
+ * @return 0 on success, 1 otherwise.
+ */
+static int
+query_sql_num (const char *sql,
+ uint64_t *num)
+{
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("num",
+ num),
+ GNUNET_PQ_result_spec_end
+ };
+
+ TEST_COND_RET_ON_FAIL (GNUNET_OK ==
+ GNUNET_PQ_prepare_anon (pg->conn,
+ sql),
+ "Preparing direct query failed\n");
+ TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
+ GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "",
+ params,
+ rs),
+ "Direct query failed\n");
+ return 0;
+}
+
+
/* ********** Instances ********** */
@@ -6861,6 +6921,7 @@ test_kyc (void)
struct TALER_MERCHANTDB_AccountDetails account;
bool fail;
struct GNUNET_TIME_Timestamp now;
+ uint64_t alerts;
make_instance ("test_kyc",
&instance);
@@ -6871,6 +6932,14 @@ test_kyc (void)
TEST_RET_ON_FAIL (test_insert_account (&instance,
&account,
GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
+ /* Arm the KYC alert path: merchant_send_kyc_notification() returns
+ early unless the instance has BOTH an e-mail address and a
+ notification language. No C entry point writes
+ 'notification_language', hence the direct UPDATE. */
+ TEST_RET_ON_FAIL (exec_sql ("UPDATE merchant.merchant_instances"
+ " SET email='kyc-alerts@example.com'"
+ " ,notification_language='en'"
+ " WHERE merchant_id='test_kyc'"));
now = GNUNET_TIME_timestamp_get ();
TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
TALER_MERCHANTDB_insert_kyc_status (pg,
@@ -6887,6 +6956,19 @@ test_kyc (void)
NULL,
false,
false));
+ /* The AFTER INSERT trigger must have queued exactly one alert.
+ Regression test: merchant_send_kyc_notification() used to call
+ random_bytea()/uri_escape()/base32_crockford() unqualified -- they
+ live in schema 'merchant' only, while the search_path holds just the
+ per-instance schema -- and to insert a 'merchant_serial' column that
+ merchant-0036 dropped. Either turned this call into a HARD_ERROR,
+ which taler-merchant-kyccheck treats as fatal. */
+ TEST_RET_ON_FAIL (query_sql_num ("SELECT COUNT(*) AS num"
+ " FROM merchant_reports"
+ " WHERE one_shot_hidden",
+ &alerts));
+ TEST_COND_RET_ON_FAIL (1 == alerts,
+ "KYC status change did not queue an alert report\n");
TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
TALER_MERCHANTDB_insert_kyc_status (pg,
instance.instance.id,