4253: Merge Repository permission requirements of #4253 and #5416.
[arvados.git] / services / api / test / unit / repository_test.rb
1 require 'test_helper'
2 require 'helpers/git_test_helper'
3
4 class RepositoryTest < ActiveSupport::TestCase
5   include GitTestHelper
6
7   def new_repo(owner_key, attrs={})
8     set_user_from_auth owner_key
9     owner = users(owner_key)
10     Repository.new({owner_uuid: owner.uuid}.merge(attrs))
11   end
12
13   def changed_repo(repo_key, changes)
14     repo = repositories(repo_key)
15     changes.each_pair { |attr, value| repo.send("#{attr}=".to_sym, value) }
16     repo
17   end
18
19   def default_git_url(repo_name, user_name=nil)
20     if user_name
21       "git@git.%s.arvadosapi.com:%s/%s.git" %
22         [Rails.configuration.uuid_prefix, user_name, repo_name]
23     else
24       "git@git.%s.arvadosapi.com:%s.git" %
25         [Rails.configuration.uuid_prefix, repo_name]
26     end
27   end
28
29   def assert_server_path(path_tail, repo_sym)
30     assert_equal(File.join(Rails.configuration.git_repositories_dir, path_tail),
31                  repositories(repo_sym).server_path)
32   end
33
34   ### name validation
35
36   {active: "active/", admin: "admin/", system_user: ""}.
37       each_pair do |user_sym, name_prefix|
38     %w(a aa a0 aA Aa AA A0).each do |name|
39       test "'#{name_prefix}#{name}' is a valid name for #{user_sym} repo" do
40         repo = new_repo(user_sym, name: name_prefix + name)
41         assert(repo.valid?)
42       end
43     end
44
45     test "name is required for #{user_sym} repo" do
46       refute(new_repo(user_sym).valid?)
47     end
48
49     test "repo name beginning with numeral is invalid for #{user_sym}" do
50       repo = new_repo(user_sym, name: "#{name_prefix}0a")
51       refute(repo.valid?)
52     end
53
54     "\\.-_/!@#$%^&*()[]{}".each_char do |bad_char|
55       test "name containing #{bad_char.inspect} is invalid for #{user_sym}" do
56         repo = new_repo(user_sym, name: "#{name_prefix}bad#{bad_char}reponame")
57         refute(repo.valid?)
58       end
59     end
60   end
61
62   test "admin can create valid repo for other user with correct name prefix" do
63     owner = users(:active)
64     repo = new_repo(:admin, name: "#{owner.username}/validnametest",
65                     owner_uuid: owner.uuid)
66     assert(repo.valid?)
67   end
68
69   test "admin can create valid system repo without name prefix" do
70     repo = new_repo(:admin, name: "validnametest",
71                     owner_uuid: users(:system_user).uuid)
72     assert(repo.valid?)
73   end
74
75   test "repo name prefix must match owner_uuid username" do
76     repo = new_repo(:admin, name: "admin/badusernametest",
77                     owner_uuid: users(:active).uuid)
78     refute(repo.valid?)
79   end
80
81   test "repo name prefix must be empty for system repo" do
82     repo = new_repo(:admin, name: "root/badprefixtest",
83                     owner_uuid: users(:system_user).uuid)
84     refute(repo.valid?)
85   end
86
87   ### owner validation
88
89   test "name must be unique per user" do
90     repo = new_repo(:active, name: repositories(:foo).name)
91     refute(repo.valid?)
92   end
93
94   test "name can be duplicated across users" do
95     repo = new_repo(:active, name: "active/#{repositories(:arvados).name}")
96     assert(repo.valid?)
97   end
98
99   test "repository cannot be owned by a group" do
100     set_user_from_auth :active
101     repo = Repository.new(owner_uuid: groups(:all_users).uuid,
102                           name: "ownedbygroup")
103     refute(repo.valid?)
104     refute_empty(repo.errors[:owner_uuid] || [])
105   end
106
107   ### URL generation
108
109   test "fetch_url" do
110     repo = new_repo(:active, name: "active/fetchtest")
111     assert_equal(default_git_url("fetchtest", "active"), repo.fetch_url)
112   end
113
114   test "fetch_url owned by system user" do
115     set_user_from_auth :admin
116     repo = Repository.new(owner_uuid: users(:system_user).uuid,
117                           name: "fetchtest")
118     assert_equal(default_git_url("fetchtest"), repo.fetch_url)
119   end
120
121   test "push_url" do
122     repo = new_repo(:active, name: "active/pushtest")
123     assert_equal(default_git_url("pushtest", "active"), repo.push_url)
124   end
125
126   test "push_url owned by system user" do
127     set_user_from_auth :admin
128     repo = Repository.new(owner_uuid: users(:system_user).uuid,
129                           name: "pushtest")
130     assert_equal(default_git_url("pushtest"), repo.push_url)
131   end
132
133   ### Path generation
134
135   test "disk path stored by UUID" do
136     assert_server_path("zzzzz-s0uqq-382brsig8rp3666/.git", :foo)
137   end
138
139   test "disk path stored by name" do
140     assert_server_path("arvados/.git", :arvados)
141   end
142
143   test "disk path for repository not on disk" do
144     assert_nil(Repository.new.server_path)
145   end
146
147   ### Repository creation
148
149   test "non-admin can create a repository for themselves" do
150     repo = new_repo(:active, name: "active/newtestrepo")
151     assert(repo.save)
152   end
153
154   test "non-admin can't create a repository for another visible user" do
155     repo = new_repo(:active, name: "repoforanon",
156                     owner_uuid: users(:anonymous).uuid)
157     assert_not_allowed { repo.save }
158   end
159
160   test "admin can create a repository for themselves" do
161     repo = new_repo(:admin, name: "admin/newtestrepo")
162     assert(repo.save)
163   end
164
165   test "admin can create a repository for others" do
166     repo = new_repo(:admin, name: "active/repoforactive",
167                     owner_uuid: users(:active).uuid)
168     assert(repo.save)
169   end
170
171   test "admin can create a system repository" do
172     repo = new_repo(:admin, name: "repoforsystem",
173                     owner_uuid: users(:system_user).uuid)
174     assert(repo.save)
175   end
176
177   ### Repository destruction
178
179   test "non-admin can destroy their own repository" do
180     set_user_from_auth :active
181     assert(repositories(:foo).destroy)
182   end
183
184   test "non-admin can't destroy others' repository" do
185     set_user_from_auth :active
186     assert_not_allowed { repositories(:repository3).destroy }
187   end
188
189   test "non-admin can't destroy system repository" do
190     set_user_from_auth :active
191     assert_not_allowed { repositories(:arvados).destroy }
192   end
193
194   test "admin can destroy their own repository" do
195     set_user_from_auth :admin
196     assert(repositories(:repository3).destroy)
197   end
198
199   test "admin can destroy others' repository" do
200     set_user_from_auth :admin
201     assert(repositories(:foo).destroy)
202   end
203
204   test "admin can destroy system repository" do
205     set_user_from_auth :admin
206     assert(repositories(:arvados).destroy)
207   end
208
209   ### Changing ownership
210
211   test "non-admin can't make their repository a system repository" do
212     set_user_from_auth :active
213     repo = changed_repo(:foo, owner_uuid: users(:system_user).uuid)
214     assert_not_allowed { repo.save }
215   end
216
217   test "admin can give their repository to someone else" do
218     set_user_from_auth :admin
219     repo = changed_repo(:repository3, owner_uuid: users(:active).uuid,
220                         name: "active/foo3")
221     assert(repo.save)
222   end
223
224   test "admin can make their repository a system repository" do
225     set_user_from_auth :admin
226     repo = changed_repo(:repository3, owner_uuid: users(:system_user).uuid,
227                         name: "foo3")
228     assert(repo.save)
229   end
230
231   test 'write permission allows changing modified_at' do
232     act_as_user users(:active) do
233       r = repositories(:foo)
234       modtime_was = r.modified_at
235       r.modified_at = Time.now
236       assert r.save
237       assert_operator modtime_was, :<, r.modified_at
238     end
239   end
240
241   test 'write permission necessary for changing modified_at' do
242     act_as_user users(:spectator) do
243       r = repositories(:foo)
244       modtime_was = r.modified_at
245       r.modified_at = Time.now
246       assert_raises ArvadosModel::PermissionDeniedError do
247         r.save!
248       end
249       r.reload
250       assert_equal modtime_was, r.modified_at
251     end
252   end
253
254   ### Renaming
255
256   test "non-admin can rename own repo" do
257     act_as_user users(:active) do
258       assert repositories(:foo).update_attributes(name: 'active/foo12345')
259     end
260   end
261
262   test "top level repo can be touched by non-admin with can_manage" do
263     add_permission_link users(:active), repositories(:arvados), 'can_manage'
264     act_as_user users(:active) do
265       assert changed_repo(:arvados, modified_at: Time.now).save
266     end
267   end
268
269   test "top level repo cannot be renamed by non-admin with can_manage" do
270     add_permission_link users(:active), repositories(:arvados), 'can_manage'
271     act_as_user users(:active) do
272       assert_not_allowed { changed_repo(:arvados, name: 'xarvados').save }
273     end
274   end
275 end