diff options
author | Bob Van Landuyt <bob@vanlanduyt.co> | 2019-06-18 16:18:26 +0200 |
---|---|---|
committer | Bob Van Landuyt <bob@vanlanduyt.co> | 2019-06-21 13:00:50 +0200 |
commit | ac2d08212b20bae20c85ea225ec3fb0052a9e1af (patch) | |
tree | 37ef6b98f39bd9eeb25b3306b09a868728602dc0 /rubocop/cop | |
parent | 2c48cb24983314ab78963d2dfb2a74b0f9104fc8 (diff) | |
download | gitlab-ce-ac2d08212b20bae20c85ea225ec3fb0052a9e1af.tar.gz |
Add a cop to ensure we authorize GraphQL types
Diffstat (limited to 'rubocop/cop')
-rw-r--r-- | rubocop/cop/graphql/authorize_types.rb | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/rubocop/cop/graphql/authorize_types.rb b/rubocop/cop/graphql/authorize_types.rb new file mode 100644 index 00000000000..93fe80c3edf --- /dev/null +++ b/rubocop/cop/graphql/authorize_types.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require_relative '../../spec_helpers' + +module RuboCop + module Cop + module Graphql + class AuthorizeTypes < RuboCop::Cop::Cop + include SpecHelpers + + MSG = 'Add an `authorize :ability` call to the type: '\ + 'https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#type-authorization' + + TYPES_DIR = 'app/graphql/types' + + # We want to exclude our own basetypes and scalars + WHITELISTED_TYPES = %w[BaseEnum BaseScalar BasePermissionType MutationType + QueryType GraphQL::Schema BaseUnion].freeze + + def_node_search :authorize?, <<~PATTERN + (send nil? :authorize ...) + PATTERN + + def on_class(node) + return unless in_type?(node) + return if whitelisted?(class_constant(node)) + return if whitelisted?(superclass_constant(node)) + + add_offense(node, location: :expression) unless authorize?(node) + end + + private + + def in_type?(node) + return if in_spec?(node) + + path = node.location.expression.source_buffer.name + + path.include?(TYPES_DIR) + end + + def whitelisted?(class_node) + return false unless class_node&.const_name + + WHITELISTED_TYPES.any? { |whitelisted| class_node.const_name.include?(whitelisted) } + end + + def class_constant(node) + node.descendants.first + end + + def superclass_constant(class_node) + # First one is the class name itself, second is it's superclass + _class_constant, *others = class_node.descendants + + others.find { |node| node.const_type? && node&.const_name != 'Types' } + end + end + end + end +end |