Class: Ability
- Inherits:
-
Object
- Object
- Ability
- Defined in:
- app/models/ability.rb
Class Method Summary collapse
- .allowed?(user, ability, subject = :global, opts = {}) ⇒ Boolean
-
.before_check(policy, ability, user, subject, opts) ⇒ Object
Hook call right before ability check.
- .feature_flags_readable_by_user(feature_flags, user = nil, filters: {}) ⇒ Object
-
.forgetting(pattern, &block) ⇒ Object
This method is something of a band-aid over the problem.
-
.issues_readable_by_user(issues, user = nil, filters: {}) ⇒ Object
(also: work_items_readable_by_user)
Returns an Array of Issues that can be read by the given user.
-
.merge_requests_readable_by_user(merge_requests, user = nil, filters: {}) ⇒ Object
Returns an Array of MergeRequests that can be read by the given user.
- .policy_for(user, subject = :global) ⇒ Object
-
.users_that_can_read_group(users, group) ⇒ Object
Given a list of users and a group this method returns the users that can read the given group.
-
.users_that_can_read_internal_notes(users, note_parent) ⇒ Object
A list of users that can read confidential notes in a project.
-
.users_that_can_read_personal_snippet(users, snippet) ⇒ Object
Given a list of users and a snippet this method returns the users that can read the given snippet.
-
.users_that_can_read_project(users, project) ⇒ Object
Given a list of users and a project this method returns the users that can read the given project.
Class Method Details
.allowed?(user, ability, subject = :global, opts = {}) ⇒ Boolean
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'app/models/ability.rb', line 73 def allowed?(user, ability, subject = :global, opts = {}) if subject.is_a?(Hash) opts = subject subject = :global end policy = policy_for(user, subject) before_check(policy, ability.to_sym, user, subject, opts) case opts[:scope] when :user DeclarativePolicy.user_scope { policy.allowed?(ability) } when :subject DeclarativePolicy.subject_scope { policy.allowed?(ability) } else policy.allowed?(ability) end ensure # TODO: replace with runner invalidation: # See: https://gitlab.com/gitlab-org/declarative-policy/-/merge_requests/24 # See: https://gitlab.com/gitlab-org/declarative-policy/-/merge_requests/25 forget_runner_result(policy.runner(ability)) if policy && ability_forgetting? end |
.before_check(policy, ability, user, subject, opts) ⇒ Object
Hook call right before ability check.
99 100 101 |
# File 'app/models/ability.rb', line 99 def before_check(policy, ability, user, subject, opts) # See Support::AbilityCheck and Support::PermissionsCheck. end |
.feature_flags_readable_by_user(feature_flags, user = nil, filters: {}) ⇒ Object
65 66 67 68 69 70 71 |
# File 'app/models/ability.rb', line 65 def feature_flags_readable_by_user(feature_flags, user = nil, filters: {}) feature_flags = apply_filters_if_needed(feature_flags, user, filters) DeclarativePolicy.user_scope do feature_flags.select { |flag| allowed?(user, :read_feature_flag, flag) } end end |
.forgetting(pattern, &block) ⇒ Object
This method is something of a band-aid over the problem. The problem is that some conditions may not be re-entrant, if facts change. (‘BasePolicy#admin?` is a known offender, due to the effects of `admin_mode`)
To deal with this we need to clear two elements of state: the offending conditions (selected by ‘pattern’) and the cached ability checks (cached on the ‘policy#runner(ability)`).
Clearing the conditions (see ‘forget_all_but`) is fairly robust, provided the pattern is not under-selective. Clearing the runners is harder, since there is not good way to know which abilities any given condition may affect. The approach taken here (see `forget_runner_result`) is to discard all runner results generated during a `forgetting` block. This may be under-selective if a runner prior to this block cached a state value that might now be invalid.
TODO: add some kind of reverse-dependency mapping in DeclarativePolicy See: gitlab.com/gitlab-org/declarative-policy/-/issues/14
126 127 128 129 130 131 132 133 134 135 |
# File 'app/models/ability.rb', line 126 def forgetting(pattern, &block) was_forgetting = ability_forgetting? ::Gitlab::SafeRequestStore[:ability_forgetting] = true keys_before = ::Gitlab::SafeRequestStore.storage.keys yield ensure ::Gitlab::SafeRequestStore[:ability_forgetting] = was_forgetting forget_all_but(keys_before, matching: pattern) end |
.issues_readable_by_user(issues, user = nil, filters: {}) ⇒ Object Also known as: work_items_readable_by_user
Returns an Array of Issues that can be read by the given user.
issues - The issues to reduce down to those readable by the user. user - The User for which to check the issues filters - A hash of abilities and filters to apply if the user lacks this
ability
42 43 44 45 46 47 48 |
# File 'app/models/ability.rb', line 42 def issues_readable_by_user(issues, user = nil, filters: {}) issues = apply_filters_if_needed(issues, user, filters) DeclarativePolicy.user_scope do issues.select { |issue| issue.visible_to_user?(user) } end end |
.merge_requests_readable_by_user(merge_requests, user = nil, filters: {}) ⇒ Object
Returns an Array of MergeRequests that can be read by the given user.
merge_requests - MRs out of which to collect MRs readable by the user. user - The User for which to check the merge_requests filters - A hash of abilities and filters to apply if the user lacks this
ability
57 58 59 60 61 62 63 |
# File 'app/models/ability.rb', line 57 def merge_requests_readable_by_user(merge_requests, user = nil, filters: {}) merge_requests = apply_filters_if_needed(merge_requests, user, filters) DeclarativePolicy.user_scope do merge_requests.select { |mr| allowed?(user, :read_merge_request, mr) } end end |
.policy_for(user, subject = :global) ⇒ Object
103 104 105 |
# File 'app/models/ability.rb', line 103 def policy_for(user, subject = :global) DeclarativePolicy.policy_for(user, subject, cache: ::Gitlab::SafeRequestStore.storage) end |
.users_that_can_read_group(users, group) ⇒ Object
Given a list of users and a group this method returns the users that can read the given group.
15 16 17 18 19 |
# File 'app/models/ability.rb', line 15 def users_that_can_read_group(users, group) DeclarativePolicy.subject_scope do users.select { |u| allowed?(u, :read_group, group) } end end |
.users_that_can_read_internal_notes(users, note_parent) ⇒ Object
A list of users that can read confidential notes in a project
30 31 32 33 34 |
# File 'app/models/ability.rb', line 30 def users_that_can_read_internal_notes(users, note_parent) DeclarativePolicy.subject_scope do users.select { |u| allowed?(u, :read_internal_note, note_parent) } end end |
.users_that_can_read_personal_snippet(users, snippet) ⇒ Object
Given a list of users and a snippet this method returns the users that can read the given snippet.
23 24 25 26 27 |
# File 'app/models/ability.rb', line 23 def users_that_can_read_personal_snippet(users, snippet) DeclarativePolicy.subject_scope do users.select { |u| allowed?(u, :read_snippet, snippet) } end end |
.users_that_can_read_project(users, project) ⇒ Object
Given a list of users and a project this method returns the users that can read the given project.
7 8 9 10 11 |
# File 'app/models/ability.rb', line 7 def users_that_can_read_project(users, project) DeclarativePolicy.subject_scope do users.select { |u| allowed?(u, :read_project, project) } end end |