[arvados] created: 2.1.0-2588-g74323ae3d

git repository hosting git at public.arvados.org
Mon Jun 6 15:48:50 UTC 2022


        at  74323ae3de455071de4fce0c2e2ee79a5650a040 (commit)


commit 74323ae3de455071de4fce0c2e2ee79a5650a040
Author: Tom Clegg <tom at curii.com>
Date:   Mon Jun 6 11:27:52 2022 -0400

    19146: Add can_write and can_manage response fields.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at curii.com>

diff --git a/doc/api/methods/groups.html.textile.liquid b/doc/api/methods/groups.html.textile.liquid
index 2a762d924..db0aac3c7 100644
--- a/doc/api/methods/groups.html.textile.liquid
+++ b/doc/api/methods/groups.html.textile.liquid
@@ -30,7 +30,9 @@ table(table table-bordered table-condensed).
 @"role"@|
 |description|text|||
 |properties|hash|User-defined metadata, may be used in queries using "subproperty filters":{{site.baseurl}}/api/methods.html#subpropertyfilters ||
-|writable_by|array|List of UUID strings identifying Users and other Groups that have write permission for this Group.  Only users who are allowed to administer the Group will receive a full list.  Other users will receive a partial list that includes the Group's owner_uuid and (if applicable) their own user UUID.||
+|writable_by|array|(Deprecated) List of UUID strings identifying Users and other Groups that have write permission for this Group.  Users who are allowed to administer the Group will receive a list of user/group UUIDs that have permission via explicit permission links; permissions via parent/ancestor groups are not taken into account.  Other users will receive a partial list including only the Group's owner_uuid and (if applicable) their own user UUID.||
+|can_write|boolean|True if the current user has write permission on this group.||
+|can_manage|boolean|True if the current user has manage permission on this group.||
 |trash_at|datetime|If @trash_at@ is non-null and in the past, this group and all objects directly or indirectly owned by the group will be hidden from API calls.  May be untrashed.||
 |delete_at|datetime|If @delete_at@ is non-null and in the past, the group and all objects directly or indirectly owned by the group may be permanently deleted.||
 |is_trashed|datetime|True if @trash_at@ is in the past, false if not.||
diff --git a/lib/controller/localdb/group_test.go b/lib/controller/localdb/group_test.go
index 2d55def9f..1fde64d11 100644
--- a/lib/controller/localdb/group_test.go
+++ b/lib/controller/localdb/group_test.go
@@ -24,14 +24,7 @@ type GroupSuite struct {
 	railsSpy *arvadostest.Proxy
 }
 
-func (s *GroupSuite) TearDownSuite(c *check.C) {
-	// Undo any changes/additions to the user database so they
-	// don't affect subsequent tests.
-	arvadostest.ResetEnv()
-	c.Check(arvados.NewClientFromEnv().RequestAndDecode(nil, "POST", "database/reset", nil, nil), check.IsNil)
-}
-
-func (s *GroupSuite) SetUpTest(c *check.C) {
+func (s *GroupSuite) SetUpSuite(c *check.C) {
 	cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
 	c.Assert(err, check.IsNil)
 	s.cluster, err = cfg.GetCluster("")
@@ -41,8 +34,12 @@ func (s *GroupSuite) SetUpTest(c *check.C) {
 	*s.localdb.railsProxy = *rpc.NewConn(s.cluster.ClusterID, s.railsSpy.URL, true, rpc.PassthroughTokenProvider)
 }
 
-func (s *GroupSuite) TearDownTest(c *check.C) {
+func (s *GroupSuite) TearDownSuite(c *check.C) {
 	s.railsSpy.Close()
+	// Undo any changes/additions to the user database so they
+	// don't affect subsequent tests.
+	arvadostest.ResetEnv()
+	c.Check(arvados.NewClientFromEnv().RequestAndDecode(nil, "POST", "database/reset", nil, nil), check.IsNil)
 }
 
 func (s *GroupSuite) setUpVocabulary(c *check.C, testVocabulary string) {
@@ -136,3 +133,99 @@ func (s *GroupSuite) TestGroupUpdateWithProperties(c *check.C) {
 		}
 	}
 }
+
+func (s *GroupSuite) TestCanWriteCanManageResponses(c *check.C) {
+	ctxUser1 := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.ActiveTokenV2}})
+	ctxUser2 := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.SpectatorToken}})
+	ctxAdmin := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.AdminToken}})
+	project, err := s.localdb.GroupCreate(ctxUser1, arvados.CreateOptions{
+		Attrs: map[string]interface{}{
+			"group_class": "project",
+		},
+	})
+	c.Assert(err, check.IsNil)
+	c.Check(project.CanWrite, check.Equals, true)
+	c.Check(project.CanManage, check.Equals, true)
+
+	subproject, err := s.localdb.GroupCreate(ctxUser1, arvados.CreateOptions{
+		Attrs: map[string]interface{}{
+			"owner_uuid":  project.UUID,
+			"group_class": "project",
+		},
+	})
+	c.Assert(err, check.IsNil)
+	c.Check(subproject.CanWrite, check.Equals, true)
+	c.Check(subproject.CanManage, check.Equals, true)
+
+	// Give 2nd user permission to read
+	permlink, err := s.localdb.LinkCreate(ctxAdmin, arvados.CreateOptions{
+		Attrs: map[string]interface{}{
+			"link_class": "permission",
+			"name":       "can_read",
+			"tail_uuid":  arvadostest.SpectatorUserUUID,
+			"head_uuid":  project.UUID,
+		},
+	})
+	c.Assert(err, check.IsNil)
+
+	// As 2nd user: can read, cannot manage, cannot write
+	project2, err := s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: project.UUID})
+	c.Assert(err, check.IsNil)
+	c.Check(project2.CanWrite, check.Equals, false)
+	c.Check(project2.CanManage, check.Equals, false)
+
+	_, err = s.localdb.LinkUpdate(ctxAdmin, arvados.UpdateOptions{
+		UUID: permlink.UUID,
+		Attrs: map[string]interface{}{
+			"name": "can_write",
+		},
+	})
+	c.Assert(err, check.IsNil)
+
+	// As 2nd user: cannot manage, can write
+	project2, err = s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: project.UUID})
+	c.Assert(err, check.IsNil)
+	c.Check(project2.CanWrite, check.Equals, true)
+	c.Check(project2.CanManage, check.Equals, false)
+
+	// As owner: after freezing, can manage (owner), cannot write (frozen)
+	project, err = s.localdb.GroupUpdate(ctxUser1, arvados.UpdateOptions{
+		UUID: project.UUID,
+		Attrs: map[string]interface{}{
+			"frozen_by_uuid": arvadostest.ActiveUserUUID,
+		}})
+	c.Assert(err, check.IsNil)
+	c.Check(project.CanWrite, check.Equals, false)
+	c.Check(project.CanManage, check.Equals, true)
+
+	// As admin: can manage (admin), cannot write (frozen)
+	project, err = s.localdb.GroupGet(ctxAdmin, arvados.GetOptions{UUID: project.UUID})
+	c.Assert(err, check.IsNil)
+	c.Check(project.CanWrite, check.Equals, false)
+	c.Check(project.CanManage, check.Equals, true)
+
+	// As 2nd user: cannot manage (perm), cannot write (frozen)
+	project2, err = s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: project.UUID})
+	c.Assert(err, check.IsNil)
+	c.Check(project2.CanWrite, check.Equals, false)
+	c.Check(project2.CanManage, check.Equals, false)
+
+	// After upgrading perm to "manage", as 2nd user: can manage (perm), cannot write (frozen)
+	_, err = s.localdb.LinkUpdate(ctxAdmin, arvados.UpdateOptions{
+		UUID: permlink.UUID,
+		Attrs: map[string]interface{}{
+			"name": "can_manage",
+		},
+	})
+	c.Assert(err, check.IsNil)
+	project2, err = s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: project.UUID})
+	c.Assert(err, check.IsNil)
+	c.Check(project2.CanWrite, check.Equals, false)
+	c.Check(project2.CanManage, check.Equals, true)
+
+	// 2nd user can also manage (but not write) the subject inside the frozen project
+	subproject2, err := s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: subproject.UUID})
+	c.Assert(err, check.IsNil)
+	c.Check(subproject2.CanWrite, check.Equals, false)
+	c.Check(subproject2.CanManage, check.Equals, true)
+}
diff --git a/sdk/go/arvados/group.go b/sdk/go/arvados/group.go
index ad7ac1ee2..0782bd43d 100644
--- a/sdk/go/arvados/group.go
+++ b/sdk/go/arvados/group.go
@@ -27,6 +27,8 @@ type Group struct {
 	WritableBy           []string               `json:"writable_by,omitempty"`
 	Description          string                 `json:"description"`
 	FrozenByUUID         string                 `json:"frozen_by_uuid"`
+	CanWrite             bool                   `json:"can_write"`
+	CanManage            bool                   `json:"can_manage"`
 }
 
 // GroupList is an arvados#groupList resource.
diff --git a/sdk/go/arvados/user.go b/sdk/go/arvados/user.go
index 68960144a..2fb061e7f 100644
--- a/sdk/go/arvados/user.go
+++ b/sdk/go/arvados/user.go
@@ -26,6 +26,8 @@ type User struct {
 	ModifiedByClientUUID string                 `json:"modified_by_client_uuid"`
 	Prefs                map[string]interface{} `json:"prefs"`
 	WritableBy           []string               `json:"writable_by,omitempty"`
+	CanWrite             bool                   `json:"can_write"`
+	CanManage            bool                   `json:"can_manage"`
 }
 
 // UserList is an arvados#userList resource.
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index 07a31d81a..e7ffe740b 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -273,6 +273,22 @@ class ArvadosModel < ApplicationRecord
     end.compact.uniq
   end
 
+  def can_write
+    if respond_to?(:frozen_by_uuid) && frozen_by_uuid
+      return false
+    else
+      return owner_uuid == current_user.uuid ||
+             current_user.is_admin ||
+             current_user.can?(write: uuid)
+    end
+  end
+
+  def can_manage
+    return owner_uuid == current_user.uuid ||
+           current_user.is_admin ||
+           current_user.can?(manage: uuid)
+  end
+
   # Return a query with read permissions restricted to the union of the
   # permissions of the members of users_list, i.e. if something is readable by
   # any user in users_list, it will be readable in the query returned by this
diff --git a/services/api/app/models/group.rb b/services/api/app/models/group.rb
index b1b2e942c..e18ee5ef3 100644
--- a/services/api/app/models/group.rb
+++ b/services/api/app/models/group.rb
@@ -44,6 +44,8 @@ class Group < ArvadosModel
     t.add :is_trashed
     t.add :properties
     t.add :frozen_by_uuid
+    t.add :can_write
+    t.add :can_manage
   end
 
   def ensure_filesystem_compatible_name
diff --git a/services/api/app/models/user.rb b/services/api/app/models/user.rb
index bbb2378f5..52b96f9c5 100644
--- a/services/api/app/models/user.rb
+++ b/services/api/app/models/user.rb
@@ -72,6 +72,8 @@ class User < ArvadosModel
     t.add :is_invited
     t.add :prefs
     t.add :writable_by
+    t.add :can_write
+    t.add :can_manage
   end
 
   ALL_PERMISSIONS = {read: true, write: true, manage: true}

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list