fix(scanner): support redis sentinel in redisson config (#154)

* fix(scanner): migrate scan stream to redisson

* fix(web): update security audit pending labels

* fix(scanner): support redis sentinel in redisson config
This commit is contained in:
XiaoSeS 2026-03-24 15:54:39 +08:00 committed by GitHub
parent 747f649fb7
commit 0fcc40cd4c
2 changed files with 108 additions and 16 deletions

View file

@ -3,6 +3,7 @@ package com.iflytek.skillhub.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
@ -10,6 +11,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import java.util.List;
@Configuration
@ConditionalOnProperty(prefix = "skillhub.security.scanner", name = "enabled", havingValue = "true")
public class RedissonConfig {
@ -21,36 +24,74 @@ public class RedissonConfig {
static Config createConfig(RedisProperties redisProperties) {
Config config = new Config();
if (hasSentinelConfiguration(redisProperties)) {
configureSentinelServers(config, redisProperties);
return config;
}
SingleServerConfig singleServerConfig = config.useSingleServer()
.setAddress(resolveAddress(redisProperties))
.setDatabase(redisProperties.getDatabase());
if (StringUtils.hasText(redisProperties.getUsername())) {
singleServerConfig.setUsername(redisProperties.getUsername());
}
if (StringUtils.hasText(redisProperties.getPassword())) {
singleServerConfig.setPassword(redisProperties.getPassword());
}
if (StringUtils.hasText(redisProperties.getClientName())) {
singleServerConfig.setClientName(redisProperties.getClientName());
}
if (redisProperties.getTimeout() != null) {
singleServerConfig.setTimeout(Math.toIntExact(redisProperties.getTimeout().toMillis()));
}
if (redisProperties.getConnectTimeout() != null) {
singleServerConfig.setConnectTimeout(Math.toIntExact(redisProperties.getConnectTimeout().toMillis()));
}
applySharedSettings(singleServerConfig, redisProperties);
return config;
}
private static void configureSentinelServers(Config config, RedisProperties redisProperties) {
SentinelServersConfig sentinelServersConfig = config.useSentinelServers()
.setMasterName(redisProperties.getSentinel().getMaster())
.setDatabase(redisProperties.getDatabase());
List<String> nodes = redisProperties.getSentinel().getNodes();
nodes.stream()
.map(String::trim)
.filter(StringUtils::hasText)
.map(node -> withRedisScheme(node, redisProperties))
.forEach(sentinelServersConfig::addSentinelAddress);
applySharedSettings(sentinelServersConfig, redisProperties);
}
private static boolean hasSentinelConfiguration(RedisProperties redisProperties) {
return redisProperties.getSentinel() != null
&& StringUtils.hasText(redisProperties.getSentinel().getMaster())
&& redisProperties.getSentinel().getNodes() != null
&& !redisProperties.getSentinel().getNodes().isEmpty();
}
private static void applySharedSettings(org.redisson.config.BaseConfig<?> serverConfig,
RedisProperties redisProperties) {
if (StringUtils.hasText(redisProperties.getUsername())) {
serverConfig.setUsername(redisProperties.getUsername());
}
if (StringUtils.hasText(redisProperties.getPassword())) {
serverConfig.setPassword(redisProperties.getPassword());
}
if (StringUtils.hasText(redisProperties.getClientName())) {
serverConfig.setClientName(redisProperties.getClientName());
}
if (redisProperties.getTimeout() != null) {
serverConfig.setTimeout(Math.toIntExact(redisProperties.getTimeout().toMillis()));
}
if (redisProperties.getConnectTimeout() != null) {
serverConfig.setConnectTimeout(Math.toIntExact(redisProperties.getConnectTimeout().toMillis()));
}
}
private static String resolveAddress(RedisProperties redisProperties) {
if (StringUtils.hasText(redisProperties.getUrl())) {
return redisProperties.getUrl();
}
return withRedisScheme(redisProperties.getHost() + ":" + redisProperties.getPort(), redisProperties);
}
private static String withRedisScheme(String address, RedisProperties redisProperties) {
if (address.startsWith("redis://") || address.startsWith("rediss://")) {
return address;
}
String scheme = redisProperties.getSsl() != null && redisProperties.getSsl().isEnabled()
? "rediss"
: "redis";
return scheme + "://" + redisProperties.getHost() + ":" + redisProperties.getPort();
return scheme + "://" + address;
}
}

View file

@ -2,10 +2,13 @@ package com.iflytek.skillhub.config;
import org.junit.jupiter.api.Test;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@ -59,4 +62,52 @@ class RedissonConfigTest {
assertThat(serverConfig.getTimeout()).isEqualTo(3000);
assertThat(serverConfig.getConnectTimeout()).isEqualTo(5000);
}
@Test
void createConfig_usesSentinelServersWhenSentinelPropertiesArePresent() throws Exception {
RedisProperties properties = new RedisProperties();
RedisProperties.Sentinel sentinel = new RedisProperties.Sentinel();
sentinel.setMaster("mymaster");
sentinel.setNodes(List.of("redis-sentinel-1:26379", "redis-sentinel-2:26379"));
properties.setSentinel(sentinel);
properties.setDatabase(3);
properties.setPassword("secret");
properties.setClientName("skillhub-stream");
properties.setTimeout(Duration.ofSeconds(3));
properties.setConnectTimeout(Duration.ofSeconds(5));
Config config = RedissonConfig.createConfig(properties);
SentinelServersConfig sentinelConfig = sentinelConfig(config);
assertThat(config.isSentinelConfig()).isTrue();
assertThat(sentinelConfig.getMasterName()).isEqualTo("mymaster");
assertThat(sentinelConfig.getSentinelAddresses())
.containsExactly("redis://redis-sentinel-1:26379", "redis://redis-sentinel-2:26379");
assertThat(sentinelConfig.getDatabase()).isEqualTo(3);
assertThat(sentinelConfig.getPassword()).isEqualTo("secret");
assertThat(sentinelConfig.getClientName()).isEqualTo("skillhub-stream");
assertThat(sentinelConfig.getTimeout()).isEqualTo(3000);
assertThat(sentinelConfig.getConnectTimeout()).isEqualTo(5000);
}
@Test
void createConfig_usesSecureSchemeForSentinelAddressesWhenSslEnabled() throws Exception {
RedisProperties properties = new RedisProperties();
RedisProperties.Sentinel sentinel = new RedisProperties.Sentinel();
sentinel.setMaster("mymaster");
sentinel.setNodes(List.of("redis-sentinel-1:26379"));
properties.setSentinel(sentinel);
properties.getSsl().setEnabled(true);
Config config = RedissonConfig.createConfig(properties);
SentinelServersConfig sentinelConfig = sentinelConfig(config);
assertThat(sentinelConfig.getSentinelAddresses()).containsExactly("rediss://redis-sentinel-1:26379");
}
private SentinelServersConfig sentinelConfig(Config config) throws Exception {
Method method = Config.class.getDeclaredMethod("getSentinelServersConfig");
method.setAccessible(true);
return (SentinelServersConfig) method.invoke(config);
}
}