mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-23 08:56:42 +08:00
fix(agent): restrict permission field edits to canvas owner only (#17185)
This commit is contained in:
@@ -581,12 +581,23 @@ func (s *AgentService) GetAgent(ctx context.Context, userID, canvasID string) (*
|
||||
|
||||
// UpdateAgent applies a draft patch to user_canvas. Settings updates may omit
|
||||
// dsl; in that case the existing draft DSL must be preserved.
|
||||
//
|
||||
// Permission is an owner-only setting: team members who have access to the
|
||||
// canvas can still update title/avatar/description, but any permission value
|
||||
// they send is ignored so they cannot make a team agent private (or vice
|
||||
// versa). The owner can change permission together with title/avatar in one
|
||||
// request.
|
||||
func (s *AgentService) UpdateAgent(ctx context.Context, userID, canvasID string, patch map[string]interface{}) error {
|
||||
canvasInstance, err := s.loadCanvasForUser(ctx, userID, canvasID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only the canvas owner may change the permission field.
|
||||
if _, ok := patch["permission"]; ok && canvasInstance.UserID != userID {
|
||||
delete(patch, "permission")
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{}
|
||||
for _, key := range []string{"title", "avatar", "description", "permission", "canvas_type", "canvas_category"} {
|
||||
if value, ok := patch[key]; ok && value != nil {
|
||||
|
||||
@@ -1469,6 +1469,89 @@ func TestUpdateAgentSettingsPreservesDSL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateAgentPermissionOwnerOnly(t *testing.T) {
|
||||
setupAgentSessionServiceTest(t)
|
||||
|
||||
status := "1"
|
||||
if err := dao.DB.Create(&entity.UserTenant{
|
||||
ID: "ut-owner",
|
||||
UserID: "user-1",
|
||||
TenantID: "user-1",
|
||||
Role: "owner",
|
||||
InvitedBy: "user-1",
|
||||
Status: &status,
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("failed to seed owner tenant: %v", err)
|
||||
}
|
||||
if err := dao.DB.Create(&entity.UserTenant{
|
||||
ID: "ut-member",
|
||||
UserID: "user-2",
|
||||
TenantID: "user-1",
|
||||
Role: "normal",
|
||||
InvitedBy: "user-1",
|
||||
Status: &status,
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("failed to seed member tenant: %v", err)
|
||||
}
|
||||
if err := dao.DB.Create(&entity.UserCanvas{
|
||||
ID: "canvas-team",
|
||||
UserID: "user-1",
|
||||
Title: sptr("Team Agent"),
|
||||
Avatar: sptr("owner-avatar"),
|
||||
Permission: "team",
|
||||
CanvasCategory: "agent_canvas",
|
||||
DSL: entity.JSONMap{},
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("failed to seed canvas: %v", err)
|
||||
}
|
||||
|
||||
// Team member tries to make the agent private while updating title/avatar.
|
||||
err := NewAgentService().UpdateAgent(context.Background(), "user-2", "canvas-team", map[string]interface{}{
|
||||
"title": "Renamed by member",
|
||||
"avatar": "member-avatar",
|
||||
"permission": "me",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("team member update should succeed for non-permission fields: %v", err)
|
||||
}
|
||||
persisted, err := dao.NewUserCanvasDAO().GetByID("canvas-team")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to reload canvas: %v", err)
|
||||
}
|
||||
if persisted.Permission != "team" {
|
||||
t.Fatalf("team member changed permission to %q; want team", persisted.Permission)
|
||||
}
|
||||
if persisted.Title == nil || *persisted.Title != "Renamed by member" {
|
||||
t.Fatalf("title = %v, want Renamed by member", persisted.Title)
|
||||
}
|
||||
if persisted.Avatar == nil || *persisted.Avatar != "member-avatar" {
|
||||
t.Fatalf("avatar = %v, want member-avatar", persisted.Avatar)
|
||||
}
|
||||
|
||||
// Owner can change permission together with title/avatar.
|
||||
err = NewAgentService().UpdateAgent(context.Background(), "user-1", "canvas-team", map[string]interface{}{
|
||||
"title": "Owner updated",
|
||||
"avatar": "owner-avatar-2",
|
||||
"permission": "me",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("owner update failed: %v", err)
|
||||
}
|
||||
persisted, err = dao.NewUserCanvasDAO().GetByID("canvas-team")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to reload canvas: %v", err)
|
||||
}
|
||||
if persisted.Permission != "me" {
|
||||
t.Fatalf("owner permission = %q, want me", persisted.Permission)
|
||||
}
|
||||
if persisted.Title == nil || *persisted.Title != "Owner updated" {
|
||||
t.Fatalf("title = %v, want Owner updated", persisted.Title)
|
||||
}
|
||||
if persisted.Avatar == nil || *persisted.Avatar != "owner-avatar-2" {
|
||||
t.Fatalf("avatar = %v, want owner-avatar-2", persisted.Avatar)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateAgentPersistsDSLAsJSONMap(t *testing.T) {
|
||||
setupAgentSessionServiceTest(t)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user