[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