Skip to content

feat(authz): scope admin data by user and channel permissions - #6334

Open
kongzi10 wants to merge 2 commits into
QuantumNous:mainfrom
kongzi10:main
Open

feat(authz): scope admin data by user and channel permissions#6334
kongzi10 wants to merge 2 commits into
QuantumNous:mainfrom
kongzi10:main

Conversation

@kongzi10

@kongzi10 kongzi10 commented Jul 20, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 创建渠道的时候增加创建人,并且在管理员权限粒度增加是否能查看非本人创建的渠道(使用日志、任务日志、绘图日志等日志页面应统一遵循上述范围)和用户管理权限点

📝 变更描述 / Description

  • 管理员默认只能看到自己的数据。
  • 没有“查看全部渠道”权限时,只能查看和操作自己创建的渠道。
  • 使用日志、任务日志、绘图日志等日志页面应统一遵循上述范围。
  • 只有配置用户管理权限点的管理员能管理查看用户数据。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

渠道商:
image
超级管理员:
image

Summary by CodeRabbit

  • New Features
    • Added granular permissions for viewing all channels (including those created by other admins) and for managing user accounts.
    • Channel, task, log, and admin views now use viewer-aware visibility scoping.
    • Updated admin navigation and user-management UI to be permission-aware.
  • Bug Fixes
    • Restricted unauthorized channel operations and bulk actions with appropriate access-denied responses.
    • Prevented clients from persisting system-managed channel ownership (creator_id).
  • Documentation
    • Added/updated translations for user-management and channel-visibility permission labels across supported languages.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds creator-based channel authorization, scoped logs and task queries, granular user/channel permissions, protected admin routes, and frontend visibility gates for channels, users, navigation, and usage-log filters.

Changes

Admin visibility and permissions

Layer / File(s) Summary
Permission and ownership contracts
service/authz/*, model/channel.go, controller/channel_authz.go, router/api-router.go, web/default/src/lib/admin-permissions.ts, web/default/src/components/layout/types.ts
Adds user read/write and channel read-all permissions, persists creator_id, protects it from client updates, and applies user permissions to admin routes.
Channel scope enforcement
controller/admin_scope.go, controller/channel*.go, controller/codex_usage.go
Restricts channel queries and operations to visible channels, requires all-channel scope for bulk operations, and assigns creators when channels are added or copied.
Scoped logs and task data
model/log.go, model/task.go, model/midjourney.go, controller/log.go, controller/task.go, controller/midjourney.go, model/log_visibility_scope_test.go
Adds reusable visibility scopes for logs and tasks, applies them to retrieval/counting queries, and validates generated visibility SQL.
Frontend permission gates
web/default/src/features/usage-logs/*, web/default/src/features/users/*, web/default/src/hooks/*, web/default/src/routes/_authenticated/users/index.tsx, web/default/src/i18n/locales/*
Uses granular permissions to filter navigation, protect user actions and routes, constrain usage-log filters and requests, and add localized permission text.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AdminUI
  participant ChannelController
  participant VisibilityScope
  participant Database
  AdminUI->>ChannelController: Request channel or log data
  ChannelController->>VisibilityScope: Build request visibility
  VisibilityScope->>Database: Query creator-owned channel IDs
  Database-->>VisibilityScope: Visible channel IDs
  VisibilityScope-->>ChannelController: Apply scoped query
  ChannelController->>Database: Execute filtered query
  Database-->>ChannelController: Scoped results
  ChannelController-->>AdminUI: Response
Loading

Possibly related PRs

Suggested reviewers: calcium-ion

Poem

I’m a rabbit guarding each channel gate,
With creator IDs keeping records straight.
Logs hop in scopes, users bloom with care,
Permissions guide who may wander there.
All-channel doors open only when right—
Safe little burrows, clean and bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main authz/scoping change for admin data by user and channel permissions.
Linked Issues check ✅ Passed The PR implements creator-based channel scoping, all-channel gating, scoped logs/tasks, and user-management permissions required by #6267.
Out of Scope Changes check ✅ Passed The changes are consistent with the stated authz and scoping objectives and do not introduce明显 unrelated functionality.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
controller/channel_authz_test.go (1)

99-133: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a channelHasSensitiveChanges case for creator_id.

The clearing test is solid, but there's no test verifying creator_id alone in requestData doesn't trip the fail-closed sensitive-change check in channelHasSensitiveChanges. Since creator_id is now a security-relevant field, a regression test here would catch someone accidentally dropping it from channelReadOnlyFields later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/channel_authz_test.go` around lines 99 - 133, Add a focused test
for channelHasSensitiveChanges that supplies requestData containing only
creator_id and verifies it is treated as a sensitive change. Reuse the existing
channelReadOnlyFields behavior and test conventions in
controller/channel_authz_test.go, without changing clearChannelReadOnlyFields or
unrelated fields.
model/task.go (1)

175-199: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider supporting channel_id = 0 in TaskVisibilityScope for consistency.

LogVisibilityScope includes an IncludeOtherUsersNonChannel flag to allow administrators to see logs not tied to any channel (channel_id = 0).
If tasks can occasionally lack a channel association (e.g., tasks that failed before routing), consider adding a similar flag to TaskVisibilityScope so these tasks are not inadvertently hidden from administrators with global visibility.

🛠️ Proposed consistency refactor
 type TaskVisibilityScope struct {
 	UserID                      int
 	ChannelIDs                  []int
 	AllChannels                 bool
+	IncludeOtherUsersNonChannel bool
 }
 
 func (scope TaskVisibilityScope) Apply(query *gorm.DB) *gorm.DB {
 	conditions := make([]string, 0, 2)
 	args := make([]any, 0, 2)
 	if scope.UserID > 0 {
 		conditions = append(conditions, "user_id = ?")
 		args = append(args, scope.UserID)
 	}
 	if scope.AllChannels {
 		conditions = append(conditions, "channel_id <> 0")
 	} else if len(scope.ChannelIDs) > 0 {
 		conditions = append(conditions, "channel_id IN ?")
 		args = append(args, scope.ChannelIDs)
 	}
+	if scope.IncludeOtherUsersNonChannel {
+		conditions = append(conditions, "channel_id = 0")
+	}
 	if len(conditions) == 0 {
 		return query.Where("1 = 0")
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/task.go` around lines 175 - 199, Extend TaskVisibilityScope and its
Apply method to support explicitly including unassigned tasks with channel_id =
0, using a flag consistent with LogVisibilityScope’s IncludeOtherUsersNonChannel
behavior. Ensure the condition is added to the existing visibility predicates
without changing current user, all-channel, or specific-channel filtering
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@controller/admin_scope.go`:
- Around line 57-73: Update ensureChannelsVisible to deduplicate channelIDs
before the database query and count comparison, then use the deduplicated slice
for both. Preserve the existing authorization and forbidden-response behavior.

In `@model/channel.go`:
- Line 33: Backfill existing channel records after introducing the CreatorId
field so their creator_id values are populated rather than left at the default
0. Add this migration using the project’s established migration mechanism,
deriving each channel’s creator from the existing ownership relationship while
preserving the CreatorId model field and restricted admin scope behavior.

In `@web/default/src/i18n/locales/zh-TW.json`:
- Around line 756-762: Update the newly added translations in the locale entries
around “User Management” to consistently use the established `用戶` terminology
instead of `使用者` and `渠道` instead of `管道`, including the permission labels and
descriptions for users and channels.

---

Nitpick comments:
In `@controller/channel_authz_test.go`:
- Around line 99-133: Add a focused test for channelHasSensitiveChanges that
supplies requestData containing only creator_id and verifies it is treated as a
sensitive change. Reuse the existing channelReadOnlyFields behavior and test
conventions in controller/channel_authz_test.go, without changing
clearChannelReadOnlyFields or unrelated fields.

In `@model/task.go`:
- Around line 175-199: Extend TaskVisibilityScope and its Apply method to
support explicitly including unassigned tasks with channel_id = 0, using a flag
consistent with LogVisibilityScope’s IncludeOtherUsersNonChannel behavior.
Ensure the condition is added to the existing visibility predicates without
changing current user, all-channel, or specific-channel filtering behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3c60d6f4-355c-484e-bea9-ab3fb9bff95c

📥 Commits

Reviewing files that changed from the base of the PR and between 5a6c53d and bb8a39c.

📒 Files selected for processing (43)
  • controller/admin_scope.go
  • controller/channel-billing.go
  • controller/channel-test.go
  • controller/channel.go
  • controller/channel_authz.go
  • controller/channel_authz_test.go
  • controller/channel_test_internal_test.go
  • controller/channel_upstream_update.go
  • controller/channel_upstream_update_test.go
  • controller/codex_usage.go
  • controller/log.go
  • controller/midjourney.go
  • controller/task.go
  • model/channel.go
  • model/log.go
  • model/log_visibility_scope_test.go
  • model/midjourney.go
  • model/task.go
  • router/api-router.go
  • service/authz/authz_test.go
  • service/authz/resources_channel.go
  • service/authz/resources_user.go
  • web/default/src/components/layout/types.ts
  • web/default/src/features/channels/types.ts
  • web/default/src/features/usage-logs/components/common-logs-filter-bar.tsx
  • web/default/src/features/usage-logs/components/task-logs-filter-bar.tsx
  • web/default/src/features/usage-logs/components/usage-logs-provider.tsx
  • web/default/src/features/usage-logs/components/usage-logs-table.tsx
  • web/default/src/features/usage-logs/lib/utils.ts
  • web/default/src/features/usage-logs/types.ts
  • web/default/src/features/users/components/data-table-row-actions.tsx
  • web/default/src/features/users/components/users-primary-buttons.tsx
  • web/default/src/hooks/use-sidebar-data.ts
  • web/default/src/hooks/use-sidebar-view.ts
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh-TW.json
  • web/default/src/i18n/locales/zh.json
  • web/default/src/lib/admin-permissions.ts
  • web/default/src/routes/_authenticated/users/index.tsx

Comment thread controller/admin_scope.go
Comment thread model/channel.go
Comment thread web/default/src/i18n/locales/zh-TW.json

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
controller/channel.go (1)

1319-1319: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard constant.ChannelBaseURLs before indexing in controller/channel.go:1319. ChannelBaseURLs is a slice, and req.Type comes from request JSON without bounds validation here; negative values or ChannelTypeDummy/higher will panic on access.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/channel.go` at line 1319, Validate req.Type is within the bounds
of constant.ChannelBaseURLs before the indexing assignment in the surrounding
channel request handler. Reject negative values and values at or above the slice
length, including ChannelTypeDummy, using the handler’s existing invalid-request
response path; only assign baseURL after validation succeeds.
controller/channel_upstream_update_test.go (1)

30-30: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Add the missing constant import. controller/channel_upstream_update_test.go uses constant.ChannelTypeAdvancedCustom, constant.ChannelTypeOpenAI, and constant.ChannelTypeAnthropic, but github.com/QuantumNous/new-api/constant isn’t imported.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/channel_upstream_update_test.go` at line 30, Add the missing
github.com/QuantumNous/new-api/constant import to
controller/channel_upstream_update_test.go so the channel upstream update tests
can resolve constant.ChannelTypeAdvancedCustom, constant.ChannelTypeOpenAI, and
constant.ChannelTypeAnthropic.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@controller/channel_upstream_update_test.go`:
- Line 30: Add the missing github.com/QuantumNous/new-api/constant import to
controller/channel_upstream_update_test.go so the channel upstream update tests
can resolve constant.ChannelTypeAdvancedCustom, constant.ChannelTypeOpenAI, and
constant.ChannelTypeAnthropic.

In `@controller/channel.go`:
- Line 1319: Validate req.Type is within the bounds of constant.ChannelBaseURLs
before the indexing assignment in the surrounding channel request handler.
Reject negative values and values at or above the slice length, including
ChannelTypeDummy, using the handler’s existing invalid-request response path;
only assign baseURL after validation succeeds.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 43fec392-861e-4cbb-b0c2-5a744d5dbd8e

📥 Commits

Reviewing files that changed from the base of the PR and between bb8a39c and a18fff7.

📒 Files selected for processing (11)
  • controller/channel.go
  • controller/channel_upstream_update.go
  • controller/channel_upstream_update_test.go
  • model/channel.go
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/ja.json
  • web/default/src/i18n/locales/ru.json
  • web/default/src/i18n/locales/vi.json
  • web/default/src/i18n/locales/zh-TW.json
  • web/default/src/i18n/locales/zh.json
🚧 Files skipped from review as they are similar to previous changes (7)
  • web/default/src/i18n/locales/fr.json
  • web/default/src/i18n/locales/en.json
  • web/default/src/i18n/locales/zh-TW.json
  • controller/channel_upstream_update.go
  • web/default/src/i18n/locales/ru.json
  • model/channel.go
  • web/default/src/i18n/locales/vi.json

@Calcium-Ion
Calcium-Ion force-pushed the main branch 2 times, most recently from 51fdfc5 to 2b6f1df Compare August 30, 2026 15:03
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.

建议创建渠道的时候增加创建人,并且在管理员权限粒度增加是否能查看非本人创建的渠道和用户管理权限点

1 participant