diff options
Diffstat (limited to 'spec/support/ability_check.rb')
-rw-r--r-- | spec/support/ability_check.rb | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/spec/support/ability_check.rb b/spec/support/ability_check.rb new file mode 100644 index 00000000000..213944506bb --- /dev/null +++ b/spec/support/ability_check.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'gitlab/utils/strong_memoize' + +module Support + module AbilityCheck + def self.inject(mod) + mod.prepend AbilityExtension + end + + module AbilityExtension + def before_check(policy, ability, user, subject, opts) + return super if Checker.ok?(policy, ability) + + ActiveSupport::Deprecation.warn(<<~WARNING) + Ability #{ability.inspect} in #{policy.class} not found. + user=#{user.inspect}, subject=#{subject}, opts=#{opts.inspect}" + + To exclude this check add this entry to #{Checker::TODO_YAML}: + #{policy.class}: + - #{ability} + WARNING + end + end + + module Checker + include Gitlab::Utils::StrongMemoize + extend self + + TODO_YAML = File.join(__dir__, 'ability_check_todo.yml') + + def ok?(policy, ability) + ignored?(policy, ability) || ability_found?(policy, ability) + end + + private + + def ignored?(policy, ability) + todo_list[policy.class.name]&.include?(ability.to_s) + end + + # Use Policy#has_ability? instead after it has been accepted and released. + # See https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/issues/25 + def ability_found?(policy, ability) + # NilPolicy has no abilities. Ignore it. + return true if policy.is_a?(DeclarativePolicy::NilPolicy) + + # Search in current policy first + return true if policy.class.ability_map.map.key?(ability) + + # Search recursively in all delegations otherwise. + # This is potentially slow. + # Stolen from: + # https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/blob/d691e/lib/declarative_policy/base.rb#L360-369 + policy.class.delegations.any? do |_, block| + new_subject = policy.instance_eval(&block) + new_policy = policy.policy_for(new_subject) + + ability_found?(new_policy, ability) + end + end + + def todo_list + hash = YAML.load_file(TODO_YAML) + return {} unless hash.is_a?(Hash) + + hash.transform_values(&:to_set) + end + + strong_memoize_attr :todo_list + end + end +end |