diff --git a/.rubocop.yml b/.rubocop.yml
index 12c9957b4..bd287aa83 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -781,6 +781,9 @@ Style/RaiseArgs:
Style/RedundantArgument:
Enabled: true
+Style/RedundantBegin:
+ Enabled: true
+
Style/RedundantCondition:
Enabled: true
diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb
index 633668e7a..797ded423 100644
--- a/app/controllers/admin/base_controller.rb
+++ b/app/controllers/admin/base_controller.rb
@@ -1,4 +1,5 @@
class Admin::BaseController < ApplicationController
+ include IpDeniedHandler
layout "admin"
before_action :authenticate_user!
diff --git a/app/controllers/concerns/ip_denied_handler.rb b/app/controllers/concerns/ip_denied_handler.rb
new file mode 100644
index 000000000..3a2e9acd5
--- /dev/null
+++ b/app/controllers/concerns/ip_denied_handler.rb
@@ -0,0 +1,17 @@
+module IpDeniedHandler
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :restrict_ip, unless: :allowed_ip?
+ end
+
+private
+
+ def restrict_ip
+ redirect_to root_path, alert: t("ip_denied_handler.unauthorized")
+ end
+
+ def allowed_ip?
+ RestrictAdminIps.new(request.remote_ip).allowed?
+ end
+end
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 0c64ddfb9..0a13ac349 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -9,25 +9,23 @@ class GraphqlController < ApplicationController
class QueryStringError < StandardError; end
def execute
- begin
- raise GraphqlController::QueryStringError if query_string.nil?
+ raise GraphqlController::QueryStringError if query_string.nil?
- result = ConsulSchema.execute(
- query_string,
- variables: prepare_variables,
- context: {},
- operation_name: params[:operationName]
- )
- render json: result
- rescue GraphqlController::QueryStringError
- render json: { message: "Query string not present" }, status: :bad_request
- rescue JSON::ParserError
- render json: { message: "Error parsing JSON" }, status: :bad_request
- rescue GraphQL::ParseError
- render json: { message: "Query string is not valid JSON" }, status: :bad_request
- rescue ArgumentError => e
- render json: { message: e.message }, status: :bad_request
- end
+ result = ConsulSchema.execute(
+ query_string,
+ variables: prepare_variables,
+ context: {},
+ operation_name: params[:operationName]
+ )
+ render json: result
+ rescue GraphqlController::QueryStringError
+ render json: { message: "Query string not present" }, status: :bad_request
+ rescue JSON::ParserError
+ render json: { message: "Error parsing JSON" }, status: :bad_request
+ rescue GraphQL::ParseError
+ render json: { message: "Query string is not valid JSON" }, status: :bad_request
+ rescue ArgumentError => e
+ render json: { message: e.message }, status: :bad_request
end
private
diff --git a/app/lib/restrict_admin_ips.rb b/app/lib/restrict_admin_ips.rb
new file mode 100644
index 000000000..6c00f8dff
--- /dev/null
+++ b/app/lib/restrict_admin_ips.rb
@@ -0,0 +1,37 @@
+class RestrictAdminIps
+ attr_reader :ip
+
+ def initialize(ip)
+ @ip = ip
+ end
+
+ def allowed?
+ unrestricted_access? || allowed_ip?
+ end
+
+ private
+
+ def unrestricted_access?
+ allowed_ips.blank?
+ end
+
+ def allowed_ips
+ Array(Tenant.current_secrets.dig(:security, :allowed_admin_ips))
+ end
+
+ def allowed_ip?
+ normalized_allowed_ips.any? { |allowed_ip| allowed_ip.include?(ip) }
+ rescue IPAddr::Error
+ false
+ end
+
+ def normalized_allowed_ips
+ allowed_ips.map do |allowed_ip|
+ IPAddr.new(allowed_ip)
+ rescue IPAddr::Error
+ Rails.logger.warn "Your allowed_admin_ips configuration includes the " \
+ "address \"#{allowed_ip}\", which is not valid"
+ nil
+ end.compact
+ end
+end
diff --git a/app/models/legislation/annotation.rb b/app/models/legislation/annotation.rb
index c9fb4d046..b1417a886 100644
--- a/app/models/legislation/annotation.rb
+++ b/app/models/legislation/annotation.rb
@@ -25,23 +25,21 @@ class Legislation::Annotation < ApplicationRecord
end
def store_context
- begin
- html = draft_version.body_html
- doc = Nokogiri::HTML(html)
+ html = draft_version.body_html
+ doc = Nokogiri::HTML(html)
- selector_start = "/html/body/#{range_start}"
- el_start = doc.at_xpath(selector_start)
+ selector_start = "/html/body/#{range_start}"
+ el_start = doc.at_xpath(selector_start)
- selector_end = "/html/body/#{range_end}"
- el_end = doc.at_xpath(selector_end)
+ selector_end = "/html/body/#{range_end}"
+ el_end = doc.at_xpath(selector_end)
- remainder_el_start = el_start.text[0..range_start_offset - 1] unless range_start_offset.zero?
- remainder_el_end = el_end.text[range_end_offset..-1]
+ remainder_el_start = el_start.text[0..range_start_offset - 1] unless range_start_offset.zero?
+ remainder_el_end = el_end.text[range_end_offset..-1]
- self.context = "#{remainder_el_start}#{quote}#{remainder_el_end}"
- rescue
- "#{quote}"
- end
+ self.context = "#{remainder_el_start}#{quote}#{remainder_el_end}"
+ rescue
+ "#{quote}"
end
def create_first_comment
diff --git a/app/models/machine_learning.rb b/app/models/machine_learning.rb
index 5541d3327..34327bd0d 100644
--- a/app/models/machine_learning.rb
+++ b/app/models/machine_learning.rb
@@ -15,57 +15,55 @@ class MachineLearning
end
def run
- begin
- export_proposals_to_json
- export_budget_investments_to_json
- export_comments_to_json
+ export_proposals_to_json
+ export_budget_investments_to_json
+ export_comments_to_json
- return unless run_machine_learning_scripts
+ return unless run_machine_learning_scripts
- if updated_file?(MachineLearning.proposals_taggings_filename) &&
- updated_file?(MachineLearning.proposals_tags_filename)
- cleanup_proposals_tags!
- import_ml_proposals_tags
- update_machine_learning_info_for("tags")
- end
-
- if updated_file?(MachineLearning.investments_taggings_filename) &&
- updated_file?(MachineLearning.investments_tags_filename)
- cleanup_investments_tags!
- import_ml_investments_tags
- update_machine_learning_info_for("tags")
- end
-
- if updated_file?(MachineLearning.proposals_related_filename)
- cleanup_proposals_related_content!
- import_proposals_related_content
- update_machine_learning_info_for("related_content")
- end
-
- if updated_file?(MachineLearning.investments_related_filename)
- cleanup_investments_related_content!
- import_budget_investments_related_content
- update_machine_learning_info_for("related_content")
- end
-
- if updated_file?(MachineLearning.proposals_comments_summary_filename)
- cleanup_proposals_comments_summary!
- import_ml_proposals_comments_summary
- update_machine_learning_info_for("comments_summary")
- end
-
- if updated_file?(MachineLearning.investments_comments_summary_filename)
- cleanup_investments_comments_summary!
- import_ml_investments_comments_summary
- update_machine_learning_info_for("comments_summary")
- end
-
- job.update!(finished_at: Time.current)
- Mailer.machine_learning_success(user).deliver_later
- rescue Exception => e
- handle_error(e)
- raise e
+ if updated_file?(MachineLearning.proposals_taggings_filename) &&
+ updated_file?(MachineLearning.proposals_tags_filename)
+ cleanup_proposals_tags!
+ import_ml_proposals_tags
+ update_machine_learning_info_for("tags")
end
+
+ if updated_file?(MachineLearning.investments_taggings_filename) &&
+ updated_file?(MachineLearning.investments_tags_filename)
+ cleanup_investments_tags!
+ import_ml_investments_tags
+ update_machine_learning_info_for("tags")
+ end
+
+ if updated_file?(MachineLearning.proposals_related_filename)
+ cleanup_proposals_related_content!
+ import_proposals_related_content
+ update_machine_learning_info_for("related_content")
+ end
+
+ if updated_file?(MachineLearning.investments_related_filename)
+ cleanup_investments_related_content!
+ import_budget_investments_related_content
+ update_machine_learning_info_for("related_content")
+ end
+
+ if updated_file?(MachineLearning.proposals_comments_summary_filename)
+ cleanup_proposals_comments_summary!
+ import_ml_proposals_comments_summary
+ update_machine_learning_info_for("comments_summary")
+ end
+
+ if updated_file?(MachineLearning.investments_comments_summary_filename)
+ cleanup_investments_comments_summary!
+ import_ml_investments_comments_summary
+ update_machine_learning_info_for("comments_summary")
+ end
+
+ job.update!(finished_at: Time.current)
+ Mailer.machine_learning_success(user).deliver_later
+ rescue Exception => e
+ handle_error(e)
+ raise e
end
handle_asynchronously :run, queue: "machine_learning"
diff --git a/config/deploy.rb b/config/deploy.rb
index 265dcd95a..84d1e6fcc 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -84,18 +84,16 @@ end
task :install_ruby do
on roles(:app) do
within release_path do
- begin
- current_ruby = capture(:rvm, "current")
- rescue SSHKit::Command::Failed
+ current_ruby = capture(:rvm, "current")
+ rescue SSHKit::Command::Failed
+ after "install_ruby", "rvm1:install:rvm"
+ after "install_ruby", "rvm1:install:ruby"
+ else
+ if current_ruby.include?("not installed")
after "install_ruby", "rvm1:install:rvm"
after "install_ruby", "rvm1:install:ruby"
else
- if current_ruby.include?("not installed")
- after "install_ruby", "rvm1:install:rvm"
- after "install_ruby", "rvm1:install:ruby"
- else
- info "Ruby: Using #{current_ruby}"
- end
+ info "Ruby: Using #{current_ruby}"
end
end
end
@@ -104,19 +102,17 @@ end
task :install_node do
on roles(:app) do
with rails_env: fetch(:rails_env) do
+ execute fetch(:fnm_install_node_command)
+ rescue SSHKit::Command::Failed
begin
- execute fetch(:fnm_install_node_command)
+ execute fetch(:fnm_setup_command)
rescue SSHKit::Command::Failed
- begin
- execute fetch(:fnm_setup_command)
- rescue SSHKit::Command::Failed
- execute fetch(:fnm_install_command)
- else
- execute fetch(:fnm_update_command)
- end
-
- execute fetch(:fnm_install_node_command)
+ execute fetch(:fnm_install_command)
+ else
+ execute fetch(:fnm_update_command)
end
+
+ execute fetch(:fnm_install_node_command)
end
end
end
diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml
index 3137ea334..5168cbd9d 100644
--- a/config/locales/en/general.yml
+++ b/config/locales/en/general.yml
@@ -759,6 +759,8 @@ en:
youtube: "%{org} YouTube"
telegram: "%{org} Telegram"
instagram: "%{org} Instagram"
+ ip_denied_handler:
+ unauthorized: "Access denied. Your IP address is not allowed."
unauthorized:
default: You do not have permission to access this page.
manage:
diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml
index 0e658e9ec..e8bf22da2 100644
--- a/config/locales/es/general.yml
+++ b/config/locales/es/general.yml
@@ -759,6 +759,8 @@ es:
youtube: "YouTube de %{org}"
telegram: "Telegram de %{org}"
instagram: "Instagram de %{org}"
+ ip_denied_handler:
+ unauthorized: "Acceso denegado. Tu IP no tiene permiso para ver este contenido."
unauthorized:
default: No tienes permiso para acceder a esta página.
manage:
diff --git a/config/secrets.yml.example b/config/secrets.yml.example
index b785db667..4f298b089 100644
--- a/config/secrets.yml.example
+++ b/config/secrets.yml.example
@@ -23,6 +23,7 @@ development:
devise_lockable: false
multitenancy: false
security:
+ # allowed_admin_ips: ["123.45.67.89", "192.168.1.0/24"]
last_sign_in: false
password_complexity: false
# lockable:
@@ -64,6 +65,7 @@ staging:
managers_application_key: ""
multitenancy: false
security:
+ # allowed_admin_ips: ["123.45.67.89", "192.168.1.0/24"]
last_sign_in: false
password_complexity: false
# lockable:
@@ -118,6 +120,7 @@ preproduction:
managers_application_key: ""
multitenancy: false
security:
+ # allowed_admin_ips: ["123.45.67.89", "192.168.1.0/24"]
last_sign_in: false
password_complexity: false
# lockable:
@@ -171,6 +174,7 @@ production:
managers_application_key: ""
multitenancy: false
security:
+ # allowed_admin_ips: ["123.45.67.89", "192.168.1.0/24"]
last_sign_in: false
password_complexity: false
# lockable:
diff --git a/spec/components/account/sign_in_info_component_spec.rb b/spec/components/account/sign_in_info_component_spec.rb
index 0e100d2d3..e11d4dd23 100644
--- a/spec/components/account/sign_in_info_component_spec.rb
+++ b/spec/components/account/sign_in_info_component_spec.rb
@@ -5,9 +5,7 @@ describe Account::SignInInfoComponent do
context "Security secret for render last sign in is enabled" do
it "shows a sign in info" do
- allow(Rails.application).to receive(:secrets).and_return(ActiveSupport::OrderedOptions.new.merge(
- security: { last_sign_in: true }
- ))
+ stub_secrets(security: { last_sign_in: true })
render_inline Account::SignInInfoComponent.new(account)
diff --git a/spec/controllers/admin/base_controller_spec.rb b/spec/controllers/admin/base_controller_spec.rb
new file mode 100644
index 000000000..a869c4cc8
--- /dev/null
+++ b/spec/controllers/admin/base_controller_spec.rb
@@ -0,0 +1,31 @@
+require "rails_helper"
+
+describe Admin::BaseController, :admin do
+ controller do
+ def index
+ render plain: "Index"
+ end
+ end
+
+ describe "#restrict_ip" do
+ before do
+ stub_secrets(security: { allowed_admin_ips: ["1.2.3.4", "5.6.7.8"] })
+ end
+
+ it "renders the content when the IP is allowed" do
+ request.env["REMOTE_ADDR"] = "1.2.3.4"
+ get :index
+
+ expect(response).to be_successful
+ expect(response.body).to eq "Index"
+ end
+
+ it "redirects to the root path when the IP isn't allowed" do
+ request.env["REMOTE_ADDR"] = "9.10.11.12"
+ get :index
+
+ expect(response).to redirect_to root_path
+ expect(flash[:alert]).to eq "Access denied. Your IP address is not allowed."
+ end
+ end
+end
diff --git a/spec/controllers/officing/voters_controller_spec.rb b/spec/controllers/officing/voters_controller_spec.rb
index 81c9c6120..e1a611755 100644
--- a/spec/controllers/officing/voters_controller_spec.rb
+++ b/spec/controllers/officing/voters_controller_spec.rb
@@ -11,13 +11,11 @@ describe Officing::VotersController do
2.times.map do
Thread.new do
- begin
- post :create, params: {
- voter: { poll_id: poll.id, user_id: user.id },
- format: :js
- }
- rescue ActionDispatch::IllegalStateError
- end
+ post :create, params: {
+ voter: { poll_id: poll.id, user_id: user.id },
+ format: :js
+ }
+ rescue ActionDispatch::IllegalStateError
end
end.each(&:join)
diff --git a/spec/controllers/polls/answers_controller_spec.rb b/spec/controllers/polls/answers_controller_spec.rb
index 08f129c0b..171fc1cc8 100644
--- a/spec/controllers/polls/answers_controller_spec.rb
+++ b/spec/controllers/polls/answers_controller_spec.rb
@@ -8,14 +8,12 @@ describe Polls::AnswersController do
2.times.map do
Thread.new do
- begin
- post :create, params: {
- question_id: question.id,
- option_id: question.question_options.find_by(title: "Answer A").id,
- format: :js
- }
- rescue ActionDispatch::IllegalStateError, ActiveRecord::RecordInvalid
- end
+ post :create, params: {
+ question_id: question.id,
+ option_id: question.question_options.find_by(title: "Answer A").id,
+ format: :js
+ }
+ rescue ActionDispatch::IllegalStateError, ActiveRecord::RecordInvalid
end
end.each(&:join)
diff --git a/spec/lib/restrict_admin_ips_spec.rb b/spec/lib/restrict_admin_ips_spec.rb
new file mode 100644
index 000000000..e8f6a2f9d
--- /dev/null
+++ b/spec/lib/restrict_admin_ips_spec.rb
@@ -0,0 +1,81 @@
+require "rails_helper"
+
+describe RestrictAdminIps do
+ it "allows any IP when allowed_admin_ips isn't configured" do
+ stub_secrets(security: {})
+
+ expect(RestrictAdminIps.new("1.2.3.4")).to be_allowed
+ expect(RestrictAdminIps.new("whatever")).to be_allowed
+ end
+
+ it "allows any IP when allowed_admin_ips is empty" do
+ stub_secrets(security: { allowed_admin_ips: [] })
+
+ expect(RestrictAdminIps.new("1.2.3.4")).to be_allowed
+ expect(RestrictAdminIps.new("whatever")).to be_allowed
+ end
+
+ it "only allows IPs present in allowed_admin_ips" do
+ stub_secrets(security: { allowed_admin_ips: ["1.2.3.4", "5.6.7.8"] })
+
+ expect(RestrictAdminIps.new("1.2.3.4")).to be_allowed
+ expect(RestrictAdminIps.new("5.6.7.8")).to be_allowed
+ expect(RestrictAdminIps.new("9.9.9.9")).not_to be_allowed
+ expect(RestrictAdminIps.new("whatever")).not_to be_allowed
+ end
+
+ it "restricts every IP when there are only malformed IPs on the list" do
+ stub_secrets(security: { allowed_admin_ips: ["not_an_ip"] })
+
+ expect(RestrictAdminIps.new("1.2.3.4")).not_to be_allowed
+ expect(RestrictAdminIps.new("not_an_ip")).not_to be_allowed
+ end
+
+ it "ignores malformed IPs in the allowed_admin_ips list" do
+ stub_secrets(security: { allowed_admin_ips: ["1.2.3.4", "not_an_ip"] })
+
+ expect(RestrictAdminIps.new("1.2.3.4")).to be_allowed
+ expect(RestrictAdminIps.new("not_an_ip")).not_to be_allowed
+ end
+
+ it "supports ranges of IPs" do
+ stub_secrets(security: { allowed_admin_ips: ["1.2.3.0/16"] })
+
+ expect(RestrictAdminIps.new("1.2.3.4")).to be_allowed
+ expect(RestrictAdminIps.new("1.2.3.5")).to be_allowed
+ expect(RestrictAdminIps.new("5.6.7.8")).not_to be_allowed
+ end
+
+ context "tenant overwriting secrets" do
+ before do
+ stub_secrets({
+ security: {
+ allowed_admin_ips: ["1.2.3.4", "5.6.7.8"]
+ },
+ tenants: {
+ private: {
+ security: {
+ allowed_admin_ips: ["127.0.0.1", "192.168.1.1"]
+ }
+ }
+ }
+ })
+ end
+
+ it "uses the general secrets for the main tenant" do
+ expect(RestrictAdminIps.new("1.2.3.4")).to be_allowed
+ expect(RestrictAdminIps.new("5.6.7.8")).to be_allowed
+ expect(RestrictAdminIps.new("127.0.0.1")).not_to be_allowed
+ expect(RestrictAdminIps.new("192.168.1.1")).not_to be_allowed
+ end
+
+ it "uses the tenant secrets for a tenant" do
+ allow(Tenant).to receive(:current_schema).and_return("private")
+
+ expect(RestrictAdminIps.new("127.0.0.1")).to be_allowed
+ expect(RestrictAdminIps.new("192.168.1.1")).to be_allowed
+ expect(RestrictAdminIps.new("1.2.3.4")).not_to be_allowed
+ expect(RestrictAdminIps.new("5.6.7.8")).not_to be_allowed
+ end
+ end
+end
diff --git a/spec/mailers/mailer_spec.rb b/spec/mailers/mailer_spec.rb
index aed829ae2..4f93ef388 100644
--- a/spec/mailers/mailer_spec.rb
+++ b/spec/mailers/mailer_spec.rb
@@ -85,12 +85,12 @@ describe Mailer do
let(:super_settings) { { address: "super.consul.dev", username: "super" } }
before do
- allow(Rails.application).to receive(:secrets).and_return(ActiveSupport::OrderedOptions.new.merge(
+ stub_secrets(
smtp_settings: default_settings,
tenants: {
supermailer: { smtp_settings: super_settings }
}
- ))
+ )
end
it "does not overwrite the settings for the default tenant" do
diff --git a/spec/models/poll/answer_spec.rb b/spec/models/poll/answer_spec.rb
index b06ccbcd7..4f3ca154e 100644
--- a/spec/models/poll/answer_spec.rb
+++ b/spec/models/poll/answer_spec.rb
@@ -187,10 +187,8 @@ describe Poll::Answer do
[answer, other_answer].map do |poll_answer|
Thread.new do
- begin
- poll_answer.save_and_record_voter_participation
- rescue ActiveRecord::RecordInvalid
- end
+ poll_answer.save_and_record_voter_participation
+ rescue ActiveRecord::RecordInvalid
end
end.each(&:join)
diff --git a/spec/models/tenant_spec.rb b/spec/models/tenant_spec.rb
index e7244c226..f3746f0e7 100644
--- a/spec/models/tenant_spec.rb
+++ b/spec/models/tenant_spec.rb
@@ -243,10 +243,7 @@ describe Tenant do
describe ".current_secrets" do
context "same secrets for all tenants" do
before do
- allow(Rails.application).to receive(:secrets).and_return(ActiveSupport::OrderedOptions.new.merge(
- star: "Sun",
- volume: "Medium"
- ))
+ stub_secrets(star: "Sun", volume: "Medium")
end
it "returns the default secrets for the default tenant" do
@@ -266,11 +263,11 @@ describe Tenant do
context "tenant overwriting secrets" do
before do
- allow(Rails.application).to receive(:secrets).and_return(ActiveSupport::OrderedOptions.new.merge(
+ stub_secrets(
star: "Sun",
volume: "Medium",
tenants: { proxima: { star: "Alpha Centauri" }}
- ))
+ )
end
it "returns the default secrets for the default tenant" do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index b29c9a589..c8d6777c3 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -994,7 +994,7 @@ describe User do
context "when secrets are configured" do
before do
- allow(Rails.application).to receive(:secrets).and_return(ActiveSupport::OrderedOptions.new.merge(
+ stub_secrets(
security: {
password_complexity: true
},
@@ -1005,7 +1005,7 @@ describe User do
}
}
}
- ))
+ )
end
it "uses the general secrets for the main tenant" do
@@ -1027,7 +1027,7 @@ describe User do
context "when secrets are configured" do
before do
- allow(Rails.application).to receive(:secrets).and_return(ActiveSupport::OrderedOptions.new.merge(
+ stub_secrets(
security: {
lockable: { maximum_attempts: "14" }
},
@@ -1038,7 +1038,7 @@ describe User do
}
}
}
- ))
+ )
end
it "uses the general secrets for the main tenant" do
@@ -1060,7 +1060,7 @@ describe User do
context "when secrets are configured" do
before do
- allow(Rails.application).to receive(:secrets).and_return(ActiveSupport::OrderedOptions.new.merge(
+ stub_secrets(
security: {
lockable: { unlock_in: "2" }
},
@@ -1071,7 +1071,7 @@ describe User do
}
}
}
- ))
+ )
end
it "uses the general secrets for the main tenant" do
diff --git a/spec/support/common_actions.rb b/spec/support/common_actions.rb
index 355ce41da..22910a166 100644
--- a/spec/support/common_actions.rb
+++ b/spec/support/common_actions.rb
@@ -14,6 +14,7 @@ module CommonActions
include Polls
include Proposals
include RemoteCensusMock
+ include Secrets
include Tags
include Translations
include Users
diff --git a/spec/support/common_actions/graphql_api.rb b/spec/support/common_actions/graphql_api.rb
index 6deceb138..452433f87 100644
--- a/spec/support/common_actions/graphql_api.rb
+++ b/spec/support/common_actions/graphql_api.rb
@@ -18,14 +18,12 @@ module GraphQLAPI
def extract_fields(response, collection_name, field_chain)
fields = field_chain.split(".")
dig(response, "data.#{collection_name}.edges").map do |node|
- begin
- if fields.size > 1
- node["node"][fields.first][fields.second]
- else
- node["node"][fields.first]
- end
- rescue NoMethodError
+ if fields.size > 1
+ node["node"][fields.first][fields.second]
+ else
+ node["node"][fields.first]
end
+ rescue NoMethodError
end.compact
end
end
diff --git a/spec/support/common_actions/secrets.rb b/spec/support/common_actions/secrets.rb
new file mode 100644
index 000000000..4af9585f4
--- /dev/null
+++ b/spec/support/common_actions/secrets.rb
@@ -0,0 +1,7 @@
+module Secrets
+ def stub_secrets(configuration)
+ allow(Rails.application).to receive(:secrets).and_return(
+ ActiveSupport::OrderedOptions.new.merge(configuration)
+ )
+ end
+end
diff --git a/spec/system/users_auth_spec.rb b/spec/system/users_auth_spec.rb
index 936b035cd..5c7d35953 100644
--- a/spec/system/users_auth_spec.rb
+++ b/spec/system/users_auth_spec.rb
@@ -661,9 +661,7 @@ describe "Users" do
context "Regular authentication with password complexity enabled" do
before do
- allow(Rails.application).to receive(:secrets).and_return(ActiveSupport::OrderedOptions.new.merge(
- security: { password_complexity: true }
- ))
+ stub_secrets(security: { password_complexity: true })
end
context "Sign up" do