diff options
Diffstat (limited to 'app/services/jira')
-rw-r--r-- | app/services/jira/requests/base.rb | 80 |
1 files changed, 71 insertions, 9 deletions
diff --git a/app/services/jira/requests/base.rb b/app/services/jira/requests/base.rb index e4e2736ca2f..56484075d08 100644 --- a/app/services/jira/requests/base.rb +++ b/app/services/jira/requests/base.rb @@ -6,6 +6,17 @@ module Jira include ProjectServicesLoggable JIRA_API_VERSION = 2 + # Limit the size of the JSON error message we will attempt to parse, as the JSON is external input. + JIRA_ERROR_JSON_SIZE_LIMIT = 5_000 + + ERRORS = { + connection: [Errno::ECONNRESET, Errno::ECONNREFUSED], + jira_ruby: JIRA::HTTPError, + ssl: OpenSSL::SSL::SSLError, + timeout: [Timeout::Error, Errno::ETIMEDOUT], + uri: [URI::InvalidURIError, SocketError] + }.freeze + ALL_ERRORS = ERRORS.values.flatten.freeze def initialize(jira_integration, params = {}) @project = jira_integration&.project @@ -43,15 +54,66 @@ module Jira def request response = client.get(url) build_service_response(response) - rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED, URI::InvalidURIError, JIRA::HTTPError, OpenSSL::SSL::SSLError => error - error_message = "Jira request error: #{error.message}" - log_error("Error sending message", client_url: client.options[:site], - error: { - exception_class: error.class.name, - exception_message: error.message, - exception_backtrace: Gitlab::BacktraceCleaner.clean_backtrace(error.backtrace) - }) - ServiceResponse.error(message: error_message) + rescue *ALL_ERRORS => e + log_error('Error sending message', + client_url: client.options[:site], + error: { + exception_class: e.class.name, + exception_message: e.message, + exception_backtrace: Gitlab::BacktraceCleaner.clean_backtrace(e.backtrace) + } + ) + + ServiceResponse.error(message: error_message(e)) + end + + def error_message(error) + reportable_error_message(error) || + s_('JiraRequest|An error occurred while requesting data from Jira. Check your Jira integration configuration and try again.') + end + + # Returns a user-facing error message if possible, otherwise `nil`. + def reportable_error_message(error) + case error + when ERRORS[:jira_ruby] + reportable_jira_ruby_error_message(error) + when ERRORS[:ssl] + s_('JiraRequest|An SSL error occurred while connecting to Jira: %{message}. Try your request again.') % { message: error.message } + when *ERRORS[:uri] + s_('JiraRequest|The Jira API URL for connecting to Jira is not valid. Check your Jira integration API URL and try again.') + when *ERRORS[:timeout] + s_('JiraRequest|A timeout error occurred while connecting to Jira. Try your request again.') + when *ERRORS[:connection] + s_('JiraRequest|A connection error occurred while connecting to Jira. Try your request again.') + end + end + + # Returns a user-facing error message for a `JIRA::HTTPError` if possible, + # otherwise `nil`. + def reportable_jira_ruby_error_message(error) + case error.message + when 'Unauthorized' + s_('JiraRequest|The credentials for accessing Jira are not valid. Check your Jira integration credentials and try again.') + when 'Forbidden' + s_('JiraRequest|The credentials for accessing Jira are not allowed to access the data. Check your Jira integration credentials and try again.') + when 'Bad Request' + s_('JiraRequest|An error occurred while requesting data from Jira. Check your Jira integration configuration and try again.') + when /errorMessages/ + jira_ruby_json_error_message(error.message) + end + end + + def jira_ruby_json_error_message(error_message) + return if error_message.length > JIRA_ERROR_JSON_SIZE_LIMIT + + begin + messages = Gitlab::Json.parse(error_message)['errorMessages']&.to_sentence + messages = Rails::Html::FullSanitizer.new.sanitize(messages).presence + return unless messages + + s_('JiraRequest|An error occurred while requesting data from Jira: %{messages}. Check your Jira integration configuration and try again.') % { messages: messages } + rescue JSON::ParserError + end end def url |