18004: Fixes a couple of race condition bugs related to caching remote users.
[arvados.git] / services / api / lib / fix_roles_projects.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'update_permissions'
6
7 include CurrentApiClient
8
9 def fix_roles_projects
10   batch_update_permissions do
11     # This migration is not reversible.  However, the behavior it
12     # enforces is backwards-compatible, and most of the time there
13     # shouldn't be anything to do at all.
14     act_as_system_user do
15       ActiveRecord::Base.transaction do
16         Group.where("(group_class != 'project' and group_class != 'filter') or group_class is null").each do |g|
17           # 1) any group not group_class != project and != filter becomes a 'role' (both empty and invalid groups)
18           old_owner = g.owner_uuid
19           g.owner_uuid = system_user_uuid
20           g.group_class = 'role'
21           g.save_with_unique_name!
22
23           if old_owner != system_user_uuid
24             # 2) Ownership of a role becomes a can_manage link
25             Link.new(link_class: 'permission',
26                          name: 'can_manage',
27                          tail_uuid: old_owner,
28                          head_uuid: g.uuid).
29               save!(validate: false)
30           end
31         end
32
33         ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |klass|
34           next if [ApiClientAuthorization,
35                    AuthorizedKey,
36                    Log,
37                    Group].include?(klass)
38           next if !klass.columns.collect(&:name).include?('owner_uuid')
39
40           # 3) If a role owns anything, give it to system user and it
41           # becomes a can_manage link
42           klass.joins("join groups on groups.uuid=#{klass.table_name}.owner_uuid and groups.group_class='role'").each do |owned|
43             Link.new(link_class: 'permission',
44                      name: 'can_manage',
45                      tail_uuid: owned.owner_uuid,
46                      head_uuid: owned.uuid).
47               save!(validate: false)
48             owned.owner_uuid = system_user_uuid
49             owned.save_with_unique_name!
50           end
51         end
52
53         Group.joins("join groups as g2 on g2.uuid=groups.owner_uuid and g2.group_class='role'").each do |owned|
54           Link.new(link_class: 'permission',
55                        name: 'can_manage',
56                        tail_uuid: owned.owner_uuid,
57                        head_uuid: owned.uuid).
58             save!(validate: false)
59           owned.owner_uuid = system_user_uuid
60           owned.save_with_unique_name!
61         end
62
63         # 4) Projects can't have outgoing permission links.  Just
64         # print a warning and delete them.
65         q = ActiveRecord::Base.connection.exec_query %{
66 select links.uuid from links, groups where groups.uuid = links.tail_uuid and
67        links.link_class = 'permission' and groups.group_class = 'project'
68 }
69         q.each do |lu|
70           ln = Link.find_by_uuid(lu['uuid'])
71           puts "WARNING: Projects cannot have outgoing permission links, removing '#{ln.name}' link #{ln.uuid} from #{ln.tail_uuid} to #{ln.head_uuid}"
72           Rails.logger.warn "Projects cannot have outgoing permission links, removing '#{ln.name}' link #{ln.uuid} from #{ln.tail_uuid} to #{ln.head_uuid}"
73           ln.destroy!
74         end
75       end
76     end
77   end
78 end