Skip to content

feat: 知识库/Agent/Skill 读取和管理权限分离 - #858

Closed
Yuchuan925 wants to merge 6 commits into
xerrors:mainfrom
Yuchuan925:feat/resource-permission-config
Closed

feat: 知识库/Agent/Skill 读取和管理权限分离#858
Yuchuan925 wants to merge 6 commits into
xerrors:mainfrom
Yuchuan925:feat/resource-permission-config

Conversation

@Yuchuan925

@Yuchuan925 Yuchuan925 commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

变更描述

统一 Agent、Skill 与知识库的细粒度共享权限,并重构知识库配置体验。

  • 新增公共权限解析模块,统一返回 none/read/manage
  • 知识库配置拆分为读取权限与管理权限,支持全局、部门和指定用户范围。
  • 知识库管理范围必须包含在读取范围内;创建者和超级管理员始终拥有管理权限;普通用户不能通过共享范围获得管理权限。
  • 兼容迁移旧版共享数据,保留原有完整权限语义。
  • 知识库配置弹窗拆分为“基础信息”“权限配置”“检索配置”三个 TAB。
  • 检索测试页移除右侧配置栏;配置弹窗的保存不会关闭弹窗,关闭和右上角 X 才负责退出。
  • 配置入口和弹窗文案统一使用“配置”,移除弹窗内删除知识库操作。

变更类型

  • 新功能
  • Bug 修复
  • 文档更新
  • 其他

测试

  • 已在 Docker 环境测试
  • 相关功能正常工作

实际验证:

  • Review 修复后权限相关单元回归:76 passed
  • docker exec api-dev pytest -q /app/test/unit/permissions/test_resource_permission.py /app/test/unit/repositories/test_agent_repository.py /app/test/unit/services/test_skill_service.py /app/test/integration/api/test_knowledge_router.py102 passed, 1 skipped
  • docker exec api-dev uv run ruff check ... → 通过
  • docker exec api-dev uv run ruff format --check ... → 通过
  • pnpm lint → 通过
  • pnpm build → 通过(仅有依赖包已有的 Rolldown 注释及 chunk size 警告)
  • git diff --check → 通过
  • 本地浏览器真实链路:验证三个配置 TAB、检索测试全宽布局、保存后弹窗保持打开、关闭/X 正常退出。

相关权限选择器验证记录:Issue #840 comment

本轮 Review 修复后的知识库集成测试受本地 Compose 环境阻塞:Milvus 未监听 milvus:19530,导致测试知识库无法创建;API、PostgreSQL 和其他服务正常启动。

说明

  • 提交作者和提交者均为 Yuchuan。
  • 已完成 3 次 Human Review,并根据 Review 结果完成简化和修正。
  • 已处理本轮 8 条未解决 Review 意见:凭据脱敏、旧 ACL 兼容、委托管理者更新、范围校验、Skill owner-only 依赖、自动生成问题设置和权限 helper 文档。
  • 未执行全量后端测试;已执行权限、Agent、Skill 和知识库相关回归测试。

Closes #840

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@xerrors xerrors changed the title feat: 统一资源权限并重构知识库配置 🤖 feat: 知识库/Agent/Skill 读取和管理权限分离 Aug 3, 2026
@xerrors

xerrors commented Aug 3, 2026

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88e9efc69c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +328 to +330
database["effective_permission"] = permission.value
database["can_manage"] = permission == ResourcePermission.MANAGE
filtered_databases.append(database)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Redact credentials from read-only database lists

When a v2 ACL grants an admin READ but not MANAGE, this branch appends the untouched database record to GET /api/knowledge/databases; get_databases() includes raw connector parameters in both metadata and additional_params, including dify_token and notion_token. The detail-route redactor is never called for this list endpoint, so a read-only admin can retrieve credentials that the new permission split is intended to hide; redact sensitive fields before appending read-only records.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2efacded. Read-only database list entries now pass through the shared redact_database_secrets() helper before being returned, covering both metadata and additional_params. Added a regression test for credential removal.

Comment on lines +171 to +174
params = database.get("additional_params")
if not isinstance(params, dict):
return
database["additional_params"] = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Redact the duplicate metadata credential field

For a read-only admin requesting GET /databases/{kb_id}, this function sanitizes only additional_params, but KnowledgeBaseManager.get_database_info() also returns the same normalized connector configuration under metadata. Consequently Dify/Notion tokens removed from additional_params remain present in metadata; sanitize both representations or stop returning the duplicate sensitive field.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2efacded. The shared redaction helper now sanitizes both additional_params and the duplicate metadata representation on read-only detail responses.

Comment on lines 152 to +155
def user_can_manage_agent(user: User, agent: Agent) -> bool:
return user.role in ADMIN_ROLES or agent.created_by == str(user.uid)
if is_builtin_agent(agent):
return user.role in ADMIN_ROLES
return resolve_agent_permission(user, agent) == ResourcePermission.MANAGE

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve admin control while interpreting legacy ACLs

On upgrade, existing non-builtin Agents still have the legacy {access_level, ...} shape, which resolve_agent_permission() converts to a read-only scope because its default legacy_permission is READ; therefore an admin other than created_by now fails this guard and cannot update or delete records that every admin could manage before this commit. The identical regression exists in user_can_manage_skill() for legacy Skills, so legacy ACL handling needs to preserve the previous admin-management behavior without granting that behavior to new v2 scopes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2efacded. Legacy flat Agent/Skill ACLs now preserve the previous admin management behavior, while ordinary users are capped at read for legacy scopes. New v2 scopes still use their explicit manage scope.

Comment on lines +129 to +132
if force_private:
if not user_uid:
raise ValueError("私有智能体必须绑定创建用户")
return {"access_level": "user", "department_ids": [], "user_uids": [str(user_uid)]}
return {"version": 2, "read_scope": None, "manage_scope": None}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not privatize agents edited by delegated managers

When an ordinary user is granted MANAGE on an Agent created by someone else, the new resolver lets them pass the update guard, but AgentRepository.update() still calls this branch for every non-admin updater. Any edit therefore replaces the ACL with owner-only null scopes while leaving created_by unchanged, immediately removing the delegated manager's own access and discarding all existing readers; preserve the submitted ACL for users who obtained management through manage_scope.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2efacded. Agent updates only force owner-only private scopes when the existing Agent is private; delegated managers updating a shared Agent preserve the submitted ACL. Added a regression test.

Comment on lines +91 to +98
if manage_level == "global" or (read_level == "user" and manage_level != "user"):
raise ValueError("管理范围必须包含在读取范围内")
if read_level == manage_level == "department":
if not set(manage_scope["department_ids"]).issubset(read_scope["department_ids"]):
raise ValueError("管理范围必须包含在读取范围内")
elif read_level == manage_level == "user":
if not set(manage_scope["user_uids"]).issubset(read_scope["user_uids"]):
raise ValueError("管理范围必须包含在读取范围内")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject user managers outside a department read scope

When read_scope is department-based and manage_scope selects individual users, this validation accepts every user UID without checking that those users belong to one of the readable departments. The saved configuration then advertises management to out-of-department users, but resolve_resource_permission() requires them to match both scopes and silently returns NONE; validate membership or reject this cross-scope combination so a successfully saved manager actually receives access.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2efacded. Strict validation now rejects mismatched non-global read/manage access levels, including department-read plus user-manage, instead of saving a configuration that cannot grant the manager access. The frontend validator matches this rule.

Comment on lines +883 to 886
} else {
updateData.additional_params = {
chunk_preset_id: editForm.chunk_preset_id || DEFAULT_CHUNK_PRESET_ID
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the automatic-question setting in the new form

For non-connector knowledge bases, the redesigned configuration modal no longer includes or submits auto_generate_questions; new databases are hard-coded to False, and the only remaining frontend references merely read this flag after uploads. As a result users can no longer enable or disable the existing automatic sample-question behavior through the UI, so retain this field in the new basic or retrieval tab and include it in additional_params.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2efacded. Restored the non-connector auto_generate_questions switch in the Basic Info tab and include its value in additional_params on save.

Comment on lines +235 to +238
dependency_scopes = [scope for scope in (dep_config["read_scope"], dep_config["manage_scope"]) if scope]
parent_scopes = [scope for scope in (parent_config["read_scope"], parent_config["manage_scope"]) if scope]
if not dependency_scopes or not parent_scopes:
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow owner-only skills to use visible dependencies

When a v2 parent Skill has both scopes disabled, it is intentionally owner-only because ownership still grants MANAGE, but parent_scopes is empty and this branch rejects every non-builtin dependency—even a globally readable dependency or an owner-only dependency created by the same user. Account for the implicit owner audience instead of treating an empty explicit scope as having no users.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2efacded. Owner-only v2 Skills now use the implicit owner UID as their effective audience when explicit scopes are empty, allowing dependency checks against visible global or owner-only Skills.

Comment thread docs/develop-guides/changelog.md Outdated

## v0.7.2 (current)

- 统一 Agent、Skill 与知识库共享权限:配置拆分读取/管理范围并统一解析 `none/read/manage`;知识库读取范围必填、管理范围不得越界且可为空,创建者与超管保留管理权;旧范围复制为读/管两份。知识库配置弹窗按基础信息、权限、检索分栏,保存后保持打开。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add the required design and acceptance document

This is a large cross-cutting change spanning the shared permission model, multiple backend resource types, routers, tests, and several frontend management flows, but the commit adds no dated document under docs/vibe recording its requirements, acceptance criteria, goal, and checklist. Add that document so the intended migration and read/manage semantics can be reviewed and maintained against the repository's required workflow.

AGENTS.md reference: AGENTS.md:L101-L102

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

更正:docs/vibe 按项目约定不应提交。我已将这些文件从 PR 最终树移除并保留为本地忽略文件;本条 Review 不需要提交设计文档。

Comment on lines +59 to +60
def _normalize_scope(scope: dict | None) -> dict | None:
if scope is None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add Chinese docstrings to the new permission helpers

The newly introduced _normalize_scope, _value, and _minimum_permission functions have no docstrings, despite the repository requiring every new function or class to have a concise Chinese docstring. Document their normalization, mapping/object lookup, and permission-order behavior rather than leaving these central ACL helpers undocumented.

AGENTS.md reference: AGENTS.md:L73-L73

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2efacded. Added concise Chinese docstrings to _normalize_scope, _value, and _minimum_permission as required by the project guidelines.

@Yuchuan925

Yuchuan925 commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

本轮 Review 意见已全部处理,修复提交为 2efacded,并在后续提交 1194885e 移除了不应进入 PR 的 docs/vibe 文件:

  • 只读知识库列表与详情统一脱敏 metadata / additional_params 凭据
  • 保留旧版 Agent/Skill 管理语义,同时限制普通用户
  • 修复委托管理者更新 Agent 时 ACL 被私有化
  • 拒绝非全局读取范围下的跨级管理范围
  • 支持 owner-only Skill 的依赖可见性
  • 恢复知识库自动生成问题设置
  • 补齐权限 helper 中文 docstring

验证:权限相关单元测试 76 passed,Ruff 和前端 lint/build 通过。知识库集成测试已执行,但当前本地 Compose 的 Milvus 未监听 milvus:19530,创建测试知识库失败,详见 PR 描述。

@Yuchuan925

Copy link
Copy Markdown
Collaborator Author

补充优化(提交 e7fd862a):按确认的产品规则移除了 legacy_permission 参数。旧版单字段配置现在固定迁移为同范围的 read_scope + manage_scope;新资源的 None 默认值和 V2 显式配置仍分别处理,避免为已确定的迁移策略保留多余分支。权限单元测试仍为 76 passed

@xerrors
xerrors marked this pull request as ready for review August 4, 2026 08:23
Copilot AI lite review requested due to automatic review settings August 4, 2026 08:23
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

- 基本信息 tab 修改名称、描述、图标或共享权限后不再出现「保存(有修改)」:
  弹窗内追踪 profile dirty,与 store 的 hasConfigChanges 合并后驱动按钮显示。
  保存按钮改用 size=small (24px) 与标题等高,避免撑高 header。
- 新建模式下原条件永远不满足、按钣缺失「创建」入口:v-if 增加 !editingAgentId,
  按钮文案根据模式在创建 / 保存之间切换。
- 新建时自动填充默认名称("新建智能体")与 slug(agent-时间戳),用户可直接修改;
  名称输入自动 focus + select 便于覆盖默认。
- 共享权限切到部门共享或指定人后,因为按钮撑高导致 card 增高;
  将 card-action / title / icon 统一为 20px 等高卡位,三种模式下卡片高度保持不变。

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

本 PR 将 Agent / Skill / 知识库的共享权限模型统一为 none/read/manage 语义,并将知识库共享配置拆分为“读取范围 / 管理范围”,同时重构知识库配置 UI(分 TAB、保存不关闭、检索测试布局调整)以匹配新的权限体验与安全约束。

Changes:

  • 新增统一权限解析模块(v2 share_config:read_scope/manage_scope),并在后端路由与序列化中输出 effective_permission / can_manage
  • 知识库共享改为读/管分离:管理范围不得越界、可为空;普通用户共享不再获得管理权限;只读用户获取知识库信息时会脱敏连接器凭据。
  • 前端知识库配置弹窗改为“基础信息 / 权限配置 / 检索配置”三 TAB;文件列表增加 token/chunk 内容量与创建者展示,并在只读状态下禁用写操作。

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
web/src/views/DataBaseView.vue 知识库创建/编辑共享配置切换到 v2(read/manage scope),并按 can_manage 隐藏编辑/删除入口。
web/src/views/DataBaseInfoView.vue 知识库详情页配置弹窗拆分 TAB、保存不关闭;只读用户禁用上传/操作并将文件表格设为只读。
web/src/utils/shareConfig.js 更新共享配置标签生成逻辑以支持 v2 读/管范围展示。
web/src/components/ShareConfigForm.vue 共享配置组件升级为 read/manage 两段式配置与范围越界校验(含 requireReadScope)。
web/src/components/SearchConfigPanel.vue 保存接口支持 notify 开关,供弹窗“静默保存”检索配置使用。
web/src/components/ModelSelectorComponent.vue 调整模型选择下拉样式(输入框与菜单组间距)。
web/src/components/model-management/AgentManagePanel.vue 统计逻辑兼容 v2 share_config(global 判断基于 read_scope/legacy)。
web/src/components/model-management/AgentEditModal.vue Agent 编辑弹窗默认 share_config 改为 v2(read_scope/manage_scope)。
web/src/components/FileTable.vue 新增内容量与创建人列;支持 readonly 模式禁用写操作与多选。
web/src/components/extensions/SkillInstallFlowModal.vue Skill 安装流程 share_config 升级为 v2 并兼容展示/克隆。
web/src/components/extensions/SkillDetailView.vue Skill 详情页 share_config 升级为 v2 并兼容克隆。
docs/develop-guides/changelog.md 记录权限模型统一、知识库配置 UI 调整与文件列表增强等变更。
backend/test/unit/services/test_skill_service.py Skill service 单测更新:v2 share_config、依赖范围覆盖规则、owner-only 依赖场景。
backend/test/unit/routers/test_knowledge_resource_permission.py 新增知识库路由所需权限分类、凭据脱敏、只读管理员禁止更新等单测。
backend/test/unit/repositories/test_agent_repository.py Agent repository 单测更新:默认 share_config v2、委托管理更新保留 ACL。
backend/test/unit/permissions/test_resource_permission.py 新增权限解析模块单测:v2 校验、legacy 兼容、权限上限与拒绝逻辑。
backend/test/unit/knowledge/test_file_listing_scaling.py 文件列表返回值扩展:chunk/token/created_by 与批量用户信息补全。
backend/test/integration/api/test_knowledge_router.py 知识库接口集成测试更新:默认 share_config v2、部门/用户共享断言改为 manage_scope。
backend/server/routers/skill_router.py Skill 序列化返回新增 effective_permission 字段。
backend/server/routers/knowledge_router.py 知识库路由引入基于资源 ACL 的权限校验、GET 输出权限字段并对只读脱敏。
backend/package/yuxi/repositories/user_repository.py 新增 list_by_uids 供文件列表批量补全创建者信息。
backend/package/yuxi/repositories/knowledge_file_repository.py 文件列表 SQL 选择字段扩展:chunk/token/created_by。
backend/package/yuxi/repositories/agent_repository.py Agent share_config 迁移到 v2,权限判定改用统一 resolver,并在序列化中输出 effective_permission
backend/package/yuxi/permissions/resource_permission.py 新增统一权限解析实现(normalize + resolve + require),覆盖 Agent/Skill/知识库策略差异。
backend/package/yuxi/permissions/init.py 导出 permissions 公共 API。
backend/package/yuxi/knowledge/manager.py 知识库 share_config 规范化为 v2、只读脱敏、文件列表补全创建者信息。
backend/package/yuxi/agents/skills/service.py Skill 权限判定/规范化改用统一 resolver,并更新依赖可见性覆盖逻辑。
backend/package/yuxi/agents/skills/repository.py 内置 Skill share_config 更新为 v2 结构。

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 372 to 375
share_config = agent.share_config or DEFAULT_SHARE_CONFIG.copy()
if share_config.get("access_level") != "global":
read_scope = share_config.get("read_scope") or {}
if read_scope.get("access_level") != "global":
raise ValueError("内置智能体必须全局共享")

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e7fd862a23

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +489 to +493
force_private=bool(
updater
and updater.role not in ADMIN_ROLES
and not current_config["read_scope"]
and not current_config["manage_scope"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce non-admin Agent ACL limits on the server

For an ordinary user delegated MANAGE on a shared Agent, this condition disables force_private, while normalize_agent_share_config() accepts arbitrary v2 access levels. A crafted PUT /agent/{id} can therefore replace the ACL with global read/manage scopes and grant every user permission to edit or delete the Agent, even though the frontend restricts ordinary users to user-level scopes; enforce those role limits in the backend or preserve the ACL for non-admin updaters.

AGENTS.md reference: AGENTS.md:L110-L110

Useful? React with 👍 / 👎.

Comment on lines +193 to +197
elif scope_matches(user, config["manage_scope"]) and (
config["read_scope"] is None or scope_matches(user, config["read_scope"])
):
granted = ResourcePermission.MANAGE
elif scope_matches(user, config["read_scope"]):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve admin management for non-global legacy ACLs

When a pre-upgrade Agent or non-builtin Skill has a legacy department/user ACL and the current admin is outside that scope, these branches derive NONE before the role ceiling is applied, whereas the previous user_can_manage_agent() and user_can_manage_skill() granted every admin management access. Fresh evidence in the final tree is that legacy compatibility only caps ordinary users and the added regression test covers only a global legacy ACL; add an admin legacy-management path for Agent and Skill without changing explicit v2 scopes.

Useful? React with 👍 / 👎.

Comment on lines +23 to +25
class ShareableResource(Protocol):
created_by: str | None
share_config: dict | None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Document the new shared-resource protocol

The final tree still introduces ShareableResource without a Chinese docstring. Prior feedback addressed three permission helper functions, but this newly added protocol remains undocumented; add a concise Chinese docstring describing the created_by and share_config contract.

AGENTS.md reference: AGENTS.md:L73-L73

Useful? React with 👍 / 👎.

Comment thread web/src/views/DataBaseInfoView.vue Outdated
console.error('表单验证失败:', err)
})
}
const searchConfigSaved = await searchConfigPanelRef.value?.save({ notify: false })

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid overwriting retrieval settings on unrelated saves

When an administrator opens this modal only to rename a knowledge base or change its ACL, this unconditional call still persists the retrieval panel. SearchConfigPanel.loadSavedConfig() overlays server values with browser-local search-config-{kbId} data, so an administrator with stale local storage can silently revert another administrator's newer retrieval settings without visiting the retrieval tab; only save this panel after the user changes it, and avoid treating local storage as authoritative shared configuration.

Useful? React with 👍 / 👎.

Comment on lines +183 to +184
if current_user.role not in {"admin", "superadmin"}:
raise HTTPException(status_code=403, detail="需要管理员权限")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Let demoted knowledge-base owners pass the route guard

When a knowledge-base creator is later demoted from admin to ordinary user, resolve_knowledge_base_permission() still grants that owner MANAGE—as the new owner regression test explicitly expects—but this role check rejects them before the resource ACL is evaluated. Role changes are supported by the user-management API, so the owner can no longer update or delete their knowledge base despite the ownership guarantee; retain the admin-only check for non-resource routes while allowing a matching owner through kb_id routes.

Useful? React with 👍 / 👎.

Comment on lines +180 to +184
async def get_admin_user(request: Request, current_user: User = Depends(get_required_user)) -> User:
"""兼容原有知识库管理员入口,同时按知识库 ACL 校验资源权限。"""

if current_user.role not in {"admin", "superadmin"}:
raise HTTPException(status_code=403, detail="需要管理员权限")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce knowledge ACLs in evaluation and graph routers

The new ACL-aware get_admin_user is local to knowledge_router.py; inspecting knowledge_eval_router.py and graph_router.py shows that both still import the global role-only admin dependency. Consequently an admin with only READ or even NONE on a knowledge base can directly upload, generate, run, resume, or delete its evaluation data and query its graph, including dataset-ID-only deletion routes; move the resource check into a shared dependency and require MANAGE for evaluation mutations and READ for read routes.

AGENTS.md reference: AGENTS.md:L110-L110

Useful? React with 👍 / 👎.

@xerrors xerrors closed this Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: 权限上感觉还有点不足

3 participants