Class: RuboCop::Cop::GraphQL::NotAuthorizedNodeType

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/graphql/not_authorized_node_type.rb

Overview

Detects types that implement Node interface and not have ‘.authorized?` check. Such types can be fetched by ID and therefore should have type level check to avoid accidental information exposure.

If ‘.authorized?` is defined in a parent class, you can add parent to the “SafeBaseClasses” to avoid offenses in children.

This cop also checks the ‘can_can_action` or `pundit_role` methods that can be used as part of the Ruby GraphQL Pro.

Examples:

# good

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  field :uuid, ID, null: false

  def self.authorized?(object, context)
    super && object.owner == context[:viewer]
  end
end

# good

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  field :uuid, ID, null: false

  class << self
    def authorized?(object, context)
      super && object.owner == context[:viewer]
    end
  end
end

# good

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  pundit_role :staff

  field :uuid, ID, null: false
end

# good

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  can_can_action :staff

  field :uuid, ID, null: false
end

# bad

class UserType < BaseType
  implements GraphQL::Types::Relay::Node

  field :uuid, ID, null: false
end

Constant Summary collapse

MSG =
".authorized? should be defined for types implementing Node interface."

Instance Method Summary collapse

Instance Method Details

#has_authorized_method?(node) ⇒ Object



94
95
96
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 94

def_node_matcher :has_authorized_method?, <<~PATTERN
  {`(:defs (:self) :authorized? ...) | `(:sclass (:self) `(:def :authorized? ...))}
PATTERN

#has_can_can_action?(node) ⇒ Object



84
85
86
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 84

def_node_matcher :has_can_can_action?, <<~PATTERN
  `(send nil? :can_can_action {nil_type? sym_type?})
PATTERN

#has_pundit_role?(node) ⇒ Object



89
90
91
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 89

def_node_matcher :has_pundit_role?, <<~PATTERN
  `(send nil? :pundit_role {nil_type? sym_type?})
PATTERN

#implements_node_type?(node) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 75

def_node_matcher :implements_node_type?, <<~PATTERN
  `(send nil? :implements
    (const
      (const
        (const
          (const nil? :GraphQL) :Types) :Relay) :Node))
PATTERN

#on_class(node) ⇒ Object



103
104
105
106
107
108
109
110
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 103

def on_class(node)
  @parent_modules ||= []
  return if possible_parent_classes(node).any? { |klass| ignored_class?(klass) }

  @parent_modules << node.child_nodes[0].const_name

  add_offense(node) if implements_node_type?(node) && !implements_authorization?(node)
end

#on_module(node) ⇒ Object



98
99
100
101
# File 'lib/rubocop/cop/graphql/not_authorized_node_type.rb', line 98

def on_module(node)
  @parent_modules ||= []
  @parent_modules << node.child_nodes[0].const_name
end