Class: Gitlab::GitAccess

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/git_access.rb

Direct Known Subclasses

GitAccessWiki

Constant Summary collapse

DOWNLOAD_COMMANDS =
%w{ git-upload-pack git-upload-archive }
PUSH_COMMANDS =
%w{ git-receive-pack }

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(actor, project) ⇒ GitAccess

Returns a new instance of GitAccess


8
9
10
11
# File 'lib/gitlab/git_access.rb', line 8

def initialize(actor, project)
  @actor    = actor
  @project  = project
end

Instance Attribute Details

#actorObject (readonly)

Returns the value of attribute actor


6
7
8
# File 'lib/gitlab/git_access.rb', line 6

def actor
  @actor
end

#projectObject (readonly)

Returns the value of attribute project


6
7
8
# File 'lib/gitlab/git_access.rb', line 6

def project
  @project
end

Instance Method Details

#can_push_to_branch?(ref) ⇒ Boolean

Returns:

  • (Boolean)

31
32
33
34
35
36
37
38
39
# File 'lib/gitlab/git_access.rb', line 31

def can_push_to_branch?(ref)
  return false unless user

  if project.protected_branch?(ref) && !project.developers_can_push_to_protected_branch?(ref)
    user.can?(:push_code_to_protected_branches, project)
  else
    user.can?(:push_code, project)
  end
end

#can_read_project?Boolean

Returns:

  • (Boolean)

41
42
43
44
45
46
47
48
49
# File 'lib/gitlab/git_access.rb', line 41

def can_read_project?
  if user
    user.can?(:read_project, project)
  elsif deploy_key
    deploy_key.projects.include?(project)
  else
    false
  end
end

#can_user_do_action?(action) ⇒ Boolean

Returns:

  • (Boolean)

125
126
127
128
# File 'lib/gitlab/git_access.rb', line 125

def can_user_do_action?(action)
  @permission_cache ||= {}
  @permission_cache[action] ||= user.can?(action, project)
end

#change_access_check(change) ⇒ Object


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/gitlab/git_access.rb', line 130

def change_access_check(change)
  oldrev, newrev, ref = change.split(' ')

  action =
    if project.protected_branch?(branch_name(ref))
      protected_branch_action(oldrev, newrev, branch_name(ref))
    elsif (tag_ref = tag_name(ref)) && protected_tag?(tag_ref)
      # Prevent any changes to existing git tag unless user has permissions
      :admin_project
    else
      :push_code
    end

  unless can_user_do_action?(action)
    status =
      case action
      when :force_push_code_to_protected_branches
        build_status_object(false, "You are not allowed to force push code to a protected branch on this project.")
      when :remove_protected_branches
        build_status_object(false, "You are not allowed to deleted protected branches from this project.")
      when :push_code_to_protected_branches
        build_status_object(false, "You are not allowed to push code to protected branches on this project.")
      when :admin_project
        build_status_object(false, "You are not allowed to change existing tags on this project.")
      else # :push_code
        build_status_object(false, "You are not allowed to push code to this project.")
      end
    return status
  end

  build_status_object(true)
end

#check(cmd, changes = nil) ⇒ Object


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/gitlab/git_access.rb', line 51

def check(cmd, changes = nil)
  unless actor
    return build_status_object(false, "No user or key was provided.")
  end

  if user && !user_allowed?
    return build_status_object(false, "Your account has been blocked.")
  end

  unless project && can_read_project?
    return build_status_object(false, 'The project you were looking for could not be found.')
  end

  case cmd
  when *DOWNLOAD_COMMANDS
    download_access_check
  when *PUSH_COMMANDS
    push_access_check(changes)
  else
    build_status_object(false, "The command you're trying to execute is not allowed.")
  end
end

#deploy_keyObject


27
28
29
# File 'lib/gitlab/git_access.rb', line 27

def deploy_key
  actor if actor.is_a?(DeployKey)
end

#download_access_checkObject


74
75
76
77
78
79
80
81
82
# File 'lib/gitlab/git_access.rb', line 74

def download_access_check
  if user
    user_download_access_check
  elsif deploy_key
    build_status_object(true)
  else
    raise 'Wrong actor'
  end
end

#forced_push?(oldrev, newrev) ⇒ Boolean

Returns:

  • (Boolean)

163
164
165
# File 'lib/gitlab/git_access.rb', line 163

def forced_push?(oldrev, newrev)
  Gitlab::ForcePushCheck.force_push?(project, oldrev, newrev)
end

#push_access_check(changes) ⇒ Object


84
85
86
87
88
89
90
91
92
# File 'lib/gitlab/git_access.rb', line 84

def push_access_check(changes)
  if user
    user_push_access_check(changes)
  elsif deploy_key
    build_status_object(false, "Deploy keys are not allowed to push code.")
  else
    raise 'Wrong actor'
  end
end

#userObject


13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/gitlab/git_access.rb', line 13

def user
  return @user if defined?(@user)

  @user =
    case actor
    when User
      actor
    when DeployKey
      nil
    when Key
      actor.user
    end
end

#user_download_access_checkObject


94
95
96
97
98
99
100
# File 'lib/gitlab/git_access.rb', line 94

def user_download_access_check
  unless user.can?(:download_code, project)
    return build_status_object(false, "You are not allowed to download code from this project.")
  end

  build_status_object(true)
end

#user_push_access_check(changes) ⇒ Object


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/gitlab/git_access.rb', line 102

def user_push_access_check(changes)
  if changes.blank?
    return build_status_object(true)
  end

  unless project.repository.exists?
    return build_status_object(false, "A repository for this project does not exist yet.")
  end

  changes = changes.lines if changes.kind_of?(String)

  # Iterate over all changes to find if user allowed all of them to be applied
  changes.map(&:strip).reject(&:blank?).each do |change|
    status = change_access_check(change)
    unless status.allowed?
      # If user does not have access to make at least one change - cancel all push
      return status
    end
  end

  build_status_object(true)
end