Commit 78e67fc8 authored by Dmytro Zaporozhets's avatar Dmytro Zaporozhets

Improve error tracking error handling

Instead of failing with 500 error when payload is invalid or
activerecord is invalid, we handle those scenarios and return a 400
error response to the client.

Changelog: changed
Signed-off-by: default avatarDmytro Zaporozhets <dzaporozhets@gitlab.com>
parent 5c9fefb0
{ {
"description": "Error tracking event payload", "description": "Error tracking event payload",
"type": "object", "type": "object",
"required": [], "required": ["exception"],
"properties": { "properties": {
"environment": { "environment": {
"type": "string" "type": "string"
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
}, },
"exception": { "exception": {
"type": "object", "type": "object",
"required": [], "required": ["values"],
"properties": { "properties": {
"values": { "values": {
"type": "array", "type": "array",
......
...@@ -12,6 +12,10 @@ module API ...@@ -12,6 +12,10 @@ module API
content_type :txt, 'text/plain' content_type :txt, 'text/plain'
default_format :envelope default_format :envelope
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
before do before do
not_found!('Project') unless project not_found!('Project') unless project
not_found! unless feature_enabled? not_found! unless feature_enabled?
...@@ -50,6 +54,12 @@ module API ...@@ -50,6 +54,12 @@ module API
bad_request!('Failed to parse sentry request') bad_request!('Failed to parse sentry request')
end end
end end
def validate_payload(payload)
unless ::ErrorTracking::Collector::PayloadValidator.new.valid?(payload)
bad_request!('Unsupported sentry payload')
end
end
end end
desc 'Submit error tracking event to the project as envelope' do desc 'Submit error tracking event to the project as envelope' do
...@@ -88,6 +98,8 @@ module API ...@@ -88,6 +98,8 @@ module API
# We don't have use for transaction request yet, # We don't have use for transaction request yet,
# so we record only event one. # so we record only event one.
if type == 'event' if type == 'event'
validate_payload(parsed_request[:event])
::ErrorTracking::CollectErrorService ::ErrorTracking::CollectErrorService
.new(project, nil, event: parsed_request[:event]) .new(project, nil, event: parsed_request[:event])
.execute .execute
...@@ -125,6 +137,8 @@ module API ...@@ -125,6 +137,8 @@ module API
bad_request!('Failed to parse sentry request') bad_request!('Failed to parse sentry request')
end end
validate_payload(parsed_body)
::ErrorTracking::CollectErrorService ::ErrorTracking::CollectErrorService
.new(project, nil, event: parsed_body) .new(project, nil, event: parsed_body)
.execute .execute
......
# frozen_string_literal: true
module ErrorTracking
module Collector
class PayloadValidator
PAYLOAD_SCHEMA_PATH = Rails.root.join('app', 'validators', 'json_schemas', 'error_tracking_event_payload.json').to_s
def valid?(payload)
JSONSchemer.schema(Pathname.new(PAYLOAD_SCHEMA_PATH)).valid?(payload)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ErrorTracking::Collector::PayloadValidator do
describe '#valid?' do
RSpec.shared_examples 'valid payload' do
it 'returns true' do
expect(described_class.new.valid?(payload)).to be_truthy
end
end
RSpec.shared_examples 'invalid payload' do
it 'returns false' do
expect(described_class.new.valid?(payload)).to be_falsey
end
end
context 'ruby payload' do
let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/parsed_event.json')) }
it_behaves_like 'valid payload'
end
context 'python payload' do
let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/python_event.json')) }
it_behaves_like 'valid payload'
end
context 'browser payload' do
let(:payload) { Gitlab::Json.parse(fixture_file('error_tracking/browser_event.json')) }
it_behaves_like 'valid payload'
end
context 'empty payload' do
let(:payload) { '' }
it_behaves_like 'invalid payload'
end
context 'invalid payload' do
let(:payload) { { 'foo' => 'bar' } }
it_behaves_like 'invalid payload'
end
end
end
...@@ -136,6 +136,21 @@ RSpec.describe API::ErrorTracking::Collector do ...@@ -136,6 +136,21 @@ RSpec.describe API::ErrorTracking::Collector do
it_behaves_like 'bad request' it_behaves_like 'bad request'
end end
context 'body with string instead of json' do
let(:params) { '"********"' }
it_behaves_like 'bad request'
end
context 'collector fails with validation error' do
before do
allow(::ErrorTracking::CollectErrorService)
.to receive(:new).and_raise(ActiveRecord::RecordInvalid)
end
it_behaves_like 'bad request'
end
context 'gzip body' do context 'gzip body' do
let(:headers) do let(:headers) do
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment