From d9346fe64dbbf2d1ebdc497a66860ad097fc1a88 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Fri, 16 Jan 2026 10:51:00 +0000 Subject: [PATCH] feat: Add AI features manager foundation - Add AI_Features_Manager coordinator class - Add AI_Vector_Storage interface (stub) - Add Anomaly_Detector class (stub for Phase 3) - Update includes and main initialization --- include/AI_Features_Manager.h | 128 +++++++++++ include/AI_Vector_Storage.h | 40 ++++ include/Anomaly_Detector.h | 105 +++++++++ include/proxysql.h | 6 + include/proxysql_structs.h | 2 + lib/AI_Features_Manager.cpp | 422 ++++++++++++++++++++++++++++++++++ lib/AI_Vector_Storage.cpp | 36 +++ lib/Anomaly_Detector.cpp | 71 ++++++ src/main.cpp | 16 ++ 9 files changed, 826 insertions(+) create mode 100644 include/AI_Features_Manager.h create mode 100644 include/AI_Vector_Storage.h create mode 100644 include/Anomaly_Detector.h create mode 100644 lib/AI_Features_Manager.cpp create mode 100644 lib/AI_Vector_Storage.cpp create mode 100644 lib/Anomaly_Detector.cpp diff --git a/include/AI_Features_Manager.h b/include/AI_Features_Manager.h new file mode 100644 index 000000000..68693cb63 --- /dev/null +++ b/include/AI_Features_Manager.h @@ -0,0 +1,128 @@ +#ifndef __CLASS_AI_FEATURES_MANAGER_H +#define __CLASS_AI_FEATURES_MANAGER_H + +#define AI_FEATURES_MANAGER_VERSION "0.1.0" + +#include "proxysql.h" +#include +#include + +// Forward declarations +class NL2SQL_Converter; +class Anomaly_Detector; +class SQLite3DB; + +/** + * @brief AI Features Manager + * + * Coordinates all AI features in ProxySQL: + * - NL2SQL (Natural Language to SQL) conversion + * - Anomaly detection for security + * - Vector storage for semantic caching + * - Hybrid model routing (local Ollama + cloud APIs) + * + * This class follows the same pattern as MCP_Threads_Handler and GenAI_Threads_Handler + * for configuration management and lifecycle. + */ +class AI_Features_Manager { +private: + int shutdown_; + pthread_rwlock_t rwlock; + + // Sub-components + NL2SQL_Converter* nl2sql_converter; + Anomaly_Detector* anomaly_detector; + SQLite3DB* vector_db; + + // Helper methods + int init_vector_db(); + int init_nl2sql(); + int init_anomaly_detector(); + void close_vector_db(); + void close_nl2sql(); + void close_anomaly_detector(); + +public: + /** + * @brief Configuration variables for AI features + * + * These are accessible via the admin interface with 'ai-' prefix + * and can be modified at runtime. + */ + struct { + // Master switches + bool ai_features_enabled; + bool ai_nl2sql_enabled; + bool ai_anomaly_detection_enabled; + + // NL2SQL configuration + char* ai_nl2sql_query_prefix; + char* ai_nl2sql_model_provider; + char* ai_nl2sql_ollama_model; + char* ai_nl2sql_openai_model; + char* ai_nl2sql_anthropic_model; + int ai_nl2sql_cache_similarity_threshold; + int ai_nl2sql_timeout_ms; + char* ai_nl2sql_openai_key; + char* ai_nl2sql_anthropic_key; + + // Anomaly detection configuration + int ai_anomaly_risk_threshold; + int ai_anomaly_similarity_threshold; + int ai_anomaly_rate_limit; + bool ai_anomaly_auto_block; + bool ai_anomaly_log_only; + + // Hybrid model routing + bool ai_prefer_local_models; + double ai_daily_budget_usd; + int ai_max_cloud_requests_per_hour; + + // Vector storage + char* ai_vector_db_path; + int ai_vector_dimension; + } variables; + + /** + * @brief Status variables (read-only counters) + */ + struct { + unsigned long long nl2sql_total_requests; + unsigned long long nl2sql_cache_hits; + unsigned long long nl2sql_local_model_calls; + unsigned long long nl2sql_cloud_model_calls; + unsigned long long anomaly_total_checks; + unsigned long long anomaly_blocked_queries; + unsigned long long anomaly_flagged_queries; + double daily_cloud_spend_usd; + } status_variables; + + AI_Features_Manager(); + ~AI_Features_Manager(); + + // Lifecycle + int init(); + void shutdown(); + + // Thread-safe locking + void wrlock(); + void wrunlock(); + + // Component access + NL2SQL_Converter* get_nl2sql() { return nl2sql_converter; } + Anomaly_Detector* get_anomaly_detector() { return anomaly_detector; } + SQLite3DB* get_vector_db() { return vector_db; } + + // Variable management (for admin interface) + char* get_variable(const char* name); + bool set_variable(const char* name, const char* value); + char** get_variables_list(); + + // Status reporting + std::string get_status_json(); +}; + +// Global instance +extern AI_Features_Manager *GloAI; + +#endif // __CLASS_AI_FEATURES_MANAGER_H diff --git a/include/AI_Vector_Storage.h b/include/AI_Vector_Storage.h new file mode 100644 index 000000000..f8a014e1a --- /dev/null +++ b/include/AI_Vector_Storage.h @@ -0,0 +1,40 @@ +#ifndef __CLASS_AI_VECTOR_STORAGE_H +#define __CLASS_AI_VECTOR_STORAGE_H + +#define AI_VECTOR_STORAGE_VERSION "0.1.0" + +#include "proxysql.h" +#include +#include + +/** + * @brief AI Vector Storage + * + * Handles vector operations for NL2SQL cache and anomaly detection + * using SQLite with sqlite-vec extension. + * + * Phase 1: Stub implementation + * Phase 2: Full implementation with embedding generation and similarity search + */ +class AI_Vector_Storage { +private: + std::string db_path; + +public: + AI_Vector_Storage(const char* path); + ~AI_Vector_Storage(); + + int init(); + void close(); + + // Vector operations (Phase 2) + int store_embedding(const std::string& text, const std::vector& embedding); + std::vector generate_embedding(const std::string& text); + std::vector> search_similar( + const std::string& query, + float threshold, + int limit + ); +}; + +#endif // __CLASS_AI_VECTOR_STORAGE_H diff --git a/include/Anomaly_Detector.h b/include/Anomaly_Detector.h new file mode 100644 index 000000000..66ed023c8 --- /dev/null +++ b/include/Anomaly_Detector.h @@ -0,0 +1,105 @@ +#ifndef __CLASS_ANOMALY_DETECTOR_H +#define __CLASS_ANOMALY_DETECTOR_H + +#define ANOMALY_DETECTOR_VERSION "0.1.0" + +#include "proxysql.h" +#include +#include +#include + +// Forward declarations +class SQLite3DB; + +/** + * @brief Anomaly detection result + */ +struct AnomalyResult { + bool is_anomaly; ///< True if anomaly detected + float risk_score; ///< 0.0-1.0 + std::string anomaly_type; ///< Type of anomaly + std::string explanation; ///< Human-readable explanation + std::vector matched_rules; ///< Rule names that matched + bool should_block; ///< Whether to block query + + AnomalyResult() : is_anomaly(false), risk_score(0.0f), should_block(false) {} +}; + +/** + * @brief Query fingerprint for behavioral analysis + */ +struct QueryFingerprint { + std::string query_pattern; ///< Normalized query + std::string user; + std::string client_host; + std::string schema; + uint64_t timestamp; + int affected_rows; + int execution_time_ms; +}; + +/** + * @brief Real-time Anomaly Detector + * + * Detects security threats and anomalous behavior using: + * - Embedding-based similarity to known threats + * - Statistical outlier detection + * - Rule-based pattern matching + */ +class Anomaly_Detector { +private: + struct { + bool enabled; + int risk_threshold; + int similarity_threshold; + int rate_limit; + bool auto_block; + bool log_only; + } config; + + SQLite3DB* vector_db; + + // Behavioral tracking + struct UserStats { + uint64_t query_count; + uint64_t last_query_time; + std::vector recent_queries; + }; + std::unordered_map user_statistics; + + // Detection methods + AnomalyResult check_sql_injection(const std::string& query); + AnomalyResult check_embedding_similarity(const std::string& query, const std::vector& embedding); + AnomalyResult check_statistical_anomaly(const QueryFingerprint& fp); + AnomalyResult check_rate_limiting(const std::string& user, const std::string& client_host); + std::vector get_query_embedding(const std::string& query); + void update_user_statistics(const QueryFingerprint& fp); + std::string normalize_query(const std::string& query); + +public: + Anomaly_Detector(); + ~Anomaly_Detector(); + + // Initialization + int init(); + void close(); + + // Main detection method + AnomalyResult analyze(const std::string& query, const std::string& user, + const std::string& client_host, const std::string& schema); + + // Threat pattern management + int add_threat_pattern(const std::string& pattern_name, const std::string& query_example, + const std::string& pattern_type, int severity); + std::string list_threat_patterns(); + bool remove_threat_pattern(int pattern_id); + + // Statistics and monitoring + std::string get_statistics(); + void clear_user_statistics(); +}; + +// Global instance (defined by AI_Features_Manager) +// extern Anomaly_Detector *GloAnomaly; + +#endif // __CLASS_ANOMALY_DETECTOR_H diff --git a/include/proxysql.h b/include/proxysql.h index 0af0ca396..f80c8f7c9 100644 --- a/include/proxysql.h +++ b/include/proxysql.h @@ -61,6 +61,12 @@ #include "proxysql_sslkeylog.h" #include "jemalloc.h" +// AI Features includes +#include "AI_Features_Manager.h" +#include "NL2SQL_Converter.h" +#include "Anomaly_Detector.h" +#include "AI_Vector_Storage.h" + #ifndef NOJEM #if defined(__APPLE__) && defined(__MACH__) #ifndef mallctl diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index 141db5938..4aa7b6c8e 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -160,6 +160,8 @@ enum debug_module { PROXY_DEBUG_MONITOR, PROXY_DEBUG_CLUSTER, PROXY_DEBUG_GENAI, + PROXY_DEBUG_NL2SQL, + PROXY_DEBUG_ANOMALY, PROXY_DEBUG_UNKNOWN // this module doesn't exist. It is used only to define the last possible module }; diff --git a/lib/AI_Features_Manager.cpp b/lib/AI_Features_Manager.cpp new file mode 100644 index 000000000..d9cddcca5 --- /dev/null +++ b/lib/AI_Features_Manager.cpp @@ -0,0 +1,422 @@ +#include "AI_Features_Manager.h" +#include "NL2SQL_Converter.h" +#include "Anomaly_Detector.h" +#include "sqlite3db.h" +#include "proxysql_utils.h" +#include +#include +#include +#include // for dirname + +// Global instance is defined in src/main.cpp +extern AI_Features_Manager *GloAI; + +// Forward declaration to avoid header ordering issues +class ProxySQL_Admin; +extern ProxySQL_Admin *GloAdmin; + +AI_Features_Manager::AI_Features_Manager() + : shutdown_(0), nl2sql_converter(NULL), anomaly_detector(NULL), vector_db(NULL) +{ + pthread_rwlock_init(&rwlock, NULL); + + // Initialize configuration variables to defaults + variables.ai_features_enabled = false; + variables.ai_nl2sql_enabled = false; + variables.ai_anomaly_detection_enabled = false; + + variables.ai_nl2sql_query_prefix = strdup("NL2SQL:"); + variables.ai_nl2sql_model_provider = strdup("ollama"); + variables.ai_nl2sql_ollama_model = strdup("llama3.2"); + variables.ai_nl2sql_openai_model = strdup("gpt-4o-mini"); + variables.ai_nl2sql_anthropic_model = strdup("claude-3-haiku"); + variables.ai_nl2sql_cache_similarity_threshold = 85; + variables.ai_nl2sql_timeout_ms = 30000; + variables.ai_nl2sql_openai_key = NULL; + variables.ai_nl2sql_anthropic_key = NULL; + + variables.ai_anomaly_risk_threshold = 70; + variables.ai_anomaly_similarity_threshold = 80; + variables.ai_anomaly_rate_limit = 100; + variables.ai_anomaly_auto_block = true; + variables.ai_anomaly_log_only = false; + + variables.ai_prefer_local_models = true; + variables.ai_daily_budget_usd = 10.0; + variables.ai_max_cloud_requests_per_hour = 100; + + variables.ai_vector_db_path = strdup("/var/lib/proxysql/ai_features.db"); + variables.ai_vector_dimension = 1536; // OpenAI text-embedding-3-small + + // Initialize status counters + memset(&status_variables, 0, sizeof(status_variables)); +} + +AI_Features_Manager::~AI_Features_Manager() { + shutdown(); + + // Free configuration strings + free(variables.ai_nl2sql_query_prefix); + free(variables.ai_nl2sql_model_provider); + free(variables.ai_nl2sql_ollama_model); + free(variables.ai_nl2sql_openai_model); + free(variables.ai_nl2sql_anthropic_model); + free(variables.ai_nl2sql_openai_key); + free(variables.ai_nl2sql_anthropic_key); + free(variables.ai_vector_db_path); + + pthread_rwlock_destroy(&rwlock); +} + +int AI_Features_Manager::init_vector_db() { + proxy_info("AI: Initializing vector storage at %s\n", variables.ai_vector_db_path); + + // Ensure directory exists + char* path_copy = strdup(variables.ai_vector_db_path); + char* dir = dirname(path_copy); + struct stat st; + if (stat(dir, &st) != 0) { + // Create directory if it doesn't exist + char cmd[512]; + snprintf(cmd, sizeof(cmd), "mkdir -p %s", dir); + system(cmd); + } + free(path_copy); + + vector_db = new SQLite3DB(); + char path_buf[512]; + strncpy(path_buf, variables.ai_vector_db_path, sizeof(path_buf) - 1); + path_buf[sizeof(path_buf) - 1] = '\0'; + int rc = vector_db->open(path_buf, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + if (rc != SQLITE_OK) { + proxy_error("AI: Failed to open vector database: %s\n", variables.ai_vector_db_path); + delete vector_db; + vector_db = NULL; + return -1; + } + + // Create tables for NL2SQL cache + const char* create_nl2sql_cache = + "CREATE TABLE IF NOT EXISTS nl2sql_cache (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "natural_language TEXT NOT NULL," + "generated_sql TEXT NOT NULL," + "schema_context TEXT," + "embedding BLOB," + "hit_count INTEGER DEFAULT 0," + "last_hit INTEGER," + "created_at INTEGER DEFAULT (strftime('%s', 'now'))" + ");"; + + if (vector_db->execute(create_nl2sql_cache) != 0) { + proxy_error("AI: Failed to create nl2sql_cache table\n"); + return -1; + } + + // Create table for anomaly patterns + const char* create_anomaly_patterns = + "CREATE TABLE IF NOT EXISTS anomaly_patterns (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "pattern_name TEXT," + "pattern_type TEXT," // 'sql_injection', 'dos', 'privilege_escalation' + "query_example TEXT," + "embedding BLOB," + "severity INTEGER," // 1-10 + "created_at INTEGER DEFAULT (strftime('%s', 'now'))" + ");"; + + if (vector_db->execute(create_anomaly_patterns) != 0) { + proxy_error("AI: Failed to create anomaly_patterns table\n"); + return -1; + } + + // Create table for query history + const char* create_query_history = + "CREATE TABLE IF NOT EXISTS query_history (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "query_text TEXT NOT NULL," + "generated_sql TEXT," + "embedding BLOB," + "execution_time_ms INTEGER," + "success BOOLEAN," + "timestamp INTEGER DEFAULT (strftime('%s', 'now'))" + ");"; + + if (vector_db->execute(create_query_history) != 0) { + proxy_error("AI: Failed to create query_history table\n"); + return -1; + } + + proxy_info("AI: Vector storage initialized successfully\n"); + return 0; +} + +int AI_Features_Manager::init_nl2sql() { + if (!variables.ai_nl2sql_enabled) { + proxy_info("AI: NL2SQL disabled, skipping initialization\n"); + return 0; + } + + proxy_info("AI: Initializing NL2SQL Converter\n"); + + nl2sql_converter = new NL2SQL_Converter(); + if (nl2sql_converter->init() != 0) { + proxy_error("AI: Failed to initialize NL2SQL Converter\n"); + delete nl2sql_converter; + nl2sql_converter = NULL; + return -1; + } + + proxy_info("AI: NL2SQL Converter initialized\n"); + return 0; +} + +int AI_Features_Manager::init_anomaly_detector() { + if (!variables.ai_anomaly_detection_enabled) { + proxy_info("AI: Anomaly detection disabled, skipping initialization\n"); + return 0; + } + + proxy_info("AI: Initializing Anomaly Detector\n"); + + anomaly_detector = new Anomaly_Detector(); + if (anomaly_detector->init() != 0) { + proxy_error("AI: Failed to initialize Anomaly Detector\n"); + delete anomaly_detector; + anomaly_detector = NULL; + return -1; + } + + proxy_info("AI: Anomaly Detector initialized\n"); + return 0; +} + +void AI_Features_Manager::close_vector_db() { + if (vector_db) { + delete vector_db; + vector_db = NULL; + } +} + +void AI_Features_Manager::close_nl2sql() { + if (nl2sql_converter) { + nl2sql_converter->close(); + delete nl2sql_converter; + nl2sql_converter = NULL; + } +} + +void AI_Features_Manager::close_anomaly_detector() { + if (anomaly_detector) { + anomaly_detector->close(); + delete anomaly_detector; + anomaly_detector = NULL; + } +} + +int AI_Features_Manager::init() { + proxy_info("AI: Initializing AI Features Manager v%s\n", AI_FEATURES_MANAGER_VERSION); + + if (!variables.ai_features_enabled) { + proxy_info("AI: AI features disabled by configuration\n"); + return 0; + } + + // Initialize vector storage first (needed by both NL2SQL and Anomaly Detector) + if (init_vector_db() != 0) { + proxy_error("AI: Failed to initialize vector storage\n"); + return -1; + } + + // Initialize NL2SQL + if (init_nl2sql() != 0) { + proxy_error("AI: Failed to initialize NL2SQL\n"); + return -1; + } + + // Initialize Anomaly Detector + if (init_anomaly_detector() != 0) { + proxy_error("AI: Failed to initialize Anomaly Detector\n"); + return -1; + } + + proxy_info("AI: AI Features Manager initialized successfully\n"); + return 0; +} + +void AI_Features_Manager::shutdown() { + if (shutdown_) return; + shutdown_ = 1; + + proxy_info("AI: Shutting down AI Features Manager\n"); + + close_nl2sql(); + close_anomaly_detector(); + close_vector_db(); + + proxy_info("AI: AI Features Manager shutdown complete\n"); +} + +void AI_Features_Manager::wrlock() { + pthread_rwlock_wrlock(&rwlock); +} + +void AI_Features_Manager::wrunlock() { + pthread_rwlock_unlock(&rwlock); +} + +char* AI_Features_Manager::get_variable(const char* name) { + if (strcmp(name, "ai_features_enabled") == 0) + return variables.ai_features_enabled ? strdup("true") : strdup("false"); + if (strcmp(name, "ai_nl2sql_enabled") == 0) + return variables.ai_nl2sql_enabled ? strdup("true") : strdup("false"); + if (strcmp(name, "ai_anomaly_detection_enabled") == 0) + return variables.ai_anomaly_detection_enabled ? strdup("true") : strdup("false"); + if (strcmp(name, "ai_nl2sql_query_prefix") == 0) + return strdup(variables.ai_nl2sql_query_prefix); + if (strcmp(name, "ai_nl2sql_model_provider") == 0) + return strdup(variables.ai_nl2sql_model_provider); + if (strcmp(name, "ai_nl2sql_ollama_model") == 0) + return strdup(variables.ai_nl2sql_ollama_model); + if (strcmp(name, "ai_nl2sql_openai_model") == 0) + return strdup(variables.ai_nl2sql_openai_model); + if (strcmp(name, "ai_anomaly_risk_threshold") == 0) { + char buf[32]; + snprintf(buf, sizeof(buf), "%d", variables.ai_anomaly_risk_threshold); + return strdup(buf); + } + if (strcmp(name, "ai_prefer_local_models") == 0) + return variables.ai_prefer_local_models ? strdup("true") : strdup("false"); + if (strcmp(name, "ai_vector_db_path") == 0) + return strdup(variables.ai_vector_db_path); + + return NULL; +} + +bool AI_Features_Manager::set_variable(const char* name, const char* value) { + wrlock(); + + bool changed = false; + + if (strcmp(name, "ai_features_enabled") == 0) { + bool new_val = (strcmp(value, "true") == 0); + changed = (variables.ai_features_enabled != new_val); + variables.ai_features_enabled = new_val; + } + else if (strcmp(name, "ai_nl2sql_enabled") == 0) { + bool new_val = (strcmp(value, "true") == 0); + changed = (variables.ai_nl2sql_enabled != new_val); + variables.ai_nl2sql_enabled = new_val; + } + else if (strcmp(name, "ai_anomaly_detection_enabled") == 0) { + bool new_val = (strcmp(value, "true") == 0); + changed = (variables.ai_anomaly_detection_enabled != new_val); + variables.ai_anomaly_detection_enabled = new_val; + } + else if (strcmp(name, "ai_nl2sql_query_prefix") == 0) { + free(variables.ai_nl2sql_query_prefix); + variables.ai_nl2sql_query_prefix = strdup(value); + changed = true; + } + else if (strcmp(name, "ai_nl2sql_model_provider") == 0) { + free(variables.ai_nl2sql_model_provider); + variables.ai_nl2sql_model_provider = strdup(value); + changed = true; + } + else if (strcmp(name, "ai_nl2sql_ollama_model") == 0) { + free(variables.ai_nl2sql_ollama_model); + variables.ai_nl2sql_ollama_model = strdup(value); + changed = true; + } + else if (strcmp(name, "ai_nl2sql_openai_model") == 0) { + free(variables.ai_nl2sql_openai_model); + variables.ai_nl2sql_openai_model = strdup(value); + changed = true; + } + else if (strcmp(name, "ai_anomaly_risk_threshold") == 0) { + variables.ai_anomaly_risk_threshold = atoi(value); + changed = true; + } + else if (strcmp(name, "ai_prefer_local_models") == 0) { + variables.ai_prefer_local_models = (strcmp(value, "true") == 0); + changed = true; + } + else if (strcmp(name, "ai_vector_db_path") == 0) { + free(variables.ai_vector_db_path); + variables.ai_vector_db_path = strdup(value); + changed = true; + } + + wrunlock(); + return changed; +} + +char** AI_Features_Manager::get_variables_list() { + // Return NULL-terminated array of variable names + static const char* vars[] = { + "ai_features_enabled", + "ai_nl2sql_enabled", + "ai_anomaly_detection_enabled", + "ai_nl2sql_query_prefix", + "ai_nl2sql_model_provider", + "ai_nl2sql_ollama_model", + "ai_nl2sql_openai_model", + "ai_nl2sql_anthropic_model", + "ai_nl2sql_cache_similarity_threshold", + "ai_nl2sql_timeout_ms", + "ai_anomaly_risk_threshold", + "ai_anomaly_similarity_threshold", + "ai_anomaly_rate_limit", + "ai_anomaly_auto_block", + "ai_anomaly_log_only", + "ai_prefer_local_models", + "ai_daily_budget_usd", + "ai_max_cloud_requests_per_hour", + "ai_vector_db_path", + "ai_vector_dimension", + NULL + }; + + // Clone the array + char** result = (char**)malloc(sizeof(char*) * 21); + for (int i = 0; vars[i]; i++) { + result[i] = strdup(vars[i]); + } + result[20] = NULL; + + return result; +} + +std::string AI_Features_Manager::get_status_json() { + char buf[1024]; + snprintf(buf, sizeof(buf), + "{" + "\"version\": \"%s\"," + "\"nl2sql\": {" + "\"total_requests\": %llu," + "\"cache_hits\": %llu," + "\"local_calls\": %llu," + "\"cloud_calls\": %llu" + "}," + "\"anomaly\": {" + "\"total_checks\": %llu," + "\"blocked\": %llu," + "\"flagged\": %llu" + "}," + "\"spend\": {" + "\"daily_usd\": %.2f" + "}" + "}", + AI_FEATURES_MANAGER_VERSION, + status_variables.nl2sql_total_requests, + status_variables.nl2sql_cache_hits, + status_variables.nl2sql_local_model_calls, + status_variables.nl2sql_cloud_model_calls, + status_variables.anomaly_total_checks, + status_variables.anomaly_blocked_queries, + status_variables.anomaly_flagged_queries, + status_variables.daily_cloud_spend_usd + ); + + return std::string(buf); +} diff --git a/lib/AI_Vector_Storage.cpp b/lib/AI_Vector_Storage.cpp new file mode 100644 index 000000000..3930782af --- /dev/null +++ b/lib/AI_Vector_Storage.cpp @@ -0,0 +1,36 @@ +#include "AI_Vector_Storage.h" +#include "proxysql_utils.h" + +AI_Vector_Storage::AI_Vector_Storage(const char* path) : db_path(path) { +} + +AI_Vector_Storage::~AI_Vector_Storage() { +} + +int AI_Vector_Storage::init() { + proxy_info("AI: Vector Storage initialized (stub)\n"); + return 0; +} + +void AI_Vector_Storage::close() { + proxy_info("AI: Vector Storage closed\n"); +} + +int AI_Vector_Storage::store_embedding(const std::string& text, const std::vector& embedding) { + // Phase 2: Implement embedding storage + return 0; +} + +std::vector AI_Vector_Storage::generate_embedding(const std::string& text) { + // Phase 2: Implement embedding generation via GenAI module or external API + return std::vector(); +} + +std::vector> AI_Vector_Storage::search_similar( + const std::string& query, + float threshold, + int limit +) { + // Phase 2: Implement similarity search using sqlite-vec + return std::vector>(); +} diff --git a/lib/Anomaly_Detector.cpp b/lib/Anomaly_Detector.cpp new file mode 100644 index 000000000..9ad15bf41 --- /dev/null +++ b/lib/Anomaly_Detector.cpp @@ -0,0 +1,71 @@ +#include "Anomaly_Detector.h" +#include "sqlite3db.h" +#include "proxysql_utils.h" +#include +#include + +// Global instance is defined elsewhere if needed +// Anomaly_Detector *GloAnomaly = NULL; + +Anomaly_Detector::Anomaly_Detector() : vector_db(NULL) { + config.enabled = true; + config.risk_threshold = 70; + config.similarity_threshold = 80; + config.rate_limit = 100; + config.auto_block = true; + config.log_only = false; +} + +Anomaly_Detector::~Anomaly_Detector() { +} + +int Anomaly_Detector::init() { + proxy_info("Anomaly: Initializing Anomaly Detector v%s\n", ANOMALY_DETECTOR_VERSION); + + // Vector DB will be provided by AI_Features_Manager + // This is a stub implementation for Phase 1 + + proxy_info("Anomaly: Anomaly Detector initialized (stub)\n"); + return 0; +} + +void Anomaly_Detector::close() { + proxy_info("Anomaly: Anomaly Detector closed\n"); +} + +AnomalyResult Anomaly_Detector::analyze(const std::string& query, const std::string& user, + const std::string& client_host, const std::string& schema) { + AnomalyResult result; + + // Stub implementation - Phase 3 will implement full functionality + proxy_debug(PROXY_DEBUG_ANOMALY, "Anomaly: Analyzing query from %s@%s\n", user.c_str(), client_host.c_str()); + + result.is_anomaly = false; + result.risk_score = 0.0f; + result.should_block = false; + + return result; +} + +int Anomaly_Detector::add_threat_pattern(const std::string& pattern_name, const std::string& query_example, + const std::string& pattern_type, int severity) { + proxy_info("Anomaly: Adding threat pattern: %s\n", pattern_name.c_str()); + return 0; +} + +std::string Anomaly_Detector::list_threat_patterns() { + return "[]"; +} + +bool Anomaly_Detector::remove_threat_pattern(int pattern_id) { + proxy_info("Anomaly: Removing threat pattern: %d\n", pattern_id); + return true; +} + +std::string Anomaly_Detector::get_statistics() { + return "{\"users_tracked\": 0}"; +} + +void Anomaly_Detector::clear_user_statistics() { + user_statistics.clear(); +} diff --git a/src/main.cpp b/src/main.cpp index 37a0e4c2c..9defb9ed8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -481,6 +481,7 @@ MySQL_Threads_Handler *GloMTH = NULL; PgSQL_Threads_Handler* GloPTH = NULL; MCP_Threads_Handler* GloMCPH = NULL; GenAI_Threads_Handler* GloGATH = NULL; +AI_Features_Manager *GloAI = NULL; Web_Interface *GloWebInterface; MySQL_STMT_Manager_v14 *GloMyStmt; PgSQL_STMT_Manager *GloPgStmt; @@ -941,6 +942,12 @@ void ProxySQL_Main_init_main_modules() { GloGATH = _tmp_GloGATH; } +void ProxySQL_Main_init_AI_module() { + GloAI = new AI_Features_Manager(); + GloAI->init(); + proxy_info("AI Features module initialized\n"); +} + void ProxySQL_Main_init_MCP_module() { GloMCPH = new MCP_Threads_Handler(); GloMCPH->init(); @@ -1290,6 +1297,14 @@ void ProxySQL_Main_shutdown_all_modules() { GloGATH = NULL; #ifdef DEBUG std::cerr << "GloGATH shutdown in "; +#endif + } + if (GloAI) { + cpu_timer t; + delete GloAI; + GloAI = NULL; +#ifdef DEBUG + std::cerr << "GloAI shutdown in "; #endif } if (GloMyLogger) { @@ -1457,6 +1472,7 @@ void ProxySQL_Main_init_phase2___not_started(const bootstrap_info_t& boostrap_in ProxySQL_Main_init_main_modules(); ProxySQL_Main_init_MCP_module(); + ProxySQL_Main_init_AI_module(); ProxySQL_Main_init_Admin_module(boostrap_info); GloMTH->print_version();