Method: Ability.forgetting

Defined in:
app/models/ability.rb

.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



147
148
149
150
151
152
153
154
155
156
# File 'app/models/ability.rb', line 147

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