WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s

This commit is contained in:
yawan
2026-09-22 16:19:06 +08:00
commit f7fc992f57
3929 changed files with 1006607 additions and 0 deletions
+137
View File
@@ -0,0 +1,137 @@
package accesscontrol
import (
"strings"
"time"
"github.com/Tencent/WeKnora/internal/types"
)
type Role struct {
ID string `json:"id" gorm:"primaryKey"`
TenantID uint64 `json:"tenant_id"`
Name string `json:"name"`
Description string `json:"description"`
Permissions types.StringArray `json:"permissions" gorm:"type:jsonb"`
Version int `json:"version"`
PermissionVersion int `json:"permission_version" gorm:"not null;default:0"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Role) TableName() string { return "workbench_access_roles" }
type Assignment struct {
TenantID uint64 `gorm:"primaryKey"`
UserID string `gorm:"primaryKey"`
RoleID string
}
func (Assignment) TableName() string { return "workbench_access_assignments" }
type Publication struct {
TenantID uint64 `json:"tenant_id" gorm:"primaryKey"`
Kind string `json:"kind" gorm:"primaryKey"`
ResourceID string `json:"resource_id" gorm:"primaryKey"`
Global bool `json:"global"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Publication) TableName() string { return "workbench_access_publications" }
type Grant struct {
TenantID uint64 `json:"tenant_id" gorm:"primaryKey"`
Kind string `json:"kind" gorm:"primaryKey"`
ResourceID string `json:"resource_id" gorm:"primaryKey"`
UserID string `json:"user_id" gorm:"primaryKey"`
UpdatedAt time.Time `json:"updated_at"`
}
func (Grant) TableName() string { return "workbench_access_grants" }
type Permission struct {
ID string `json:"id"`
Name string `json:"name"`
}
type Module struct {
ID string `json:"id"`
Name string `json:"name"`
Permissions []Permission `json:"permissions"`
AdminOnly bool `json:"admin_only,omitempty"`
}
var Catalog = []Module{
{"chat", "对话", []Permission{{"chat.read", "查看对话"}, {"chat.write", "发起对话与生成"}}, false},
{"content", "内容任务", []Permission{{"content.read", "查看内容任务与训练营导图"}, {"content.write", "创建与编辑内容任务"}, {"content.generate", "拆解、生成与修改内容"}, {"content.maps", "创建、生成与修改训练营导图"}, {"content.review", "采用、跳过与跨稿质检"}, {"content.delete", "删除内容任务与训练营导图"}, {"content.deliver", "复制与下载成稿"}}, false},
{"flows", "画布编排", []Permission{{"flows.read", "查看画布"}, {"flows.write", "创建与修改画布"}, {"flows.delete", "删除画布"}}, false},
{"digital-humans", "数字人", []Permission{{"digital-humans.read", "查看数字人与蒸馏结果"}, {"digital-humans.write", "创建、编辑与绑定 Agent"}, {"digital-humans.distill", "提交资料、蒸馏与试写"}, {"digital-humans.review", "审核蒸馏版本"}, {"digital-humans.wechat", "连接与管理微信账号"}, {"digital-humans.delete", "删除数字人"}}, false},
{"knowledge", "知识库", []Permission{{"knowledge.read", "查看、检索、Wiki 与知识图谱"}, {"knowledge.write", "上传、分类、编辑与删除知识"}, {"knowledge.consumption", "开放与禁用自己的消费记录"}}, false},
{"agents", "Agent 与技能", []Permission{{"agents.read", "查看 Agent、技能与记忆"}, {"agents.write", "手动、AI 创建与配置 Agent"}, {"agents.skills", "导入、挂载与删除 Markdown 技能"}, {"agents.memory", "编辑、审核与整理记忆"}, {"agents.delete", "删除 Agent"}}, false},
{"sharing", "共享空间", []Permission{{"sharing.read", "查看共享空间"}, {"sharing.write", "管理共享(仍受空间管理员限制)"}}, false},
{"settings", "设置", []Permission{{"settings.read", "查看空间设置"}, {"settings.write", "修改空间设置"}}, true},
{"access", "访问控制", []Permission{{"access.read", "查看用户、角色与资源授权"}, {"access.write", "管理用户、角色与资源授权"}}, true},
{"balance", "余额", []Permission{{"balance.read", "查看全部用户余额与发放记录"}, {"balance.write", "发放余额与设置额度"}}, true},
{"usage", "用量分析", []Permission{{"usage.read", "查看模型用量与费用明细"}}, true},
{"audit", "操作日志", []Permission{{"audit.read", "查看用户操作记录"}}, true},
{"system", "系统错误日志", []Permission{{"system.read", "查看运行错误与 AI 错误"}}, true},
}
const currentPermissionVersion = 2
// Legacy roles used one write permission for all actions in a module.
// Expand only unsaved legacy rows so deselecting a new permission is effective.
func effectiveRolePermissions(role Role) types.StringArray {
permissions := append(types.StringArray{}, role.Permissions...)
if role.PermissionVersion >= currentPermissionVersion {
return permissions
}
selected := map[string]bool{}
for _, permission := range permissions {
selected[permission] = true
}
for _, module := range Catalog {
if !selected[module.ID+".read"] || !selected[module.ID+".write"] || module.AdminOnly {
continue
}
for _, permission := range module.Permissions {
if selected[permission.ID] || permission.ID == "content.review" || permission.ID == "content.deliver" {
continue
}
permissions = append(permissions, permission.ID)
selected[permission.ID] = true
}
}
return permissions
}
func adminOnlyPermission(permission string) bool {
for _, module := range Catalog {
if strings.HasPrefix(permission, module.ID+".") {
return module.AdminOnly
}
}
return false
}
func validPermissions(values []string) bool {
known := map[string]bool{}
for _, m := range Catalog {
for _, p := range m.Permissions {
known[p.ID] = true
}
}
selected := map[string]bool{}
for _, v := range values {
if !known[v] {
return false
}
selected[v] = true
}
for _, value := range values {
module, _, _ := strings.Cut(value, ".")
if !strings.HasSuffix(value, ".read") && !selected[module+".read"] {
return false
}
}
return true
}