Skip to content

Commit

Permalink
feat: 允许在拥有子文件权限时search与list接口返回父目录node TencentBlueKing#2164
Browse files Browse the repository at this point in the history
  • Loading branch information
cnlkl committed May 30, 2024
1 parent 97cec74 commit fe26c4e
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -158,34 +159,54 @@ class RepoNameRuleInterceptor(
SecurityUtils.getUserId(), projectId, repoName
)

val paths: List<String>
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<String>): MutableList<Rule> {
return paths.flatMapTo(ArrayList(paths.size * 4)) { path ->
// 拥有所有父目录查看权限,用于在前端与bk-driver中查看
val parentFolders = PathUtils.resolveAncestorFolder(path)
val rules = ArrayList<Rule>(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<String>): MutableList<Rule> {
return paths.flatMapTo(ArrayList(paths.size * 2)) { path ->
listOf<Rule>(
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -265,10 +266,20 @@ object NodeQueryHelper {
throw UnsupportedOperationException("Unsupported operation [$operationType].")
}

private fun buildPermissionPathCriteria(paths: List<String>) = paths.flatMap {
private fun buildNoPermissionPathCriteria(paths: List<String>) = paths.flatMap {
listOf(TNode::fullPath.isEqualTo(it), TNode::fullPath.regex("^${escapeRegex(it)}"))
}

private fun buildHasPermissionPathCriteria(paths: List<String>) = paths.flatMap { path ->
val parentFolders = PathUtils.resolveAncestorFolder(path)
val criteriaList = ArrayList<Criteria>(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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
)
)
)
Expand Down

0 comments on commit fe26c4e

Please sign in to comment.