diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/search/common/RepoNameRuleInterceptor.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/search/common/RepoNameRuleInterceptor.kt index 717842554f..d81518d3c5 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/search/common/RepoNameRuleInterceptor.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/search/common/RepoNameRuleInterceptor.kt @@ -35,6 +35,7 @@ import com.tencent.bkrepo.auth.api.ServicePermissionClient import com.tencent.bkrepo.auth.pojo.enums.PermissionAction import com.tencent.bkrepo.common.api.constant.ensureSuffix import com.tencent.bkrepo.common.artifact.exception.RepoNotFoundException +import com.tencent.bkrepo.common.artifact.path.PathUtils import com.tencent.bkrepo.common.query.enums.OperationType import com.tencent.bkrepo.common.query.interceptor.QueryContext import com.tencent.bkrepo.common.query.interceptor.QueryRuleInterceptor @@ -158,34 +159,54 @@ class RepoNameRuleInterceptor( SecurityUtils.getUserId(), projectId, repoName ) - val paths: List - val relationType: Rule.NestedRule.RelationType - if (hasPermissionPaths?.isNotEmpty() == true) { - paths = hasPermissionPaths - relationType = Rule.NestedRule.RelationType.OR - } else if (hasPermissionPaths?.isEmpty() == true) { - // hasPermissionPath为empty时所有路径都无权限,构造一个永远不成立的条件使查询结果为空列表 + // hasPermissionPath为empty时所有路径都无权限,构造一个永远不成立的条件使查询结果为空列表 + if (hasPermissionPaths?.isEmpty() == true) { return Rule.NestedRule( mutableListOf( - repoRule, Rule.QueryRule(NodeInfo::projectId.name, false, OperationType.NULL) + repoRule, + Rule.QueryRule(NodeInfo::projectId.name, false, OperationType.NULL) ) ) - } else if (noPermissionPaths.isNotEmpty()) { - paths = noPermissionPaths - relationType = Rule.NestedRule.RelationType.NOR - } else { - return repoRule } - // 构造rule - val pathRules = paths.flatMapTo(ArrayList(paths.size)) { path -> - listOf( - Rule.QueryRule(NodeInfo::fullPath.name, path.ensureSuffix("/"), OperationType.PREFIX) as Rule, - Rule.QueryRule(NodeInfo::fullPath.name, path, OperationType.EQ) as Rule, + // 配置了有权限的路径 + if (hasPermissionPaths?.isNotEmpty() == true) { + val rules = buildHasPermissionPathRules(hasPermissionPaths) + val pathRule = Rule.NestedRule(rules, Rule.NestedRule.RelationType.OR) + return Rule.NestedRule(mutableListOf(repoRule, pathRule)) + } + + // 配置了无权限路径 + if (noPermissionPaths.isNotEmpty()) { + val pathRules = buildNoPermissionPathRules(noPermissionPaths) + val pathRule = Rule.NestedRule(pathRules, Rule.NestedRule.RelationType.NOR) + return Rule.NestedRule(mutableListOf(repoRule, pathRule)) + } + + return repoRule + } + + private fun buildHasPermissionPathRules(paths: List): MutableList { + return paths.flatMapTo(ArrayList(paths.size * 4)) { path -> + // 拥有所有父目录查看权限,用于在前端与bk-driver中查看 + val parentFolders = PathUtils.resolveAncestorFolder(path) + val rules = ArrayList(parentFolders.size + 2) + parentFolders.forEach { rules.add(Rule.QueryRule(NodeInfo::fullPath.name, it, OperationType.EQ)) } + // 拥有目录自身的权限 + rules.add(Rule.QueryRule(NodeInfo::fullPath.name, path, OperationType.EQ)) + // 拥有子目录的权限 + rules.add(Rule.QueryRule(NodeInfo::fullPath.name, path.ensureSuffix("/"), OperationType.PREFIX)) + rules + } + } + + private fun buildNoPermissionPathRules(paths: List): MutableList { + return paths.flatMapTo(ArrayList(paths.size * 2)) { path -> + listOf( + Rule.QueryRule(NodeInfo::fullPath.name, path.ensureSuffix("/"), OperationType.PREFIX), + Rule.QueryRule(NodeInfo::fullPath.name, path, OperationType.EQ), ) } - val pathRule = Rule.NestedRule(pathRules, relationType) - return Rule.NestedRule(mutableListOf(repoRule, pathRule)) } private fun hasRepoPermission( diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/util/NodeQueryHelper.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/util/NodeQueryHelper.kt index ec05171aed..db8abe6138 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/util/NodeQueryHelper.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/util/NodeQueryHelper.kt @@ -28,6 +28,7 @@ package com.tencent.bkrepo.repository.util import com.tencent.bkrepo.auth.api.ServicePermissionClient +import com.tencent.bkrepo.common.artifact.path.PathUtils import com.tencent.bkrepo.common.artifact.path.PathUtils.escapeRegex import com.tencent.bkrepo.common.artifact.path.PathUtils.toFullPath import com.tencent.bkrepo.common.artifact.path.PathUtils.toPath @@ -97,12 +98,12 @@ object NodeQueryHelper { } else if (option.hasPermissionPath?.isNotEmpty() == true) { Criteria().andOperator( criteria, - Criteria().orOperator(buildPermissionPathCriteria(option.hasPermissionPath!!)) + Criteria().orOperator(buildHasPermissionPathCriteria(option.hasPermissionPath!!)) ) } else if (option.noPermissionPath.isNotEmpty()) { Criteria().andOperator( criteria, - Criteria().norOperator(buildPermissionPathCriteria(option.noPermissionPath)) + Criteria().norOperator(buildNoPermissionPathCriteria(option.noPermissionPath)) ) } else { criteria @@ -265,10 +266,20 @@ object NodeQueryHelper { throw UnsupportedOperationException("Unsupported operation [$operationType].") } - private fun buildPermissionPathCriteria(paths: List) = paths.flatMap { + private fun buildNoPermissionPathCriteria(paths: List) = paths.flatMap { listOf(TNode::fullPath.isEqualTo(it), TNode::fullPath.regex("^${escapeRegex(it)}")) } + private fun buildHasPermissionPathCriteria(paths: List) = paths.flatMap { path -> + val parentFolders = PathUtils.resolveAncestorFolder(path) + val criteriaList = ArrayList(parentFolders.size + 2) + // 拥有文件权限时将自动拥有父目录查看权限,在前端或者bk-driver中才能查看子目录及文件 + parentFolders.forEach { criteriaList.add(TNode::fullPath.isEqualTo(it)) } + criteriaList.add(TNode::fullPath.isEqualTo(path)) + criteriaList.add(TNode::fullPath.regex("^${escapeRegex(path)}")) + criteriaList + } + private fun update(operator: String): Update { return Update() .set(TNode::lastModifiedDate.name, LocalDateTime.now()) diff --git a/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/NodeSearchServiceTest.kt b/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/NodeSearchServiceTest.kt index f9ef78c7d6..0ffdd85f4b 100644 --- a/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/NodeSearchServiceTest.kt +++ b/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/NodeSearchServiceTest.kt @@ -314,7 +314,9 @@ class NodeSearchServiceTest @Autowired constructor( @Test fun testHasPermissionPathSearch() { whenever(servicePermissionClient.listPermissionPath(anyString(), anyString(), anyString())).thenReturn( - ResponseBuilder.success(ListPathResult(status = true, path = mapOf(OperationType.IN to listOf("/a")))) + ResponseBuilder.success( + ListPathResult(status = true, path = mapOf(OperationType.IN to listOf("/a/a1.txt"))) + ) ) whenever(servicePermissionClient.listPermissionRepo(anyString(), anyString(), isNull())).thenReturn( ResponseBuilder.success(listOf(UT_REPO_NAME)) diff --git a/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/NodeServiceTest.kt b/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/NodeServiceTest.kt index cd08142d78..81d071506d 100644 --- a/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/NodeServiceTest.kt +++ b/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/NodeServiceTest.kt @@ -300,7 +300,7 @@ class NodeServiceTest @Autowired constructor( ResponseBuilder.success( ListPathResult( status = true, - path = mapOf(OperationType.IN to listOf("/a/1", "/a/2")) + path = mapOf(OperationType.IN to listOf("/a/1/1.txt", "/a/2")) ) ) )