From c688537d497f1edb70a0b52a9e9d7581de383baa Mon Sep 17 00:00:00 2001 From: Raz Monsonego <74051729+raz-mon@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:52:41 +0200 Subject: [PATCH] Add flag for ability of a module context to execute debug commands (#13774) This PR adds a flag to the `RM_GetContextFlags` module-API function that depicts whether the context may execute debug commands, according to redis's standards. --- src/module.c | 11 +++++++++++ src/redismodule.h | 4 +++- tests/modules/basics.c | 21 ++++++++++++++++++++- tests/unit/moduleapi/basics.tcl | 24 ++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/module.c b/src/module.c index 644d24ad4..e8fd91f53 100644 --- a/src/module.c +++ b/src/module.c @@ -3901,6 +3901,9 @@ int RM_GetSelectedDb(RedisModuleCtx *ctx) { * context is using RESP3. * * * REDISMODULE_CTX_FLAGS_SERVER_STARTUP: The Redis instance is starting + * + * * REDISMODULE_CTX_FLAGS_DEBUG_ENABLED: Debug commands are enabled for this + * context. */ int RM_GetContextFlags(RedisModuleCtx *ctx) { int flags = 0; @@ -3923,6 +3926,9 @@ int RM_GetContextFlags(RedisModuleCtx *ctx) { if (c && (c->flags & (CLIENT_DIRTY_CAS|CLIENT_DIRTY_EXEC))) { flags |= REDISMODULE_CTX_FLAGS_MULTI_DIRTY; } + if (c && allowProtectedAction(server.enable_debug_cmd, c)) { + flags |= REDISMODULE_CTX_FLAGS_DEBUG_ENABLED; + } } if (scriptIsRunning()) @@ -3990,6 +3996,11 @@ int RM_GetContextFlags(RedisModuleCtx *ctx) { if (listLength(server.loadmodule_queue) > 0) flags |= REDISMODULE_CTX_FLAGS_SERVER_STARTUP; + /* If debug commands are completely enabled */ + if (server.enable_debug_cmd == PROTECTED_ACTION_ALLOWED_YES) { + flags |= REDISMODULE_CTX_FLAGS_DEBUG_ENABLED; + } + return flags; } diff --git a/src/redismodule.h b/src/redismodule.h index b8f00e816..6964e692e 100644 --- a/src/redismodule.h +++ b/src/redismodule.h @@ -208,11 +208,13 @@ typedef struct RedisModuleStreamID { #define REDISMODULE_CTX_FLAGS_ASYNC_LOADING (1<<23) /* Redis is starting. */ #define REDISMODULE_CTX_FLAGS_SERVER_STARTUP (1<<24) +/* This context can call execute debug commands. */ +#define REDISMODULE_CTX_FLAGS_DEBUG_ENABLED (1<<25) /* Next context flag, must be updated when adding new flags above! This flag should not be used directly by the module. * Use RedisModule_GetContextFlagsAll instead. */ -#define _REDISMODULE_CTX_FLAGS_NEXT (1<<25) +#define _REDISMODULE_CTX_FLAGS_NEXT (1<<26) /* Keyspace changes notification classes. Every class is associated with a * character for configuration purposes. diff --git a/tests/modules/basics.c b/tests/modules/basics.c index 15b9f5619..4e8bfba90 100644 --- a/tests/modules/basics.c +++ b/tests/modules/basics.c @@ -794,6 +794,21 @@ int TestAssertIntegerReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply, lon return 1; } +/* Replies "yes", "no" otherwise if the context may execute debug commands */ +int TestCanDebug(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + REDISMODULE_NOT_USED(argv); + REDISMODULE_NOT_USED(argc); + int flags = RedisModule_GetContextFlags(ctx); + int allFlags = RedisModule_GetContextFlagsAll(); + if ((allFlags & REDISMODULE_CTX_FLAGS_DEBUG_ENABLED) && + (flags & REDISMODULE_CTX_FLAGS_DEBUG_ENABLED)) { + RedisModule_ReplyWithSimpleString(ctx, "yes"); + } else { + RedisModule_ReplyWithSimpleString(ctx, "no"); + } + return REDISMODULE_OK; +} + #define T(name,...) \ do { \ RedisModule_Log(ctx,"warning","Testing %s", name); \ @@ -802,7 +817,7 @@ int TestAssertIntegerReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply, lon /* TEST.BASICS -- Run all the tests. * Note: it is useful to run these tests from the module rather than TCL - * since it's easier to check the reply types like that (make a distinction + * since it's easier to check the reply types like that make a distinction * between 0 and "0", etc. */ int TestBasics(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { REDISMODULE_NOT_USED(argv); @@ -1017,6 +1032,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) TestGetResp,"readonly",1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"test.candebug", + TestCanDebug,"readonly",1,1,1) == REDISMODULE_ERR) + return REDISMODULE_ERR; + RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_SET | diff --git a/tests/unit/moduleapi/basics.tcl b/tests/unit/moduleapi/basics.tcl index 042e3474a..1fcc9487d 100644 --- a/tests/unit/moduleapi/basics.tcl +++ b/tests/unit/moduleapi/basics.tcl @@ -44,3 +44,27 @@ start_server {tags {"modules external:skip"} overrides {enable-module-command no assert_error "ERR *MODULE command not allowed*" {r module load $testmodule} } } + +start_server {tags {"modules external:skip"} overrides {enable-debug-command no}} { + r module load $testmodule + + test {debug command disabled} { + assert_equal {no} [r test.candebug] + } +} + +start_server {tags {"modules external:skip"} overrides {enable-debug-command yes}} { + r module load $testmodule + + test {debug command enabled} { + assert_equal {yes} [r test.candebug] + } +} + +start_server {tags {"modules external:skip"} overrides {enable-debug-command local}} { + r module load $testmodule + + test {debug commands are enabled for local connection} { + assert_equal {yes} [r test.candebug] + } +}