mirror of https://github.com/sysown/proxysql
Merge pull request #5567 from sysown/v3.0_pgsql_sslkeylog_5281
Add SSL/TLS traffic decryption for PostgreSQL backend connectionsfix/ci-workflow-run-chain-pr-sha
commit
1a8e4ed918
@ -0,0 +1,63 @@
|
||||
diff -ruN ../tmp/src/interfaces/libpq/fe-secure-openssl.c ./src/interfaces/libpq/fe-secure-openssl.c
|
||||
--- ../tmp/src/interfaces/libpq/fe-secure-openssl.c 2025-08-11 21:06:43.000000000 +0000
|
||||
+++ ./src/interfaces/libpq/fe-secure-openssl.c 2026-04-03 00:00:00.000000000 +0000
|
||||
@@ -97,6 +97,8 @@
|
||||
|
||||
static PQsslKeyPassHook_OpenSSL_type PQsslKeyPassHook = NULL;
|
||||
static int ssl_protocol_version_to_openssl(const char *protocol);
|
||||
+
|
||||
+static PQsslKeyLogCallback_type PQsslKeyLogCB = NULL;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Procedures common to all secure sessions */
|
||||
@@ -972,6 +974,10 @@
|
||||
/* Disable old protocol versions */
|
||||
SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
|
||||
+ /* Set SSL keylog callback if configured (for TLS traffic decryption) */
|
||||
+ if (PQsslKeyLogCB)
|
||||
+ SSL_CTX_set_keylog_callback(SSL_context, (void(*)(const SSL*, const char*))PQsslKeyLogCB);
|
||||
+
|
||||
/* Set the minimum and maximum protocol versions if necessary */
|
||||
if (conn->ssl_min_protocol_version &&
|
||||
strlen(conn->ssl_min_protocol_version) != 0)
|
||||
@@ -1758,6 +1764,24 @@
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * SSL Key Log callback support
|
||||
+ *
|
||||
+ * Global callback for writing TLS secrets to a keylog file.
|
||||
+ * Follows the same pattern as PQsslKeyPassHook.
|
||||
+ */
|
||||
+PQsslKeyLogCallback_type
|
||||
+PQgetSSLKeyLogCallback(void)
|
||||
+{
|
||||
+ return PQsslKeyLogCB;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+PQsetSSLKeyLogCallback(PQsslKeyLogCallback_type cb)
|
||||
+{
|
||||
+ PQsslKeyLogCB = cb;
|
||||
+}
|
||||
+
|
||||
const char *const *
|
||||
PQsslAttributeNames(PGconn *conn)
|
||||
{
|
||||
diff -ruN ../tmp/src/interfaces/libpq/libpq-fe.h ./src/interfaces/libpq/libpq-fe.h
|
||||
--- ../tmp/src/interfaces/libpq/libpq-fe.h 2025-08-11 21:06:43.000000000 +0000
|
||||
+++ ./src/interfaces/libpq/libpq-fe.h 2026-04-03 00:00:00.000000000 +0000
|
||||
@@ -669,6 +669,11 @@
|
||||
extern void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook);
|
||||
extern int PQdefaultSSLKeyPassHook_OpenSSL(char *buf, int size, PGconn *conn);
|
||||
|
||||
+/* Support for SSL key log callback (TLS traffic decryption) */
|
||||
+typedef void (*PQsslKeyLogCallback_type)(const void *ssl, const char *line);
|
||||
+extern PQsslKeyLogCallback_type PQgetSSLKeyLogCallback(void);
|
||||
+extern void PQsetSSLKeyLogCallback(PQsslKeyLogCallback_type cb);
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,458 @@
|
||||
/**
|
||||
* @file pgsql-ssl_keylog-t.cpp
|
||||
* @brief Integration test for PgSQL backend SSL keylog support.
|
||||
*
|
||||
* @details Validates that TLS secrets from PostgreSQL backend SSL connections
|
||||
* are written to the keylog file when admin-ssl_keylog_file is set.
|
||||
*
|
||||
* ProxySQL patches libpq with a global SSL keylog callback
|
||||
* (PQsetSSLKeyLogCallback). When admin-ssl_keylog_file is set, ALL
|
||||
* TLS connections write secrets to the keylog file in NSS Key Log Format.
|
||||
*
|
||||
* Test cases:
|
||||
* 1. Basic keylog creation — set admin-ssl_keylog_file, make PgSQL SSL connection,
|
||||
* verify file is non-empty
|
||||
* 2. NSS format validation — parse keylog lines, verify regex match for NSS Key Log Format
|
||||
* 3. TLS version label check — verify keylog contains TLS 1.2 or 1.3 secret labels
|
||||
* 4. Concurrent connections — 8 threads making PgSQL SSL connections, verify no corruption
|
||||
* 5. Disable keylog — set empty, make new connections, verify no new lines
|
||||
* 6. Log rotation — PROXYSQL FLUSH LOGS, verify new secrets appended
|
||||
* 7. Monitor SSL keylog — enable use_ssl=1, wait for monitor, verify keylog entries
|
||||
* 8. Non-SSL no keylog — use_ssl=0, verify no new entries
|
||||
* 9. Invalid keylog path — set /nonexistent/dir/file, verify graceful handling
|
||||
*
|
||||
* Test infrastructure: docker-pgsql16-single (PgSQL backend with SSL enabled)
|
||||
* Admin connection: PgSQL protocol on pgsql_admin_host:pgsql_admin_port
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <regex>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "libpq-fe.h"
|
||||
#include "command_line.h"
|
||||
#include "tap.h"
|
||||
#include "utils.h"
|
||||
|
||||
CommandLine cl;
|
||||
|
||||
using PGConnPtr = std::unique_ptr<PGconn, decltype(&PQfinish)>;
|
||||
|
||||
static const char* KEYLOG_PATH = "/tmp/pgsql_ssl_keylog_test.log";
|
||||
|
||||
// ============================================================
|
||||
// Helper: open PgSQL admin connection
|
||||
// ============================================================
|
||||
static PGConnPtr open_admin() {
|
||||
std::stringstream ss;
|
||||
ss << "host=" << cl.pgsql_admin_host
|
||||
<< " port=" << cl.pgsql_admin_port
|
||||
<< " user=" << cl.admin_username
|
||||
<< " password=" << cl.admin_password
|
||||
<< " sslmode=disable";
|
||||
PGconn* conn = PQconnectdb(ss.str().c_str());
|
||||
if (PQstatus(conn) != CONNECTION_OK) {
|
||||
fprintf(stderr, "Admin connection failed: %s", PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
return PGConnPtr(nullptr, &PQfinish);
|
||||
}
|
||||
return PGConnPtr(conn, &PQfinish);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: run admin SQL, return true on success
|
||||
// ============================================================
|
||||
static bool admin_exec(PGconn* admin, const char* sql) {
|
||||
PGresult* res = PQexec(admin, sql);
|
||||
ExecStatusType st = PQresultStatus(res);
|
||||
bool ok = (st == PGRES_COMMAND_OK || st == PGRES_TUPLES_OK);
|
||||
if (!ok) {
|
||||
diag("Admin query failed: '%s' err='%s'", sql, PQerrorMessage(admin));
|
||||
}
|
||||
PQclear(res);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: run admin SQL and return first column of first row
|
||||
// ============================================================
|
||||
static std::string admin_query_value(PGconn* admin, const char* sql) {
|
||||
std::string result;
|
||||
PGresult* res = PQexec(admin, sql);
|
||||
if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) > 0) {
|
||||
const char* val = PQgetvalue(res, 0, 0);
|
||||
if (val) result = val;
|
||||
} else {
|
||||
diag("Admin query failed: '%s' err='%s'", sql, PQerrorMessage(admin));
|
||||
}
|
||||
PQclear(res);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: set admin-ssl_keylog_file and load to runtime
|
||||
// ============================================================
|
||||
static bool set_keylog_file(PGconn* admin, const char* path) {
|
||||
std::string sql = "SET admin-ssl_keylog_file='";
|
||||
if (path) sql += path;
|
||||
sql += "'";
|
||||
if (!admin_exec(admin, sql.c_str())) return false;
|
||||
return admin_exec(admin, "LOAD ADMIN VARIABLES TO RUNTIME");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: make a PgSQL backend connection with SSL
|
||||
// ============================================================
|
||||
static PGConnPtr make_pgsql_ssl_conn() {
|
||||
std::stringstream ss;
|
||||
ss << "host=" << cl.pgsql_host
|
||||
<< " port=" << cl.pgsql_port
|
||||
<< " user=" << cl.pgsql_root_username
|
||||
<< " password=" << cl.pgsql_root_password
|
||||
<< " sslmode=require";
|
||||
PGconn* conn = PQconnectdb(ss.str().c_str());
|
||||
return PGConnPtr(conn, &PQfinish);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: make a PgSQL backend connection without SSL
|
||||
// ============================================================
|
||||
static PGConnPtr make_pgsql_nossl_conn() {
|
||||
std::stringstream ss;
|
||||
ss << "host=" << cl.pgsql_host
|
||||
<< " port=" << cl.pgsql_port
|
||||
<< " user=" << cl.pgsql_root_username
|
||||
<< " password=" << cl.pgsql_root_password
|
||||
<< " sslmode=disable";
|
||||
PGconn* conn = PQconnectdb(ss.str().c_str());
|
||||
return PGConnPtr(conn, &PQfinish);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: count non-empty lines in a file
|
||||
// ============================================================
|
||||
static long count_file_lines(const char* path) {
|
||||
std::ifstream f(path);
|
||||
if (!f.is_open()) return -1;
|
||||
long n = 0;
|
||||
std::string line;
|
||||
while (std::getline(f, line)) {
|
||||
if (!line.empty()) ++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: get file size in bytes, returns -1 if file doesn't exist
|
||||
// ============================================================
|
||||
static long file_size(const char* path) {
|
||||
std::ifstream f(path, std::ios::ate | std::ios::binary);
|
||||
if (!f.is_open()) return -1;
|
||||
return (long)f.tellg();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: check whether any line in the file matches a regex
|
||||
// ============================================================
|
||||
static bool file_has_regex_match(const char* path, const std::regex& re) {
|
||||
std::ifstream f(path);
|
||||
if (!f.is_open()) return false;
|
||||
std::string line;
|
||||
while (std::getline(f, line)) {
|
||||
if (std::regex_search(line, re)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: set pgsql_servers use_ssl and reload
|
||||
// ============================================================
|
||||
static bool set_pgsql_use_ssl(PGconn* admin, int value) {
|
||||
std::string sql = "UPDATE pgsql_servers SET use_ssl=" + std::to_string(value);
|
||||
if (!admin_exec(admin, sql.c_str())) return false;
|
||||
return admin_exec(admin, "LOAD PGSQL SERVERS TO RUNTIME");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helper: get pgsql-monitor_connect_interval (ms)
|
||||
// ============================================================
|
||||
static long get_monitor_interval(PGconn* admin) {
|
||||
std::string v = admin_query_value(admin,
|
||||
"SELECT Variable_Value FROM global_variables "
|
||||
"WHERE Variable_Name='pgsql-monitor_connect_interval'");
|
||||
return v.empty() ? 1000 : atol(v.c_str());
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
plan(9);
|
||||
|
||||
if (cl.getEnv()) {
|
||||
diag("Failed to get required environment variables");
|
||||
return exit_status();
|
||||
}
|
||||
|
||||
// Remove any leftover keylog file from a prior run
|
||||
::remove(KEYLOG_PATH);
|
||||
|
||||
// Open PgSQL admin connection
|
||||
auto admin_conn = open_admin();
|
||||
if (!admin_conn) {
|
||||
BAIL_OUT("Admin connection failed — cannot continue");
|
||||
return exit_status();
|
||||
}
|
||||
PGconn* admin = admin_conn.get();
|
||||
diag("PgSQL admin connected to %s:%d", cl.pgsql_admin_host, cl.pgsql_admin_port);
|
||||
|
||||
// Save original keylog file setting so we can restore it at the end
|
||||
std::string original_keylog = admin_query_value(admin,
|
||||
"SELECT Variable_Value FROM global_variables "
|
||||
"WHERE Variable_Name='admin-ssl_keylog_file'");
|
||||
diag("Original admin-ssl_keylog_file='%s'", original_keylog.c_str());
|
||||
|
||||
// ================================================================
|
||||
// Test 1: Basic keylog creation
|
||||
// ================================================================
|
||||
diag("---- Test 1: Basic keylog creation ----");
|
||||
|
||||
bool set_ok = set_keylog_file(admin, KEYLOG_PATH);
|
||||
diag("Set admin-ssl_keylog_file='%s' result=%s", KEYLOG_PATH, set_ok ? "ok" : "FAIL");
|
||||
|
||||
if (set_ok) {
|
||||
auto conn1 = make_pgsql_ssl_conn();
|
||||
if (PQstatus(conn1.get()) != CONNECTION_OK) {
|
||||
diag("PgSQL SSL connection failed: %s", PQerrorMessage(conn1.get()));
|
||||
}
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
long sz = file_size(KEYLOG_PATH);
|
||||
diag("Keylog file size after SSL PgSQL connection: %ld bytes", sz);
|
||||
ok(set_ok && sz > 0,
|
||||
"Test 1: Keylog file is non-empty after PgSQL SSL connection (size=%ld)", sz);
|
||||
|
||||
// ================================================================
|
||||
// Test 2: NSS format validation
|
||||
// ================================================================
|
||||
diag("---- Test 2: NSS Key Log Format validation ----");
|
||||
|
||||
std::regex nss_re(R"(^[A-Z_]+ [0-9a-fA-F]{64} [0-9a-fA-F]+$)");
|
||||
bool has_valid_line = file_has_regex_match(KEYLOG_PATH, nss_re);
|
||||
ok(has_valid_line,
|
||||
"Test 2: Keylog file contains valid NSS Key Log Format lines");
|
||||
|
||||
// ================================================================
|
||||
// Test 3: TLS version label check
|
||||
// ================================================================
|
||||
diag("---- Test 3: TLS 1.2/1.3 secret label check ----");
|
||||
|
||||
std::regex tls_label_re(
|
||||
R"(^(CLIENT_RANDOM|CLIENT_HANDSHAKE_TRAFFIC_SECRET|SERVER_HANDSHAKE_TRAFFIC_SECRET|)"
|
||||
R"(CLIENT_TRAFFIC_SECRET_\d+|SERVER_TRAFFIC_SECRET_\d+) )");
|
||||
bool has_tls_label = file_has_regex_match(KEYLOG_PATH, tls_label_re);
|
||||
ok(has_tls_label,
|
||||
"Test 3: Keylog contains TLS 1.2 CLIENT_RANDOM or TLS 1.3 traffic secret labels");
|
||||
|
||||
// ================================================================
|
||||
// Test 4: Concurrent connections — no corruption
|
||||
// ================================================================
|
||||
diag("---- Test 4: Concurrent SSL connections ----");
|
||||
|
||||
long lines_before = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines before concurrent test: %ld", lines_before);
|
||||
|
||||
const int NUM_THREADS = 8;
|
||||
std::atomic<int> conn_ok_count{0};
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(NUM_THREADS);
|
||||
|
||||
for (int i = 0; i < NUM_THREADS; ++i) {
|
||||
threads.emplace_back([&conn_ok_count]() {
|
||||
auto c = make_pgsql_ssl_conn();
|
||||
if (PQstatus(c.get()) == CONNECTION_OK) {
|
||||
++conn_ok_count;
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto& t : threads) t.join();
|
||||
usleep(200000);
|
||||
|
||||
long lines_after = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines after concurrent test: %ld (conn_ok=%d)", lines_after, (int)conn_ok_count);
|
||||
|
||||
bool all_valid = true;
|
||||
{
|
||||
std::ifstream f(KEYLOG_PATH);
|
||||
std::string line;
|
||||
while (std::getline(f, line)) {
|
||||
if (line.empty()) continue;
|
||||
if (!std::regex_search(line, nss_re)) {
|
||||
diag("Corrupt/unexpected line: '%s'", line.c_str());
|
||||
all_valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ok(all_valid && lines_after > lines_before,
|
||||
"Test 4: Concurrent SSL connections produced valid keylog lines without corruption "
|
||||
"(before=%ld after=%ld)", lines_before, lines_after);
|
||||
|
||||
// ================================================================
|
||||
// Test 5: Disable keylog — no new lines after clearing
|
||||
// ================================================================
|
||||
diag("---- Test 5: Disable keylog ----");
|
||||
|
||||
set_keylog_file(admin, "");
|
||||
usleep(50000);
|
||||
|
||||
long lines_disabled = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines before disable connection: %ld", lines_disabled);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
auto c = make_pgsql_ssl_conn();
|
||||
(void)c;
|
||||
}
|
||||
usleep(200000);
|
||||
|
||||
long lines_after_disable = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines after connections with keylog disabled: %ld", lines_after_disable);
|
||||
ok(lines_after_disable == lines_disabled,
|
||||
"Test 5: No new keylog lines written after disabling keylog "
|
||||
"(before=%ld after=%ld)", lines_disabled, lines_after_disable);
|
||||
|
||||
// ================================================================
|
||||
// Test 6: Log rotation — PROXYSQL FLUSH LOGS appends new secrets
|
||||
// ================================================================
|
||||
diag("---- Test 6: Log rotation via PROXYSQL FLUSH LOGS ----");
|
||||
|
||||
set_keylog_file(admin, KEYLOG_PATH);
|
||||
usleep(50000);
|
||||
|
||||
{
|
||||
auto c = make_pgsql_ssl_conn();
|
||||
(void)c;
|
||||
}
|
||||
usleep(100000);
|
||||
|
||||
long lines_pre_flush = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines before PROXYSQL FLUSH LOGS: %ld", lines_pre_flush);
|
||||
|
||||
bool flush_ok = admin_exec(admin, "PROXYSQL FLUSH LOGS");
|
||||
diag("PROXYSQL FLUSH LOGS result=%s", flush_ok ? "ok" : "FAIL");
|
||||
|
||||
{
|
||||
auto c = make_pgsql_ssl_conn();
|
||||
(void)c;
|
||||
}
|
||||
usleep(100000);
|
||||
|
||||
long lines_post_flush = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines after PROXYSQL FLUSH LOGS + new connection: %ld", lines_post_flush);
|
||||
ok(flush_ok && lines_post_flush > lines_pre_flush,
|
||||
"Test 6: New keylog secrets appended after PROXYSQL FLUSH LOGS "
|
||||
"(before=%ld after=%ld)", lines_pre_flush, lines_post_flush);
|
||||
|
||||
// ================================================================
|
||||
// Test 7: Monitor SSL keylog — enable use_ssl, wait, verify entries
|
||||
// ================================================================
|
||||
diag("---- Test 7: Monitor SSL keylog ----");
|
||||
|
||||
::remove(KEYLOG_PATH);
|
||||
set_keylog_file(admin, KEYLOG_PATH);
|
||||
usleep(50000);
|
||||
|
||||
long lines_before_monitor = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines before enabling monitor SSL: %ld", lines_before_monitor);
|
||||
|
||||
long monitor_interval_ms = get_monitor_interval(admin);
|
||||
diag("pgsql-monitor_connect_interval=%ld ms", monitor_interval_ms);
|
||||
|
||||
bool use_ssl_ok = set_pgsql_use_ssl(admin, 1);
|
||||
diag("Set pgsql_servers use_ssl=1 result=%s", use_ssl_ok ? "ok" : "FAIL");
|
||||
|
||||
useconds_t wait_us = (useconds_t)(monitor_interval_ms * 2 * 1000);
|
||||
if (wait_us > 10000000) wait_us = 10000000;
|
||||
diag("Waiting %u us for monitor cycles...", wait_us);
|
||||
usleep(wait_us);
|
||||
|
||||
long lines_after_monitor = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines after monitor SSL cycles: %ld", lines_after_monitor);
|
||||
ok(use_ssl_ok && lines_after_monitor > lines_before_monitor,
|
||||
"Test 7: Monitor SSL connections write keylog entries "
|
||||
"(before=%ld after=%ld)", lines_before_monitor, lines_after_monitor);
|
||||
|
||||
set_pgsql_use_ssl(admin, 0);
|
||||
usleep(50000);
|
||||
|
||||
// ================================================================
|
||||
// Test 8: Non-SSL PgSQL connection — no keylog entries added
|
||||
// ================================================================
|
||||
diag("---- Test 8: Non-SSL connection produces no keylog entries ----");
|
||||
|
||||
admin_exec(admin, "SET pgsql-monitor_enabled='false'");
|
||||
admin_exec(admin, "LOAD PGSQL VARIABLES TO RUNTIME");
|
||||
usleep(500000);
|
||||
|
||||
::remove(KEYLOG_PATH);
|
||||
set_keylog_file(admin, KEYLOG_PATH);
|
||||
usleep(50000);
|
||||
|
||||
long lines_nossl_before = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines before non-SSL connections: %ld", lines_nossl_before);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
auto c = make_pgsql_nossl_conn();
|
||||
if (PQstatus(c.get()) != CONNECTION_OK) {
|
||||
diag("Non-SSL PgSQL connection failed (may be expected): %s",
|
||||
PQerrorMessage(c.get()));
|
||||
}
|
||||
}
|
||||
usleep(200000);
|
||||
|
||||
long lines_nossl_after = count_file_lines(KEYLOG_PATH);
|
||||
diag("Lines after non-SSL connections: %ld", lines_nossl_after);
|
||||
ok(lines_nossl_after == lines_nossl_before,
|
||||
"Test 8: Non-SSL PgSQL connections do not add keylog entries "
|
||||
"(before=%ld after=%ld)", lines_nossl_before, lines_nossl_after);
|
||||
|
||||
admin_exec(admin, "SET pgsql-monitor_enabled='true'");
|
||||
admin_exec(admin, "LOAD PGSQL VARIABLES TO RUNTIME");
|
||||
|
||||
// ================================================================
|
||||
// Test 9: Invalid keylog path — graceful handling
|
||||
// ================================================================
|
||||
diag("---- Test 9: Invalid keylog path ----");
|
||||
|
||||
const char* bad_path = "/nonexistent/dir/proxysql_keylog.log";
|
||||
set_keylog_file(admin, bad_path);
|
||||
|
||||
{
|
||||
auto c = make_pgsql_ssl_conn();
|
||||
(void)c;
|
||||
}
|
||||
usleep(100000);
|
||||
|
||||
long bad_sz = file_size(bad_path);
|
||||
diag("bad_path size=%ld (expected -1)", bad_sz);
|
||||
|
||||
ok(bad_sz < 0,
|
||||
"Test 9: Invalid keylog path handled gracefully — file not created at bad path");
|
||||
|
||||
// ================================================================
|
||||
// Cleanup
|
||||
// ================================================================
|
||||
diag("---- Cleanup ----");
|
||||
|
||||
set_keylog_file(admin, original_keylog.empty() ? "" : original_keylog.c_str());
|
||||
|
||||
if (::remove(KEYLOG_PATH) == 0) {
|
||||
diag("Removed keylog file: %s", KEYLOG_PATH);
|
||||
}
|
||||
|
||||
return exit_status();
|
||||
}
|
||||
Loading…
Reference in new issue