Merge pull request #8596 from tchak/secu-log-graphql-queries
secu(graphql): log full queries and variables
This commit is contained in:
commit
a217072b4f
4 changed files with 4 additions and 125 deletions
|
@ -1,6 +1,4 @@
|
||||||
class API::V2::GraphqlController < API::V2::BaseController
|
class API::V2::GraphqlController < API::V2::BaseController
|
||||||
include GraphqlOperationLogConcern
|
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
result = API::V2::Schema.execute(query,
|
result = API::V2::Schema.execute(query,
|
||||||
variables: variables,
|
variables: variables,
|
||||||
|
@ -24,7 +22,8 @@ class API::V2::GraphqlController < API::V2::BaseController
|
||||||
super
|
super
|
||||||
|
|
||||||
payload.merge!({
|
payload.merge!({
|
||||||
graphql_operation: operation_log(query(fallback: ''), params[:operationName], to_unsafe_hash(params[:variables]))
|
graphql_query: query(fallback: params[:queryId]),
|
||||||
|
graphql_variables: to_unsafe_hash(params[:variables]).to_json
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
module GraphqlOperationLogConcern
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
# This method parses GraphQL query and creates a short description of the query. It is useful for logging.
|
|
||||||
def operation_log(query, operation_name, variables)
|
|
||||||
return "NoQuery" if query.nil?
|
|
||||||
|
|
||||||
operation = parse_graphql_query(query, operation_name)
|
|
||||||
|
|
||||||
return "InvalidQuery" if operation.nil?
|
|
||||||
return "IntrospectionQuery" if operation.name == "IntrospectionQuery"
|
|
||||||
|
|
||||||
message = "#{operation.operation_type}: "
|
|
||||||
message += if operation.name.present?
|
|
||||||
"#{operation.name} { "
|
|
||||||
else
|
|
||||||
"{ "
|
|
||||||
end
|
|
||||||
message += operation.selections.map(&:name).join(', ')
|
|
||||||
message += " } "
|
|
||||||
message += if variables.present?
|
|
||||||
variables.flat_map do |(name, value)|
|
|
||||||
format_graphql_variable(name, value)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
operation.selections.flat_map(&:arguments).flat_map do |argument|
|
|
||||||
format_graphql_variable(argument.name, argument.value)
|
|
||||||
end
|
|
||||||
end.join(', ')
|
|
||||||
|
|
||||||
message.strip
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def parse_graphql_query(query, operation_name)
|
|
||||||
operations = GraphQL.parse(query).children.filter do |node|
|
|
||||||
node.is_a?(GraphQL::Language::Nodes::OperationDefinition)
|
|
||||||
end
|
|
||||||
if operations.size == 1
|
|
||||||
operations.first
|
|
||||||
else
|
|
||||||
operations.find { |node| node.name == operation_name }
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def format_graphql_variable(name, value)
|
|
||||||
if value.is_a?(Hash)
|
|
||||||
value.map do |(name, value)|
|
|
||||||
format_graphql_variable(name, value)
|
|
||||||
end
|
|
||||||
elsif value.is_a?(GraphQL::Language::Nodes::InputObject)
|
|
||||||
value.arguments.map do |argument|
|
|
||||||
format_graphql_variable(argument.name, argument.value)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
"#{name}: \"#{value.to_s.truncate(10)}\""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -14,7 +14,8 @@ Rails.application.configure do
|
||||||
user_email: event.payload[:user_email],
|
user_email: event.payload[:user_email],
|
||||||
user_roles: event.payload[:user_roles],
|
user_roles: event.payload[:user_roles],
|
||||||
user_agent: event.payload[:user_agent],
|
user_agent: event.payload[:user_agent],
|
||||||
graphql_operation: event.payload[:graphql_operation],
|
graphql_query: event.payload[:graphql_query],
|
||||||
|
graphql_variables: event.payload[:graphql_variables],
|
||||||
browser: event.payload[:browser],
|
browser: event.payload[:browser],
|
||||||
browser_version: event.payload[:browser_version],
|
browser_version: event.payload[:browser_version],
|
||||||
platform: event.payload[:platform]
|
platform: event.payload[:platform]
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
RSpec.describe GraphqlOperationLogConcern, type: :controller do
|
|
||||||
class TestController < ActionController::Base
|
|
||||||
include GraphqlOperationLogConcern
|
|
||||||
end
|
|
||||||
|
|
||||||
controller TestController do
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#operation_log' do
|
|
||||||
let(:query) { nil }
|
|
||||||
let(:variables) { nil }
|
|
||||||
let(:operation_name) { nil }
|
|
||||||
|
|
||||||
subject { controller.operation_log(query, operation_name, variables) }
|
|
||||||
|
|
||||||
context 'with no query' do
|
|
||||||
it { expect(subject).to eq('NoQuery') }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with invalid query' do
|
|
||||||
let(:query) { 'query { demarche {} }' }
|
|
||||||
|
|
||||||
it { expect(subject).to eq('InvalidQuery') }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with two queries' do
|
|
||||||
let(:query) { 'query demarche { demarche } query dossier { dossier }' }
|
|
||||||
let(:operation_name) { 'dossier' }
|
|
||||||
|
|
||||||
it { expect(subject).to eq('query: dossier { dossier }') }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with arguments' do
|
|
||||||
let(:query) { 'query demarche { demarche(number: 123) { id } }' }
|
|
||||||
|
|
||||||
it { expect(subject).to eq('query: demarche { demarche } number: "123"') }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with variables' do
|
|
||||||
let(:query) { 'query { demarche(number: 123) { id } }' }
|
|
||||||
let(:variables) { { number: 124 } }
|
|
||||||
|
|
||||||
it { expect(subject).to eq('query: { demarche } number: "124"') }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with mutation and arguments' do
|
|
||||||
let(:query) { 'mutation { passerDossierEnInstruction(input: { number: 123 }) { id } }' }
|
|
||||||
|
|
||||||
it { expect(subject).to eq('mutation: { passerDossierEnInstruction } number: "123"') }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with mutation and variables' do
|
|
||||||
let(:query) { 'mutation { passerDossierEnInstruction(input: { number: 123 }) { id } }' }
|
|
||||||
let(:variables) { { input: { number: 124 } } }
|
|
||||||
|
|
||||||
it { expect(subject).to eq('mutation: { passerDossierEnInstruction } number: "124"') }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Add table
Reference in a new issue