From 9f7bec894288131af3fe1a6779f6837b62ea0ce1 Mon Sep 17 00:00:00 2001 From: Martin Gruner Date: Tue, 20 Jul 2021 13:31:46 +0000 Subject: [PATCH] Maintenance: Add Brakeman for static security analysis. --- .gitlab/ci/pre.yml | 11 + Gemfile | 1 + Gemfile.lock | 2 + .../application_controller/prevents_csrf.rb | 3 +- .../import_freshdesk_controller.rb | 2 +- app/controllers/import_zendesk_controller.rb | 4 +- .../knowledge_base/categories_controller.rb | 8 +- app/controllers/mentions_controller.rb | 14 +- app/models/cti/driver/placetel.rb | 1 + app/models/cti/driver/sipgate_io.rb | 1 + app/models/locale.rb | 1 + app/models/text_module.rb | 4 +- app/models/transaction/slack.rb | 3 +- app/models/translation.rb | 2 + config/brakeman.ignore | 742 ++++++++++++++++++ config/brakeman.yml | 3 + config/initializers/cookies_serializer.rb | 4 +- lib/github/http_client.rb | 1 + lib/gitlab/http_client.rb | 1 + lib/models.rb | 8 +- .../freshdesk/conversation/attachments.rb | 1 + .../freshdesk/conversation/inline_images.rb | 1 + .../ticket/comment/attachment/request.rb | 1 + lib/service/geo_calendar/zammad.rb | 1 + lib/service/geo_ip/zammad.rb | 1 + lib/service/geo_location/gmaps.rb | 2 + lib/service/image/zammad.rb | 2 + lib/telegram.rb | 1 + lib/twitter_sync.rb | 1 + .../ticket/comment/attachment/request_spec.rb | 2 +- 30 files changed, 805 insertions(+), 24 deletions(-) create mode 100644 config/brakeman.ignore create mode 100644 config/brakeman.yml diff --git a/.gitlab/ci/pre.yml b/.gitlab/ci/pre.yml index 8e780b3db..5a6d2a651 100644 --- a/.gitlab/ci/pre.yml +++ b/.gitlab/ci/pre.yml @@ -34,6 +34,17 @@ zeitwerk_check: - bundle exec rake zammad:db:init - bundle exec rails zeitwerk:check +brakeman: + <<: *template_pre + artifacts: + expire_in: 1 week + paths: + - tmp/brakeman-report.html + when: on_failure + script: + - bundle install -j $(nproc) --path vendor + - bundle exec brakeman -o /dev/stdout -o tmp/brakeman-report.html + coffeelint: <<: *template_pre script: diff --git a/Gemfile b/Gemfile index aefd16123..05c4b6059 100644 --- a/Gemfile +++ b/Gemfile @@ -189,6 +189,7 @@ group :development, :test do gem 'guard-symlink', require: false # code QA + gem 'brakeman', require: false gem 'coffeelint' gem 'overcommit' gem 'rubocop' diff --git a/Gemfile.lock b/Gemfile.lock index 72ef34028..40d9f8505 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -127,6 +127,7 @@ GEM tzinfo bootsnap (1.7.5) msgpack (~> 1.0) + brakeman (5.0.4) browser (5.3.1) buftok (0.2.0) builder (3.2.4) @@ -657,6 +658,7 @@ DEPENDENCIES autoprefixer-rails biz bootsnap + brakeman browser byebug capybara diff --git a/app/controllers/application_controller/prevents_csrf.rb b/app/controllers/application_controller/prevents_csrf.rb index 9acc129a6..176bed83f 100644 --- a/app/controllers/application_controller/prevents_csrf.rb +++ b/app/controllers/application_controller/prevents_csrf.rb @@ -26,8 +26,7 @@ module ApplicationController::PreventsCsrf def verify_csrf_token return true if !protect_against_forgery? - return true if request.get? - return true if request.head? + return true if request.get? || request.head? return true if %w[token_auth basic_auth].include?(@_auth_type) # call Rails method to verify CRSF token diff --git a/app/controllers/import_freshdesk_controller.rb b/app/controllers/import_freshdesk_controller.rb index 00dda7178..96b0ae0aa 100644 --- a/app/controllers/import_freshdesk_controller.rb +++ b/app/controllers/import_freshdesk_controller.rb @@ -17,7 +17,7 @@ class ImportFreshdeskController < ApplicationController endpoint = "#{params[:url]}/api/v2" endpoint.gsub!(%r{([^:])//+}, '\\1/') - response = UserAgent.request("#{endpoint}/contacts") + response = UserAgent.request("#{endpoint}/contacts", verify_ssl: true) if response.header.nil? || !response.header['x-freshdesk-api-version'] render json: { diff --git a/app/controllers/import_zendesk_controller.rb b/app/controllers/import_zendesk_controller.rb index cbe620622..837635772 100644 --- a/app/controllers/import_zendesk_controller.rb +++ b/app/controllers/import_zendesk_controller.rb @@ -23,7 +23,7 @@ class ImportZendeskController < ApplicationController 'Connection refused' => 'Connection refused!', } - response = UserAgent.request(params[:url]) + response = UserAgent.request(params[:url], verify_ssl: true) if !response.success? message_human = '' @@ -41,7 +41,7 @@ class ImportZendeskController < ApplicationController end # since 2016-10-15 a redirect to a marketing page has been implemented - if !response.body.match?(%r{#{params[:url]}}) + if response.body.exclude?(params[:url]) render json: { result: 'invalid', message_human: 'Hostname not found!', diff --git a/app/controllers/knowledge_base/categories_controller.rb b/app/controllers/knowledge_base/categories_controller.rb index e65850f0e..9e3a1639e 100644 --- a/app/controllers/knowledge_base/categories_controller.rb +++ b/app/controllers/knowledge_base/categories_controller.rb @@ -4,20 +4,20 @@ class KnowledgeBase::CategoriesController < KnowledgeBase::BaseController before_action :load_knowledge_base, only: %i[reorder_root_categories reorder_categories reorder_answers] def reorder_root_categories - reorder @knowledge_base.categories.root, params[:ordered_ids], KnowledgeBase::Category + reorder_records @knowledge_base.categories.root, params[:ordered_ids], KnowledgeBase::Category end def reorder_categories - reorder @category.children, params[:ordered_ids], KnowledgeBase::Category + reorder_records @category.children, params[:ordered_ids], KnowledgeBase::Category end def reorder_answers - reorder @category.answers, params[:ordered_ids], KnowledgeBase::Answer + reorder_records @category.answers, params[:ordered_ids], KnowledgeBase::Answer end private - def reorder(collection, ids, klass) + def reorder_records(collection, ids, klass) # Check if ids for models in collection are present all_ids_present = collection.map(&:id).sort == ids.sort raise Exceptions::UnprocessableEntity, 'Provide position of all items in scope' if !all_ids_present diff --git a/app/controllers/mentions_controller.rb b/app/controllers/mentions_controller.rb index e20e4f324..3bf011885 100644 --- a/app/controllers/mentions_controller.rb +++ b/app/controllers/mentions_controller.rb @@ -53,22 +53,22 @@ class MentionsController < ApplicationController private - def ensure_mentionable_type! - return if ['Ticket'].include?(params[:mentionable_type]) + def mentionable_type! + @mentionable_type ||= begin + raise 'Invalid mentionable_type!' if 'Ticket'.freeze != params[:mentionable_type] - raise 'Invalid mentionable_type!' + params[:mentionable_type] + end end def mentionable! - ensure_mentionable_type! - - object = params[:mentionable_type].constantize.find(params[:mentionable_id]) + object = mentionable_type!.constantize.find(params[:mentionable_id]) authorize!(object, :agent_read_access?) object end def fill_condition_mentionable(condition) - condition[:mentionable_type] = params[:mentionable_type] + condition[:mentionable_type] = mentionable_type! return if params[:mentionable_id].blank? condition[:mentionable_id] = params[:mentionable_id] diff --git a/app/models/cti/driver/placetel.rb b/app/models/cti/driver/placetel.rb index cd7c462e2..7551bd7b1 100644 --- a/app/models/cti/driver/placetel.rb +++ b/app/models/cti/driver/placetel.rb @@ -101,6 +101,7 @@ class Cti::Driver::Placetel < Cti::Driver::Base open_timeout: 4, read_timeout: 6, total_timeout: 6, + verify_ssl: true, }, ) diff --git a/app/models/cti/driver/sipgate_io.rb b/app/models/cti/driver/sipgate_io.rb index 3801c1504..519cfc6c9 100644 --- a/app/models/cti/driver/sipgate_io.rb +++ b/app/models/cti/driver/sipgate_io.rb @@ -47,6 +47,7 @@ class Cti::Driver::SipgateIo < Cti::Driver::Base open_timeout: 4, read_timeout: 6, total_timeout: 6, + verify_ssl: true, }, ) diff --git a/app/models/locale.rb b/app/models/locale.rb index 88e255047..d36afa1c2 100644 --- a/app/models/locale.rb +++ b/app/models/locale.rb @@ -106,6 +106,7 @@ all: json: true, open_timeout: 8, read_timeout: 24, + verify_ssl: true, } ) diff --git a/app/models/text_module.rb b/app/models/text_module.rb index 2b20f79bc..4e7ebfa3b 100644 --- a/app/models/text_module.rb +++ b/app/models/text_module.rb @@ -37,7 +37,8 @@ load text modules from online url, {}, { - json: true, + json: true, + verify_ssl: true, } ) @@ -98,6 +99,7 @@ push text_modules to online json: true, open_timeout: 6, read_timeout: 16, + verify_ssl: true, } ) raise "Can't push text_modules to #{url}: #{result.error}" if !result.success? diff --git a/app/models/transaction/slack.rb b/app/models/transaction/slack.rb index a988e6c13..2f4f7b9f2 100644 --- a/app/models/transaction/slack.rb +++ b/app/models/transaction/slack.rb @@ -300,7 +300,8 @@ class Transaction::Slack total_timeout: 20, log: { facility: 'slack_webhook', - } + }, + verify_ssl: true, }, ) end diff --git a/app/models/translation.rb b/app/models/translation.rb index e5daad546..906e65a58 100644 --- a/app/models/translation.rb +++ b/app/models/translation.rb @@ -85,6 +85,7 @@ push translations to online json: true, open_timeout: 8, read_timeout: 24, + verify_ssl: true, } ) raise "Can't push translations to #{url}: #{result.error}" if !result.success? @@ -355,6 +356,7 @@ all: json: true, open_timeout: 8, read_timeout: 24, + verify_ssl: true, } ) raise "Can't load translations from #{url}: #{result.error}" if !result.success? diff --git a/config/brakeman.ignore b/config/brakeman.ignore new file mode 100644 index 000000000..f27e7ab70 --- /dev/null +++ b/config/brakeman.ignore @@ -0,0 +1,742 @@ +{ + "ignored_warnings": [ + { + "warning_type": "Redirect", + "warning_code": 18, + "fingerprint": "069e68c2898ea30f966463fa4616887fb203d48d8c2184693d56569d41f2d3b7", + "check_name": "Redirect", + "message": "Possible unprotected redirect", + "file": "app/controllers/external_credentials_controller.rb", + "line": 38, + "link": "https://brakemanscanner.org/docs/warning_types/redirect/", + "code": "redirect_to(ExternalCredential.request_account_to_link(params[:provider].downcase)[:authorize_url])", + "render_path": null, + "location": { + "type": "method", + "class": "ExternalCredentialsController", + "method": "link_account" + }, + "user_input": "ExternalCredential.request_account_to_link(params[:provider].downcase)[:authorize_url]", + "confidence": "High", + "note": "" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "0fcd117fd53301f531142fc075ee8d30219c1239affce9322f9939ac0572ba3b", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "app/models/ticket/number.rb", + "line": 45, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "Setting.get(\"ticket_number\").constantize", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Number", + "method": "Ticket::Number.adapter" + }, + "user_input": "Setting.get(\"ticket_number\")", + "confidence": "Medium", + "note": "Setting.get(\"ticket_number\") returns defined ticket number backend class names" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "15d4ddbc3ac2ae0a0fe27218a42a1920fe2c1868ae5f504422c4af8ffe893beb", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/channel/filter/monitoring_base.rb", + "line": 92, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/#{(Setting.get(\"#{integration_name}_recovery_match\") or \"(OK|UP)\")}/i", + "render_path": null, + "location": { + "type": "method", + "class": "Channel::Filter::MonitoringBase", + "method": "Channel::Filter::MonitoringBase.run" + }, + "user_input": "Setting.get(\"#{integration_name}_recovery_match\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "15d4ddbc3ac2ae0a0fe27218a42a1920fe2c1868ae5f504422c4af8ffe893beb", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/channel/filter/monitoring_base.rb", + "line": 121, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/#{(Setting.get(\"#{integration_name}_recovery_match\") or \"(OK|UP)\")}/i", + "render_path": null, + "location": { + "type": "method", + "class": "Channel::Filter::MonitoringBase", + "method": "Channel::Filter::MonitoringBase.run" + }, + "user_input": "Setting.get(\"#{integration_name}_recovery_match\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "176994cedb6a57bc52f7a98b0fd93caad211f8f3b48fd010a5db164b37992e1f", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "app/models/avatar.rb", + "line": 405, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "ObjectLookup.by_id(object_id).constantize", + "render_path": null, + "location": { + "type": "method", + "class": "Avatar", + "method": "Avatar._add_init_avatar" + }, + "user_input": "ObjectLookup.by_id(object_id)", + "confidence": "Medium", + "note": "ObjectLookup.by_id works as designed" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "230f45f9fba03dd6308704600d0c2cd639ab138a3a485c0dc54f750356d22ebc", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/subject.rb", + "line": 67, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/#{Setting.get(\"ticket_hook\")}:#{number}(\\s+?|)/", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Subject", + "method": "subject_clean" + }, + "user_input": "Setting.get(\"ticket_hook\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "2eaeb513e1e099ce8bf973d91a9bfce398910cdcede6fce7469d6bd576fe938f", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/subject.rb", + "line": 63, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/\\[#{Setting.get(\"ticket_hook\")}#{Setting.get(\"ticket_hook_divider\")}#{number}\\](\\s+?|)/", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Subject", + "method": "subject_clean" + }, + "user_input": "Setting.get(\"ticket_hook\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "34d5d0f52def9a9fbcb045f4f16b0117cb22d59d8ab6184f3bddd057d81d7cd1", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/models/channel/filter/internal_article_check.rb", + "line": 31, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "ticket.articles.where(\"ticket_articles.to #{Rails.application.config.db_like} ?\", \"%#{parse_email(mail[:from_email])}%\")", + "render_path": null, + "location": { + "type": "method", + "class": "Channel::Filter::InternalArticleCheck", + "method": "Channel::Filter::InternalArticleCheck.last_outgoing_mail_is_internal?" + }, + "user_input": "Rails.application.config.db_like", + "confidence": "Weak", + "note": "The db_like config setting is safe to use in an SQL string." + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "381781925211cac1f2592a6537f4abc050f98b081e5554b7d3d70a9454157e35", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/number/increment.rb", + "line": 47, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/(?<=\\W|^)#{Regexp.quote(Setting.get(\"ticket_hook\"))}\\s{0,2}(#{(\"\" or Setting.get(\"system_id\").to_s)}\\d{2,48})\\b/i", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Number::Increment", + "method": "Ticket::Number::Increment.check" + }, + "user_input": "Setting.get(\"system_id\").to_s", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "4ea1b96c11cdde309b0f31defd8af9dc39dd7605a7bb18b13b122469a74a5a70", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/channel/filter/monitoring_base.rb", + "line": 115, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/#{(Setting.get(\"#{integration_name}_ignore_match\") or \"\")}/i", + "render_path": null, + "location": { + "type": "method", + "class": "Channel::Filter::MonitoringBase", + "method": "Channel::Filter::MonitoringBase.run" + }, + "user_input": "Setting.get(\"#{integration_name}_ignore_match\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "55248822583e32826f88a68e27568416fe1f101d83b02791c10296d2393b83a5", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "app/models/store/file.rb", + "line": 32, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "\"Store::Provider::#{(Setting.get(\"storage_provider\") or \"DB\")}\".constantize", + "render_path": null, + "location": { + "type": "method", + "class": "File", + "method": "s(:self).add" + }, + "user_input": "Setting.get(\"storage_provider\")", + "confidence": "Medium", + "note": "Setting.get('storage_provider') returns defined Store::Provider backend class names" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "582df3b442a09879f0c035b50f6c4fce9aa8285c907737476f16004246c67bc6", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `safe_constantize` called with parameter value", + "file": "app/controllers/tests_controller.rb", + "line": 19, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "params.fetch(:exception, \"StandardError\").safe_constantize", + "render_path": null, + "location": { + "type": "method", + "class": "TestsController", + "method": "error_raised_exception" + }, + "user_input": "params.fetch(:exception, \"StandardError\")", + "confidence": "High", + "note": "Only for testing purposes" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "5840449fd32ff0c102ebe4b61132fbb129aae57636bbe407cbb809da7eb5a4ee", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/subject.rb", + "line": 61, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/\\[#{Setting.get(\"ticket_hook\")}: #{number}\\](\\s+?|)/", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Subject", + "method": "subject_clean" + }, + "user_input": "Setting.get(\"ticket_hook\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "73999042c4866cd2effe286fdd6a74c51659bc4a5fc760d1b96d35bd11b2bcda", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "lib/transaction_dispatcher.rb", + "line": 37, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "Setting.get(setting.name).constantize", + "render_path": null, + "location": { + "type": "method", + "class": "TransactionDispatcher", + "method": "s(:self).perform" + }, + "user_input": "Setting.get(setting.name)", + "confidence": "Medium", + "note": "Setting.where(area: 'Transaction::Backend::Sync').order(:name) returns defined Transaction backend class names" + }, + { + "warning_type": "Dangerous Send", + "warning_code": 23, + "fingerprint": "73f7454b7fdc88e0fb9cfc849b74006956a7a031836897a0b61d8d13dde94340", + "check_name": "Send", + "message": "User controlled method execution", + "file": "app/controllers/channels_sms_controller.rb", + "line": 48, + "link": "https://brakemanscanner.org/docs/warning_types/dangerous_send/", + "code": "Channel.driver_class(params[:options][:adapter]).new.send(params[:options], test_options)", + "render_path": null, + "location": { + "type": "method", + "class": "ChannelsSmsController", + "method": "test" + }, + "user_input": "params[:options]", + "confidence": "High", + "note": "Channel#send is a custom implementation" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "7541faf8d3249dc4ac24f9c354024614ae79b0d6cd4c057f034ea88be1154bf7", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "lib/application_lib.rb", + "line": 26, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "Setting.get(setting).constantize", + "render_path": null, + "location": { + "type": "method", + "class": "ApplicationLib::ClassMethods", + "method": "load_adapter_by_setting" + }, + "user_input": "Setting.get(setting)", + "confidence": "Medium", + "note": "ApplicationLib.load_adapter_by_setting works as designed" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "768e035d4bcb32ab79f5f747ccd5561d3c5f3a8ea74b2be08638d892be2249b2", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/number/date.rb", + "line": 49, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/(?<=\\W|^)#{Regexp.quote(Setting.get(\"ticket_hook\"))}\\s{0,2}(\\d{4,10}#{(Setting.get(\"system_id\") or \"\")}\\d{2,40})\\b/i", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Number::Date", + "method": "Ticket::Number::Date.check" + }, + "user_input": "Setting.get(\"system_id\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "SSL Verification Bypass", + "warning_code": 71, + "fingerprint": "7d088914c00f93dddb545ad9e567d59bf89dad493884b550ba72c014c0190011", + "check_name": "SSLVerify", + "message": "SSL certificate verification was bypassed", + "file": "lib/user_agent.rb", + "line": 335, + "link": "https://brakemanscanner.org/docs/warning_types/ssl_verification_bypass/", + "code": "(Net::HTTP.Proxy($1, $2, ((options[\"proxy_username\"] or Setting.get(\"proxy_username\")) or nil), ((options[\"proxy_password\"] or Setting.get(\"proxy_password\")) or nil)).new(uri.host, uri.port) or Net::HTTP.new(uri.host, uri.port)).verify_mode = OpenSSL::SSL::VERIFY_NONE", + "render_path": null, + "location": { + "type": "method", + "class": "UserAgent", + "method": "s(:self).get_http" + }, + "user_input": null, + "confidence": "High", + "note": "SSL Verification can already be requested from callers. The default value should be switched to true at some point." + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "8db3b4731daa1ef96c53729b2fca4cc91b47af058564f61cba24833aacaa55ae", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "app/jobs/transaction_job.rb", + "line": 25, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "Setting.get(setting.name).constantize", + "render_path": null, + "location": { + "type": "method", + "class": "TransactionJob", + "method": "perform" + }, + "user_input": "Setting.get(setting.name)", + "confidence": "Medium", + "note": "Setting.where(area: 'Transaction::Backend::Async').order(:name) returns defined Transaction backend class names" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "949570adfbda072b1fa14632a6d7a0e829a632c699339dce93e1ff109bf79786", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/number/increment.rb", + "line": 41, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/(?<=\\W|^)#{Regexp.quote(Setting.get(\"ticket_hook\"))}#{Regexp.quote(Setting.get(\"ticket_hook_divider\").to_s)}(#{(\"\" or Setting.get(\"system_id\").to_s)}\\d{2,48})\\b/i", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Number::Increment", + "method": "Ticket::Number::Increment.check" + }, + "user_input": "Setting.get(\"system_id\").to_s", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "9bb8bfef12e845cf5264fc09d776c90c4458dee93f69d70689e1caa9a0dd4c8a", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/subject.rb", + "line": 68, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/#{Setting.get(\"ticket_hook\")}#{Setting.get(\"ticket_hook_divider\")}#{number}(\\s+?|)/", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Subject", + "method": "subject_clean" + }, + "user_input": "Setting.get(\"ticket_hook\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "9ec74dbe0ca90264aab31f05df4f0565f53e28477c93ced418e0249913c519fc", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/models/organization/search.rb", + "line": 116, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "Organization.select(\"DISTINCT(organizations.id), #{::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, [\"active\", \"updated_at\"]), ::SqlHelper.new(:object => (self)).get_order_by(params, [\"desc\", \"desc\"]), \"organizations.updated_at\")}\")", + "render_path": null, + "location": { + "type": "method", + "class": "Organization", + "method": "search" + }, + "user_input": "::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, [\"active\", \"updated_at\"]), ::SqlHelper.new(:object => (self)).get_order_by(params, [\"desc\", \"desc\"]), \"organizations.updated_at\")", + "confidence": "Medium", + "note": "SqlHelper does properly escape table and column names." + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "a08cb6cbb584ab6bf0a1c068a0e99336b97bb68d98aa0294cc4e1184f15aaf9a", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/subject.rb", + "line": 66, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/#{Setting.get(\"ticket_hook\")}: #{number}(\\s+?|)/", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Subject", + "method": "subject_clean" + }, + "user_input": "Setting.get(\"ticket_hook\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "a5818edfcce4a3860c36ce71d434d1d4dd91fe3cac9ac945c71e4e2932ffe6cc", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/models/ticket/search.rb", + "line": 203, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "Ticket.select(\"DISTINCT(tickets.id), #{::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")}\")", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Search", + "method": "search" + }, + "user_input": "::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")", + "confidence": "Medium", + "note": "SqlHelper does properly escape table and column names." + }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "a5818edfcce4a3860c36ce71d434d1d4dd91fe3cac9ac945c71e4e2932ffe6cc", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/models/ticket/search.rb", + "line": 212, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "Ticket.select(\"DISTINCT(tickets.id), #{::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")}\")", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Search", + "method": "search" + }, + "user_input": "::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")", + "confidence": "Medium", + "note": "SqlHelper does properly escape table and column names." + }, + { + "warning_type": "Dangerous Send", + "warning_code": 23, + "fingerprint": "b24120f184a097dbf931fd0c251e26b431fc4a0ac679f02ed2c85a9ebb338cc7", + "check_name": "Send", + "message": "User controlled method execution", + "file": "app/controllers/attachments_controller.rb", + "line": 87, + "link": "https://brakemanscanner.org/docs/warning_types/dangerous_send/", + "code": "Store.find(params[:id]).store_object.name.safe_constantize.send(\"can_#{params[:action]}_attachment?\", Store.find(params[:id]), current_user)", + "render_path": null, + "location": { + "type": "method", + "class": "AttachmentsController", + "method": "verify_object_permissions" + }, + "user_input": "params[:action]", + "confidence": "High", + "note": "Save because 'before_action' is limited to defined actions" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "b4e5b1ad22930f849b12cbdf519dced6ec46b6cc653504f0a8e910c0a9590d61", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "app/models/object_manager/attribute.rb", + "line": 806, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "ObjectLookup.by_id(object_lookup_id).constantize", + "render_path": null, + "location": { + "type": "method", + "class": "ObjectManager::Attribute", + "method": "check_name" + }, + "user_input": "ObjectLookup.by_id(object_lookup_id)", + "confidence": "Medium", + "note": "ObjectLookup.by_id works as designed" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "befcb5177e42e1d0c9184b046185ec84c7ecef8fc9b53822d8344f6a6a35860c", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/subject.rb", + "line": 62, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/\\[#{Setting.get(\"ticket_hook\")}:#{number}\\](\\s+?|)/", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Subject", + "method": "subject_clean" + }, + "user_input": "Setting.get(\"ticket_hook\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "SSL Verification Bypass", + "warning_code": 71, + "fingerprint": "cce91e3b231a7971f9f9d2298b8bba7b309610f4b98a88e530cac6fdd8efa1c4", + "check_name": "SSLVerify", + "message": "SSL certificate verification was bypassed", + "file": "app/controllers/integration/exchange_controller.rb", + "line": 17, + "link": "https://brakemanscanner.org/docs/warning_types/ssl_verification_bypass/", + "code": "Autodiscover::Client.new(:email => params[:user], :password => params[:password]).http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE", + "render_path": null, + "location": { + "type": "method", + "class": "Integration::ExchangeController", + "method": "autodiscover" + }, + "user_input": null, + "confidence": "High", + "note": "Only if requester sends `:disable_ssl_verify` param" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "d48809837203098f7be4803f19b4f180f93361030bcf145560c65582d44f8edc", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "app/models/channel/email_parser.rb", + "line": 154, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "Setting.get(setting.name).constantize", + "render_path": null, + "location": { + "type": "method", + "class": "Channel::EmailParser", + "method": "_process" + }, + "user_input": "Setting.get(setting.name)", + "confidence": "Medium", + "note": "Setting.where(area: 'Postmaster::PreFilter').order(:name) returns defined postmaster backend class names" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "d48809837203098f7be4803f19b4f180f93361030bcf145560c65582d44f8edc", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `constantize` called with model attribute", + "file": "app/models/channel/email_parser.rb", + "line": 318, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "Setting.get(setting.name).constantize", + "render_path": null, + "location": { + "type": "method", + "class": "Channel::EmailParser", + "method": "_process" + }, + "user_input": "Setting.get(setting.name)", + "confidence": "Medium", + "note": "Setting.where(area: 'Postmaster::PreFilter').order(:name) returns defined postmaster backend class names" + }, + { + "warning_type": "Remote Code Execution", + "warning_code": 24, + "fingerprint": "e8789f715661836374232aa2ba4aa9eacbba8ea4961f5b26468a0d96c4c91e33", + "check_name": "UnsafeReflection", + "message": "Unsafe reflection method `safe_constantize` called with model attribute", + "file": "app/controllers/attachments_controller.rb", + "line": 86, + "link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/", + "code": "Store.find(params[:id]).store_object.name.safe_constantize", + "render_path": null, + "location": { + "type": "method", + "class": "AttachmentsController", + "method": "verify_object_permissions" + }, + "user_input": "Store.find(params[:id]).store_object", + "confidence": "Medium", + "note": "Store#store_object returns defined Model objects" + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "ea2a3af842a48c9ef4dc8d142abd56978baa4823a598d2a76dc8f840799d6967", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket/number/date.rb", + "line": 44, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/(?<=\\W|^)#{Regexp.quote(Setting.get(\"ticket_hook\"))}#{Regexp.quote((Setting.get(\"ticket_hook_divider\") or \"\"))}(\\d{4,10}#{(Setting.get(\"system_id\") or \"\")}\\d{2,40})\\b/i", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket::Number::Date", + "method": "Ticket::Number::Date.check" + }, + "user_input": "Setting.get(\"system_id\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + }, + { + "warning_type": "Session Setting", + "warning_code": 29, + "fingerprint": "f0ee1cc1980474c82a013645508f002dcc801e00db5592f7dd8cd6bdb93c73fe", + "check_name": "SessionSettings", + "message": "Session secret should not be included in version control", + "file": "config/secrets.yml", + "line": 2, + "link": "https://brakemanscanner.org/docs/warning_types/session_setting/", + "code": null, + "render_path": null, + "location": null, + "user_input": null, + "confidence": "High", + "note": "Since Sessions are stored in the database and not in cookies, the session secret is not used / not relevant.\"" + }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "fcad47a712a324ace0e97560767e5420500df03fd3de3057198800bdea5fd324", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "lib/models.rb", + "line": 171, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "model_class.where(\"#{reflection_value.name}_id\" => object_id)", + "render_path": null, + "location": { + "type": "method", + "class": "Models", + "method": "s(:self).references" + }, + "user_input": "reflection_value.name", + "confidence": "Weak", + "note": "Reflections come from the models themselves and are thus safe to use." + }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "fcad47a712a324ace0e97560767e5420500df03fd3de3057198800bdea5fd324", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "lib/models.rb", + "line": 184, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "model_class.where(\"#{reflection_value.name}_id\" => object_id)", + "render_path": null, + "location": { + "type": "method", + "class": "Models", + "method": "s(:self).references" + }, + "user_input": "reflection_value.name", + "confidence": "Weak", + "note": "Reflections come from the models themselves and are thus safe to use." + }, + { + "warning_type": "Denial of Service", + "warning_code": 76, + "fingerprint": "fe906d9ee6b37c92b7deec029d6a4cca47071006440817e4a50292b2ca956a30", + "check_name": "RegexDoS", + "message": "Model attribute used in regular expression", + "file": "app/models/ticket.rb", + "line": 1612, + "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", + "code": "/#{Setting.get(\"send_no_auto_response_reg_exp\")}/i", + "render_path": null, + "location": { + "type": "method", + "class": "Ticket", + "method": "send_email_notification" + }, + "user_input": "Setting.get(\"send_no_auto_response_reg_exp\")", + "confidence": "Medium", + "note": "Admin configured RegExp" + } + ], + "updated": "2021-07-20 13:22:48 +0200", + "brakeman_version": "5.0.4" +} diff --git a/config/brakeman.yml b/config/brakeman.yml new file mode 100644 index 000000000..530ef878d --- /dev/null +++ b/config/brakeman.yml @@ -0,0 +1,3 @@ +--- +:skip_checks: +- CheckMassAssignment diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb index c1c123d7b..ed5c3fbcd 100644 --- a/config/initializers/cookies_serializer.rb +++ b/config/initializers/cookies_serializer.rb @@ -4,4 +4,6 @@ # Specify a serializer for the signed and encrypted cookie jars. # Valid options are :json, :marshal, and :hybrid. -Rails.application.config.action_dispatch.cookies_serializer = :marshal + +# Since sessions are stored in the database, the serializer is not used / not relevant. +# Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/lib/github/http_client.rb b/lib/github/http_client.rb index cf28ccc7d..dd582384d 100644 --- a/lib/github/http_client.rb +++ b/lib/github/http_client.rb @@ -24,6 +24,7 @@ class GitHub log: { facility: 'GitHub', }, + verify_ssl: true, }, ) diff --git a/lib/gitlab/http_client.rb b/lib/gitlab/http_client.rb index 98e7baf7e..f2a247537 100644 --- a/lib/gitlab/http_client.rb +++ b/lib/gitlab/http_client.rb @@ -24,6 +24,7 @@ class GitLab log: { facility: 'GitLab', }, + verify_ssl: true, }, ) diff --git a/lib/models.rb b/lib/models.rb index 0d4691c36..203ea1b91 100644 --- a/lib/models.rb +++ b/lib/models.rb @@ -145,7 +145,7 @@ returns ref_attributes.each do |item| next if model_attributes[:attributes].exclude?(item) - count = model_class.where("#{item} = ?", object_id).count + count = model_class.where(item => object_id).count next if count.zero? && !include_zero if !references[model_class.to_s][item] @@ -168,7 +168,7 @@ returns next if ref_attributes.include?(col_name) if reflection_value.options[:class_name] == object_name - count = model_class.where("#{col_name} = ?", object_id).count + count = model_class.where(col_name => object_id).count next if count.zero? && !include_zero if !references[model_class.to_s][col_name] @@ -181,7 +181,7 @@ returns next if reflection_value.options[:class_name] next if reflection_value.name != object_name.downcase.to_sym - count = model_class.where("#{col_name} = ?", object_id).count + count = model_class.where(col_name => object_id).count next if count.zero? && !include_zero if !references[model_class.to_s][col_name] @@ -256,7 +256,7 @@ returns items_to_update = {} attributes.each_key do |attribute| Rails.logger.debug { "#{object_name}: #{model}.#{attribute}->#{object_id_to_merge}->#{object_id_primary}" } - model_object.where("#{attribute} = ?", object_id_to_merge).each do |item| + model_object.where(attribute => object_id_to_merge).each do |item| if !items_to_update[item.id] items_to_update[item.id] = item end diff --git a/lib/sequencer/unit/import/freshdesk/conversation/attachments.rb b/lib/sequencer/unit/import/freshdesk/conversation/attachments.rb index 93505a751..2b5fc0338 100644 --- a/lib/sequencer/unit/import/freshdesk/conversation/attachments.rb +++ b/lib/sequencer/unit/import/freshdesk/conversation/attachments.rb @@ -43,6 +43,7 @@ class Sequencer { open_timeout: 20, read_timeout: 240, + verify_ssl: true, }, ) diff --git a/lib/sequencer/unit/import/freshdesk/conversation/inline_images.rb b/lib/sequencer/unit/import/freshdesk/conversation/inline_images.rb index e480e63d9..5cb3a4e1b 100644 --- a/lib/sequencer/unit/import/freshdesk/conversation/inline_images.rb +++ b/lib/sequencer/unit/import/freshdesk/conversation/inline_images.rb @@ -40,6 +40,7 @@ class Sequencer { open_timeout: 20, read_timeout: 240, + verify_ssl: true, }, ) diff --git a/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request.rb b/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request.rb index 81273e3ef..5629f80a4 100644 --- a/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request.rb +++ b/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request.rb @@ -34,6 +34,7 @@ class Sequencer { open_timeout: 20, read_timeout: 240, + verify_ssl: true, }, ) end diff --git a/lib/service/geo_calendar/zammad.rb b/lib/service/geo_calendar/zammad.rb index d0fd35ef6..f111b6a02 100644 --- a/lib/service/geo_calendar/zammad.rb +++ b/lib/service/geo_calendar/zammad.rb @@ -25,6 +25,7 @@ class Service::GeoCalendar::Zammad open_timeout: 2, read_timeout: 4, total_timeout: 12, + verify_ssl: true, }, ) if !response.success? && response.code.to_s !~ %r{^40.$} diff --git a/lib/service/geo_ip/zammad.rb b/lib/service/geo_ip/zammad.rb index 0e36642d4..2c29b5a35 100644 --- a/lib/service/geo_ip/zammad.rb +++ b/lib/service/geo_ip/zammad.rb @@ -23,6 +23,7 @@ class Service::GeoIp::Zammad open_timeout: 2, read_timeout: 4, total_timeout: 4, + verify_ssl: true, }, ) if !response.success? && response.code.to_s !~ %r{^40.$} diff --git a/lib/service/geo_location/gmaps.rb b/lib/service/geo_location/gmaps.rb index 217702ca0..1b487cedc 100644 --- a/lib/service/geo_location/gmaps.rb +++ b/lib/service/geo_location/gmaps.rb @@ -11,6 +11,7 @@ class Service::GeoLocation::Gmaps open_timeout: 2, read_timeout: 4, total_timeout: 4, + verify_ssl: true, }, ) return if !response.success? @@ -36,6 +37,7 @@ class Service::GeoLocation::Gmaps open_timeout: 2, read_timeout: 4, total_timeout: 4, + verify_ssl: true, }, ) return if !response.success? diff --git a/lib/service/image/zammad.rb b/lib/service/image/zammad.rb index 803b9882b..ac9c9d3ce 100644 --- a/lib/service/image/zammad.rb +++ b/lib/service/image/zammad.rb @@ -24,6 +24,7 @@ class Service::Image::Zammad open_timeout: OPEN_TIMEOUT, read_timeout: READ_TIMEOUT, total_timeout: TOTAL_TIMEOUT, + verify_ssl: true, }, ) if !response.success? @@ -57,6 +58,7 @@ class Service::Image::Zammad open_timeout: OPEN_TIMEOUT, read_timeout: READ_TIMEOUT, total_timeout: TOTAL_TIMEOUT, + verify_ssl: true, }, ) if !response.success? diff --git a/lib/telegram.rb b/lib/telegram.rb index c89667b8d..fafaf9add 100644 --- a/lib/telegram.rb +++ b/lib/telegram.rb @@ -795,6 +795,7 @@ returns { open_timeout: 20, read_timeout: 40, + verify_ssl: true, }, ) end diff --git a/lib/twitter_sync.rb b/lib/twitter_sync.rb index b8e3b48b1..0f397eed7 100644 --- a/lib/twitter_sync.rb +++ b/lib/twitter_sync.rb @@ -779,6 +779,7 @@ download public media file from twitter { open_timeout: 20, read_timeout: 40, + verify_ssl: true, }, ) end diff --git a/spec/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request_spec.rb b/spec/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request_spec.rb index 700233b48..6c05ffd6c 100644 --- a/spec/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request_spec.rb +++ b/spec/lib/sequencer/unit/import/zendesk/ticket/comment/attachment/request_spec.rb @@ -18,7 +18,7 @@ RSpec.describe Sequencer::Unit::Import::Zendesk::Ticket::Comment::Attachment::Re it 'open timeout should be 20s and read timeout should be 240s' do allow(response).to receive(:success?).and_return(true) - allow(UserAgent).to receive(:get).with(any_args, { open_timeout: 20, read_timeout: 240 }).and_return(response) + allow(UserAgent).to receive(:get).with(any_args, { open_timeout: 20, read_timeout: 240, verify_ssl: true }).and_return(response) process(mock_parameters) expect(UserAgent).to have_received(:get) end