This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new e6cc09e010 fix(admin): validate proxy discovery bindings before writes
(#7271)
e6cc09e010 is described below
commit e6cc09e0102533f4709f49226cbace347d700584
Author: Liming Deng <[email protected]>
AuthorDate: Wed Sep 30 11:27:35 2026 +0800
fix(admin): validate proxy discovery bindings before writes (#7271)
* fix(admin): validate proxy discovery bindings before writes
* fix(admin): validate discovery before binding processor lookup
---
.../service/impl/ProxySelectorServiceImpl.java | 19 +++++----
.../admin/service/ProxySelectorServiceTest.java | 47 ++++++++++++++++++++++
2 files changed, 59 insertions(+), 7 deletions(-)
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
index ed44ff4807..3c128165de 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
@@ -49,6 +49,7 @@ import org.apache.shenyu.admin.service.ProxySelectorService;
import org.apache.shenyu.admin.service.configs.ConfigsImportContext;
import org.apache.shenyu.admin.transfer.DiscoveryTransfer;
import org.apache.shenyu.admin.utils.ShenyuResultMessage;
+import org.apache.shenyu.admin.utils.Assert;
import org.apache.shenyu.common.dto.ProxySelectorData;
import org.apache.shenyu.common.utils.UUIDUtils;
import org.jetbrains.annotations.NotNull;
@@ -301,8 +302,9 @@ public class ProxySelectorServiceImpl implements
ProxySelectorService {
public String bindingDiscoveryHandler(final ProxySelectorAddDTO
proxySelectorAddDTO) {
Timestamp currentTime = new Timestamp(System.currentTimeMillis());
String selectorId = proxySelectorAddDTO.getSelectorId();
- DiscoveryProcessor discoveryProcessor =
discoveryProcessorHolder.chooseProcessor(proxySelectorAddDTO.getDiscovery().getDiscoveryType());
- ProxySelectorAddDTO.Discovery discovery =
proxySelectorAddDTO.getDiscovery();
+ final ProxySelectorAddDTO.Discovery discovery =
proxySelectorAddDTO.getDiscovery();
+ Assert.notNull(discovery, "Discovery configuration is required for
selector: " + selectorId);
+ DiscoveryProcessor discoveryProcessor =
discoveryProcessorHolder.chooseProcessor(discovery.getDiscoveryType());
String discoveryId = discovery.getId();
if (!StringUtils.hasLength(discoveryId)) {
discoveryId = UUIDUtils.getInstance().generateShortUuid();
@@ -349,13 +351,18 @@ public class ProxySelectorServiceImpl implements
ProxySelectorService {
*/
@Transactional(rollbackFor = Exception.class)
public String update(final ProxySelectorAddDTO proxySelectorAddDTO) {
- // update proxy selector
+ ProxySelectorAddDTO.Discovery discovery =
proxySelectorAddDTO.getDiscovery();
+ Assert.notNull(discovery, "Discovery configuration is required");
ProxySelectorDO proxySelectorDO =
ProxySelectorDO.buildProxySelectorDO(proxySelectorAddDTO);
- proxySelectorMapper.update(proxySelectorDO);
- // DiscoveryRelDO
DiscoveryRelDO discoveryRelDO =
discoveryRelMapper.selectByProxySelectorId(proxySelectorDO.getId());
+ Assert.notNull(discoveryRelDO, "Discovery binding does not exist for
proxy selector: " + proxySelectorDO.getId());
String discoveryHandlerId = discoveryRelDO.getDiscoveryHandlerId();
DiscoveryHandlerDO discoveryHandlerDO =
discoveryHandlerMapper.selectById(discoveryHandlerId);
+ Assert.notNull(discoveryHandlerDO, "Discovery handler does not exist:
" + discoveryHandlerId);
+ DiscoveryDO discoveryDO =
discoveryMapper.selectById(discoveryHandlerDO.getDiscoveryId());
+ Assert.notNull(discoveryDO, "Discovery does not exist: " +
discoveryHandlerDO.getDiscoveryId());
+ // Validate all related records before performing any update.
+ proxySelectorMapper.update(proxySelectorDO);
// update discovery handler
Timestamp currentTime = new Timestamp(System.currentTimeMillis());
discoveryHandlerDO.setHandler(proxySelectorAddDTO.getHandler());
@@ -364,8 +371,6 @@ public class ProxySelectorServiceImpl implements
ProxySelectorService {
discoveryHandlerDO.setDateUpdated(currentTime);
discoveryHandlerMapper.updateSelective(discoveryHandlerDO);
// update discovery
- DiscoveryDO discoveryDO =
discoveryMapper.selectById(discoveryHandlerDO.getDiscoveryId());
- ProxySelectorAddDTO.Discovery discovery =
proxySelectorAddDTO.getDiscovery();
discoveryDO.setServerList(discovery.getServerList());
discoveryDO.setDateUpdated(currentTime);
discoveryDO.setProps(discovery.getProps());
diff --git
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
index 0751ee66c9..cdad6d53e3 100644
---
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
+++
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
@@ -19,6 +19,7 @@ package org.apache.shenyu.admin.service;
import org.apache.shenyu.admin.discovery.DiscoveryProcessor;
import org.apache.shenyu.admin.discovery.DiscoveryProcessorHolder;
+import org.apache.shenyu.admin.exception.ValidFailException;
import org.apache.shenyu.admin.mapper.DiscoveryHandlerMapper;
import org.apache.shenyu.admin.mapper.DiscoveryMapper;
import org.apache.shenyu.admin.mapper.DiscoveryRelMapper;
@@ -40,6 +41,8 @@ import org.apache.shenyu.common.dto.ProxySelectorData;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -55,11 +58,13 @@ import static
org.apache.shenyu.common.constant.Constants.SYS_DEFAULT_NAMESPACE_
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@@ -157,6 +162,48 @@ class ProxySelectorServiceTest {
verify(discoveryUpstreamMapper,
never()).deleteByDiscoveryHandlerId(any());
}
+ @ParameterizedTest
+ @ValueSource(strings = {"configuration", "relation", "handler",
"discovery"})
+ void validatesAllBindingsBeforeUpdatingAnyRecord(final String missing) {
+ ProxySelectorAddDTO dto = new ProxySelectorAddDTO();
+ dto.setId("proxy");
+ dto.setName("proxy");
+ dto.setPluginName("tcp");
+ dto.setForwardPort(8080);
+ dto.setHandler("new-handler");
+ if (!"configuration".equals(missing)) {
+ dto.setDiscovery(new ProxySelectorAddDTO.Discovery());
+ }
+ DiscoveryRelDO relation = new DiscoveryRelDO();
+ relation.setDiscoveryHandlerId("handler");
+ DiscoveryHandlerDO handler = new DiscoveryHandlerDO();
+ handler.setId("handler");
+ handler.setDiscoveryId("discovery");
+ handler.setHandler("original");
+
given(discoveryRelMapper.selectByProxySelectorId("proxy")).willReturn("relation".equals(missing)
? null : relation);
+
given(discoveryHandlerMapper.selectById("handler")).willReturn("handler".equals(missing)
? null : handler);
+
given(discoveryMapper.selectById("discovery")).willReturn("discovery".equals(missing)
? null : new DiscoveryDO());
+
+ assertThrows(ValidFailException.class, () ->
proxySelectorService.update(dto));
+
+ verify(proxySelectorMapper, never()).update(any());
+ verify(discoveryHandlerMapper, never()).updateSelective(any());
+ verify(discoveryMapper, never()).updateSelective(any());
+ verifyNoInteractions(discoveryUpstreamMapper,
discoveryProcessorHolder);
+ assertEquals("original", handler.getHandler());
+ }
+
+ @Test
+ void bindingRejectsMissingConfigurationBeforeLookingUpProcessorOrWriting()
{
+ ProxySelectorAddDTO dto = new ProxySelectorAddDTO();
+ dto.setSelectorId("selector-without-discovery");
+
+ ValidFailException failure = assertThrows(ValidFailException.class, ()
-> proxySelectorService.bindingDiscoveryHandler(dto));
+
+ assertEquals("Discovery configuration is required for selector:
selector-without-discovery", failure.getMessage());
+ verifyNoInteractions(discoveryProcessorHolder, discoveryMapper,
discoveryHandlerMapper, discoveryRelMapper, discoveryUpstreamMapper);
+ }
+
@Test
void testFetchDataWithProxySelector() {
DiscoveryHandlerDO discoveryHandlerDO = new DiscoveryHandlerDO();