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 6a1a0e6753 fix(admin): apply namespace name filter for administrators. 
(#7728)
6a1a0e6753 is described below

commit 6a1a0e67532ffba6a121f941d9ffa9c486bd61e9
Author: 甜梦守护者 <[email protected]>
AuthorDate: Fri Oct 23 11:39:30 2026 +0800

    fix(admin): apply namespace name filter for administrators. (#7728)
---
 .../admin/service/impl/NamespaceServiceImpl.java   |   4 +-
 .../shenyu/admin/mapper/NamespaceMapperTest.java   | 107 +++++++++++++++++++++
 .../admin/service/NamespaceServiceImplTest.java    |  96 +++++++++++++++++-
 3 files changed, 205 insertions(+), 2 deletions(-)

diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/NamespaceServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/NamespaceServiceImpl.java
index 2fdc41c93c..1a28a07f23 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/NamespaceServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/NamespaceServiceImpl.java
@@ -183,7 +183,9 @@ public class NamespaceServiceImpl implements 
NamespaceService {
     public List<NamespaceVO> list(final String name) {
         
         if (SessionUtil.isAdmin()) {
-            List<NamespaceDO> allList = namespaceMapper.selectAll();
+            NamespaceQuery query = new NamespaceQuery();
+            query.setName(name);
+            List<NamespaceDO> allList = namespaceMapper.selectByQuery(query);
             return 
allList.stream().map(NamespaceTransfer.INSTANCE::mapToVo).collect(Collectors.toList());
         }
         
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/NamespaceMapperTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/NamespaceMapperTest.java
new file mode 100644
index 0000000000..71691d62bb
--- /dev/null
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/mapper/NamespaceMapperTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.mapper;
+
+import org.apache.ibatis.builder.xml.XMLMapperBuilder;
+import org.apache.ibatis.mapping.Environment;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
+import org.apache.shenyu.admin.model.entity.NamespaceDO;
+import org.apache.shenyu.admin.model.query.NamespaceQuery;
+import org.junit.jupiter.api.Test;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests for namespace name filtering and namespace scope.
+ */
+public final class NamespaceMapperTest {
+
+    @Test
+    public void testNameFilteringAndNamespaceScope() throws Exception {
+        DriverManagerDataSource dataSource = new DriverManagerDataSource(
+                "jdbc:h2:mem:namespace-filter-" + UUID.randomUUID()
+                        + ";DB_CLOSE_DELAY=-1;MODE=MySQL", "sa", "");
+        JdbcTemplate jdbc = new JdbcTemplate(dataSource);
+
+        try {
+            new ResourceDatabasePopulator(
+                    new 
ClassPathResource("sql-script/h2/schema.sql")).execute(dataSource);
+
+            String insertSql = "INSERT INTO namespace (id, namespace_id, name) 
VALUES (?, ?, ?)";
+            jdbc.update(insertSql, "test-foo", "ns-foo", "pr7703-foo");
+            jdbc.update(insertSql, "test-prod-foo", "ns-prod-foo", 
"prod-pr7703-foo");
+            jdbc.update(insertSql, "test-bar", "ns-bar", "pr7703-bar");
+
+            Configuration configuration = new Configuration(
+                    new Environment("test", new JdbcTransactionFactory(), 
dataSource));
+            configuration.setMapUnderscoreToCamelCase(true);
+            String mapperResource = "mappers/namespace-sqlmap.xml";
+            try (InputStream input = new 
ClassPathResource(mapperResource).getInputStream()) {
+                new XMLMapperBuilder(input, configuration, mapperResource,
+                        configuration.getSqlFragments()).parse();
+            }
+
+            try (SqlSession session = new SqlSessionFactoryBuilder()
+                    .build(configuration).openSession()) {
+                NamespaceMapper mapper = 
session.getMapper(NamespaceMapper.class);
+                NamespaceQuery query = new NamespaceQuery();
+                query.setName("pr7703-foo");
+
+                assertEquals(Set.of("ns-foo", "ns-prod-foo"),
+                        namespaceIds(mapper.selectByQuery(query)));
+
+                List<String> allowedNamespaces = List.of("ns-foo", "ns-bar");
+                assertEquals(Set.of("ns-foo"), namespaceIds(
+                        mapper.selectByNamespaceIdsAndName(allowedNamespaces, 
"pr7703-foo")));
+
+                query.setName("pr7703-missing");
+                assertTrue(mapper.selectByQuery(query).isEmpty());
+
+                Set<String> allNamespaces = namespaceIds(mapper.selectAll());
+                for (String name : new String[]{null, ""}) {
+                    query.setName(name);
+                    assertEquals(allNamespaces, 
namespaceIds(mapper.selectByQuery(query)));
+                    assertEquals(Set.of("ns-foo", "ns-bar"), namespaceIds(
+                            
mapper.selectByNamespaceIdsAndName(allowedNamespaces, name)));
+                }
+            }
+        } finally {
+            jdbc.execute("SHUTDOWN");
+        }
+    }
+
+    private Set<String> namespaceIds(final List<NamespaceDO> namespaces) {
+        return namespaces.stream()
+                .map(NamespaceDO::getNamespaceId)
+                .collect(Collectors.toSet());
+    }
+}
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/NamespaceServiceImplTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/NamespaceServiceImplTest.java
index b4906def9e..075e12b303 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/NamespaceServiceImplTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/NamespaceServiceImplTest.java
@@ -28,13 +28,19 @@ import org.apache.shenyu.admin.mapper.RuleMapper;
 import org.apache.shenyu.admin.mapper.SelectorMapper;
 import org.apache.shenyu.admin.model.entity.DiscoveryDO;
 import org.apache.shenyu.admin.model.entity.NamespaceDO;
+import org.apache.shenyu.admin.model.query.NamespaceQuery;
+import org.apache.shenyu.admin.model.vo.NamespaceVO;
 import org.apache.shenyu.admin.service.impl.NamespaceServiceImpl;
 import org.apache.shenyu.admin.service.publish.NamespaceEventPublisher;
+import org.apache.shenyu.admin.utils.SessionUtil;
 import org.apache.shenyu.admin.utils.ShenyuResultMessage;
 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.NullAndEmptySource;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import java.util.Collections;
@@ -42,13 +48,16 @@ import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
 /**
- * Tests for namespace deletion with discovery records.
+ * Tests for namespace listing and deletion.
  */
 @ExtendWith(MockitoExtension.class)
 public final class NamespaceServiceImplTest {
@@ -125,4 +134,89 @@ public final class NamespaceServiceImplTest {
         verify(discoveryMapper).selectAllByNamespaceIds(namespaceIds);
         verify(namespaceMapper).deleteByIds(ids);
     }
+
+    @Test
+    public void testAdminListFiltersByName() {
+        NamespaceQuery query = new NamespaceQuery();
+        query.setName("foo");
+
+        NamespaceDO namespace = NamespaceDO.builder()
+                .namespaceId("namespace-foo")
+                .name("prod-foo")
+                .build();
+
+        try (MockedStatic<SessionUtil> sessionUtil = 
mockStatic(SessionUtil.class)) {
+            sessionUtil.when(SessionUtil::isAdmin).thenReturn(true);
+            
when(namespaceMapper.selectByQuery(query)).thenReturn(List.of(namespace));
+
+            List<NamespaceVO> result = namespaceService.list("foo");
+
+            assertEquals(1, result.size());
+            assertEquals("namespace-foo", result.get(0).getNamespaceId());
+            assertEquals("prod-foo", result.get(0).getName());
+
+            verify(namespaceMapper).selectByQuery(query);
+            verify(namespaceMapper, never()).selectAll();
+        }
+    }
+
+    @ParameterizedTest
+    @NullAndEmptySource
+    public void testAdminListWithoutNameReturnsAll(final String name) {
+        NamespaceQuery query = new NamespaceQuery();
+        query.setName(name);
+
+        List<NamespaceDO> namespaces = List.of(
+                
NamespaceDO.builder().namespaceId("namespace-foo").name("foo").build(),
+                
NamespaceDO.builder().namespaceId("namespace-bar").name("bar").build());
+
+        try (MockedStatic<SessionUtil> sessionUtil = 
mockStatic(SessionUtil.class)) {
+            sessionUtil.when(SessionUtil::isAdmin).thenReturn(true);
+            when(namespaceMapper.selectByQuery(query)).thenReturn(namespaces);
+
+            List<NamespaceVO> result = namespaceService.list(name);
+
+            assertEquals(List.of("foo", "bar"), 
result.stream().map(NamespaceVO::getName).toList());
+            verify(namespaceMapper).selectByQuery(query);
+        }
+    }
+
+    @Test
+    public void testNonAdminListUsesAuthorizedNamespaces() {
+        List<String> namespaceIds = List.of("namespace-foo");
+        NamespaceDO namespace = NamespaceDO.builder()
+                .namespaceId("namespace-foo")
+                .name("prod-foo")
+                .build();
+
+        try (MockedStatic<SessionUtil> sessionUtil = 
mockStatic(SessionUtil.class)) {
+            sessionUtil.when(SessionUtil::isAdmin).thenReturn(false);
+            sessionUtil.when(SessionUtil::visitorId).thenReturn("user-1");
+            
when(namespaceUserService.listNamespaceIdByUserId("user-1")).thenReturn(namespaceIds);
+            when(namespaceMapper.selectByNamespaceIdsAndName(namespaceIds, 
"foo"))
+                    .thenReturn(List.of(namespace));
+
+            List<NamespaceVO> result = namespaceService.list("foo");
+
+            assertEquals(1, result.size());
+            assertEquals("namespace-foo", result.get(0).getNamespaceId());
+            verify(namespaceMapper).selectByNamespaceIdsAndName(namespaceIds, 
"foo");
+            verify(namespaceMapper, never()).selectAll();
+        }
+    }
+
+    @Test
+    public void testNonAdminListWithoutPermissionsReturnsEmpty() {
+        try (MockedStatic<SessionUtil> sessionUtil = 
mockStatic(SessionUtil.class)) {
+            sessionUtil.when(SessionUtil::isAdmin).thenReturn(false);
+            sessionUtil.when(SessionUtil::visitorId).thenReturn("user-1");
+            when(namespaceUserService.listNamespaceIdByUserId("user-1"))
+                    .thenReturn(Collections.emptyList());
+
+            List<NamespaceVO> result = namespaceService.list("foo");
+
+            assertTrue(result.isEmpty());
+            verifyNoInteractions(namespaceMapper);
+        }
+    }
 }

Reply via email to