@@ -1649,31 +1649,48 @@ int MR_ClusterInit(RedisModuleCtx* rctx, char *password) {
16491649 clusterCtx .password = password ? MR_STRDUP (password ) : NULL ;
16501650 memset (clusterCtx .myId , '0' , REDISMODULE_NODE_ID_LEN );
16511651
1652- RedisModuleServerInfoData * info = RedisModule_GetServerInfo (rctx , "Server" );
1653- const char * rlecVersion = RedisModule_ServerInfoGetFieldC (info , "rlec_version" );
16541652 /* Note: RedisModule_GetContextFlags() does NOT report
16551653 * REDISMODULE_CTX_FLAGS_CLUSTER yet at module-load time, so read the
16561654 * cluster-enabled config directly to learn the runtime mode. */
16571655 bool ossClusterRuntime = false;
16581656 RedisModuleCallReply * ceReply = RedisModule_Call (rctx , "config" , "cc" , "get" , "cluster-enabled" );
1659- if (ceReply && RedisModule_CallReplyType (ceReply ) == REDISMODULE_REPLY_ARRAY &&
1660- RedisModule_CallReplyLength (ceReply ) >= 2 ) {
1661- RedisModuleCallReply * val = RedisModule_CallReplyArrayElement (ceReply , 1 );
1662- if (RedisModule_CallReplyType (val ) == REDISMODULE_REPLY_STRING ) {
1657+ if (ceReply ) {
1658+ /* CONFIG GET replies as a flat array in RESP2 and as a map in RESP3.
1659+ * The module ctx defaults to RESP2, but handle both shapes so a future
1660+ * RESP3 default can't silently break detection and misclassify an
1661+ * OSS-cluster shard as enterprise. */
1662+ int ceType = RedisModule_CallReplyType (ceReply );
1663+ RedisModuleCallReply * val = NULL ;
1664+ if (ceType == REDISMODULE_REPLY_ARRAY && RedisModule_CallReplyLength (ceReply ) >= 2 ) {
1665+ val = RedisModule_CallReplyArrayElement (ceReply , 1 );
1666+ } else if (ceType == REDISMODULE_REPLY_MAP && RedisModule_CallReplyMapElement &&
1667+ RedisModule_CallReplyLength (ceReply ) >= 1 ) {
1668+ RedisModule_CallReplyMapElement (ceReply , 0 , NULL , & val );
1669+ }
1670+ if (val && RedisModule_CallReplyType (val ) == REDISMODULE_REPLY_STRING ) {
16631671 size_t vlen = 0 ;
16641672 const char * vstr = RedisModule_CallReplyStringPtr (val , & vlen );
1665- if (vstr && vlen == 3 && strncmp (vstr , "yes" , 3 ) == 0 ) {
1673+ /* CONFIG GET returns the canonical lowercase "yes"/"no" (Redis
1674+ * spec), so a case-sensitive compare of exactly 3 bytes is safe. */
1675+ if (vstr && vlen == 3 && memcmp (vstr , "yes" , 3 ) == 0 ) {
16661676 ossClusterRuntime = true;
16671677 }
16681678 }
1669- }
1670- if (ceReply ) {
16711679 RedisModule_FreeCallReply (ceReply );
16721680 }
1673- if (rlecVersion && !ossClusterRuntime ) {
1681+ /* rlec_version is only present on enterprise binaries. It was already
1682+ * parsed into MR_RlecMajorVersion by MR_GetRedisVersion() (run before
1683+ * MR_ClusterInit), so reuse it here instead of fetching Server info a
1684+ * second time; MR_RlecMajorVersion >= 0 means the field was present.
1685+ *
1686+ * Treat the shard as enterprise only when rlec_version is present AND we
1687+ * are not in OSS cluster mode. This is the load-bearing decision of the
1688+ * PR: it unblocks an enterprise binary running as an OSS cluster (e.g. the
1689+ * env0 testing setup), which must take the OSS path (internal-secret AUTH,
1690+ * no _proxy-filtered command flags) rather than the enterprise path. */
1691+ if (MR_RlecMajorVersion >= 0 && !ossClusterRuntime ) {
16741692 clusterCtx .isOss = false;
16751693 }
1676- RedisModule_FreeServerInfo (rctx , info );
16771694
16781695 RedisModule_Log (rctx , "notice" , "Detected redis %s (cluster-enabled=%s)" ,
16791696 clusterCtx .isOss ? "oss" : "enterprise" ,
0 commit comments