Commit 71b98566 authored by Ash McKenzie's avatar Ash McKenzie

Merge branch...

Merge branch '243555-update-whitelist-blacklist-to-allowlist-denylist-in-signup-restrictions-window' into 'master'

Use allowlist/denylist in Signup restrictions window

See merge request gitlab-org/gitlab!46168
parents 9f4e2c15 cf3844af
import $ from 'jquery'; import $ from 'jquery';
import { refreshCurrentPage } from '../../lib/utils/url_utility'; import { refreshCurrentPage } from '../../lib/utils/url_utility';
function showBlacklistType() { function showDenylistType() {
if ($('input[name="blacklist_type"]:checked').val() === 'file') { if ($('input[name="denylist_type"]:checked').val() === 'file') {
$('.blacklist-file').show(); $('.js-denylist-file').show();
$('.blacklist-raw').hide(); $('.js-denylist-raw').hide();
} else { } else {
$('.blacklist-file').hide(); $('.js-denylist-file').hide();
$('.blacklist-raw').show(); $('.js-denylist-raw').show();
} }
} }
...@@ -60,6 +60,6 @@ export default function adminInit() { ...@@ -60,6 +60,6 @@ export default function adminInit() {
$('li.project_member, li.group_member').on('ajax:success', refreshCurrentPage); $('li.project_member, li.group_member').on('ajax:success', refreshCurrentPage);
$("input[name='blacklist_type']").on('click', showBlacklistType); $("input[name='denylist_type']").on('click', showDenylistType);
showBlacklistType(); showDenylistType();
} }
...@@ -216,10 +216,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -216,10 +216,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
remove_blank_params_for!(:elasticsearch_aws_secret_access_key, :eks_secret_access_key) remove_blank_params_for!(:elasticsearch_aws_secret_access_key, :eks_secret_access_key)
# TODO Remove domain_blacklist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-foss/issues/67204) # TODO Remove domain_denylist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-foss/issues/67204)
params.delete(:domain_blacklist_raw) if params[:domain_blacklist_file] params.delete(:domain_denylist_raw) if params[:domain_denylist_file]
params.delete(:domain_blacklist_raw) if params[:domain_blacklist] params.delete(:domain_denylist_raw) if params[:domain_blacklist]
params.delete(:domain_whitelist_raw) if params[:domain_whitelist] params.delete(:domain_allowlist_raw) if params[:domain_whitelist]
params.require(:application_setting).permit( params.require(:application_setting).permit(
visible_application_setting_attributes visible_application_setting_attributes
...@@ -240,7 +240,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -240,7 +240,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
*ApplicationSetting.repository_storages_weighted_attributes, *ApplicationSetting.repository_storages_weighted_attributes,
:lets_encrypt_notification_email, :lets_encrypt_notification_email,
:lets_encrypt_terms_of_service_accepted, :lets_encrypt_terms_of_service_accepted,
:domain_blacklist_file, :domain_denylist_file,
:raw_blob_request_limit, :raw_blob_request_limit,
:issues_create_limit, :issues_create_limit,
:default_branch_name, :default_branch_name,
......
...@@ -201,12 +201,12 @@ module ApplicationSettingsHelper ...@@ -201,12 +201,12 @@ module ApplicationSettingsHelper
:disabled_oauth_sign_in_sources, :disabled_oauth_sign_in_sources,
:domain_blacklist, :domain_blacklist,
:domain_blacklist_enabled, :domain_blacklist_enabled,
# TODO Remove domain_blacklist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-foss/issues/67204) # TODO Remove domain_denylist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-foss/issues/67204)
:domain_blacklist_raw, :domain_denylist_raw,
:domain_whitelist, :domain_whitelist,
# TODO Remove domain_whitelist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-foss/issues/67204) # TODO Remove domain_allowlist_raw in APIv5 (See https://gitlab.com/gitlab-org/gitlab-foss/issues/67204)
:domain_whitelist_raw, :domain_allowlist_raw,
:outbound_local_requests_whitelist_raw, :outbound_local_requests_allowlist_raw,
:dsa_key_restriction, :dsa_key_restriction,
:ecdsa_key_restriction, :ecdsa_key_restriction,
:ed25519_key_restriction, :ed25519_key_restriction,
......
...@@ -202,38 +202,38 @@ module ApplicationSettingImplementation ...@@ -202,38 +202,38 @@ module ApplicationSettingImplementation
super(sources) super(sources)
end end
def domain_whitelist_raw def domain_allowlist_raw
array_to_string(self.domain_whitelist) array_to_string(self.domain_whitelist)
end end
def domain_blacklist_raw def domain_denylist_raw
array_to_string(self.domain_blacklist) array_to_string(self.domain_blacklist)
end end
def domain_whitelist_raw=(values) def domain_allowlist_raw=(values)
self.domain_whitelist = strings_to_array(values) self.domain_whitelist = strings_to_array(values)
end end
def domain_blacklist_raw=(values) def domain_denylist_raw=(values)
self.domain_blacklist = strings_to_array(values) self.domain_blacklist = strings_to_array(values)
end end
def domain_blacklist_file=(file) def domain_denylist_file=(file)
self.domain_blacklist_raw = file.read self.domain_denylist_raw = file.read
end end
def outbound_local_requests_whitelist_raw def outbound_local_requests_allowlist_raw
array_to_string(self.outbound_local_requests_whitelist) array_to_string(self.outbound_local_requests_whitelist)
end end
def outbound_local_requests_whitelist_raw=(values) def outbound_local_requests_allowlist_raw=(values)
clear_memoization(:outbound_local_requests_whitelist_arrays) clear_memoization(:outbound_local_requests_allowlist_arrays)
self.outbound_local_requests_whitelist = strings_to_array(values) self.outbound_local_requests_whitelist = strings_to_array(values)
end end
def add_to_outbound_local_requests_whitelist(values_array) def add_to_outbound_local_requests_whitelist(values_array)
clear_memoization(:outbound_local_requests_whitelist_arrays) clear_memoization(:outbound_local_requests_allowlist_arrays)
self.outbound_local_requests_whitelist ||= [] self.outbound_local_requests_whitelist ||= []
self.outbound_local_requests_whitelist += values_array self.outbound_local_requests_whitelist += values_array
...@@ -242,16 +242,16 @@ module ApplicationSettingImplementation ...@@ -242,16 +242,16 @@ module ApplicationSettingImplementation
end end
# This method separates out the strings stored in the # This method separates out the strings stored in the
# application_setting.outbound_local_requests_whitelist array into 2 arrays; # application_setting.outbound_local_requests_allowlist array into 2 arrays;
# an array of IPAddr objects (`[IPAddr.new('127.0.0.1')]`), and an array of # an array of IPAddr objects (`[IPAddr.new('127.0.0.1')]`), and an array of
# domain strings (`['www.example.com']`). # domain strings (`['www.example.com']`).
def outbound_local_requests_whitelist_arrays def outbound_local_requests_allowlist_arrays
strong_memoize(:outbound_local_requests_whitelist_arrays) do strong_memoize(:outbound_local_requests_allowlist_arrays) do
next [[], []] unless self.outbound_local_requests_whitelist next [[], []] unless self.outbound_local_requests_whitelist
ip_whitelist, domain_whitelist = separate_whitelists(self.outbound_local_requests_whitelist) ip_allowlist, domain_allowlist = separate_allowlists(self.outbound_local_requests_whitelist)
[ip_whitelist, domain_whitelist] [ip_allowlist, domain_allowlist]
end end
end end
...@@ -396,19 +396,19 @@ module ApplicationSettingImplementation ...@@ -396,19 +396,19 @@ module ApplicationSettingImplementation
private private
def separate_whitelists(string_array) def separate_allowlists(string_array)
string_array.reduce([[], []]) do |(ip_whitelist, domain_whitelist), string| string_array.reduce([[], []]) do |(ip_allowlist, domain_allowlist), string|
address, port = parse_addr_and_port(string) address, port = parse_addr_and_port(string)
ip_obj = Gitlab::Utils.string_to_ip_object(address) ip_obj = Gitlab::Utils.string_to_ip_object(address)
if ip_obj if ip_obj
ip_whitelist << Gitlab::UrlBlockers::IpWhitelistEntry.new(ip_obj, port: port) ip_allowlist << Gitlab::UrlBlockers::IpAllowlistEntry.new(ip_obj, port: port)
else else
domain_whitelist << Gitlab::UrlBlockers::DomainWhitelistEntry.new(address, port: port) domain_allowlist << Gitlab::UrlBlockers::DomainAllowlistEntry.new(address, port: port)
end end
[ip_whitelist, domain_whitelist] [ip_allowlist, domain_allowlist]
end end
end end
......
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
= _('Allow requests to the local network from system hooks') = _('Allow requests to the local network from system hooks')
.form-group .form-group
= f.label :outbound_local_requests_whitelist_raw, class: 'label-bold' do = f.label :outbound_local_requests_allowlist_raw, class: 'label-bold' do
= _('Local IP addresses and domain names that hooks and services may access.') = _('Local IP addresses and domain names that hooks and services may access.')
= f.text_area :outbound_local_requests_whitelist_raw, placeholder: "example.com, 192.168.1.1", class: 'form-control', rows: 8 = f.text_area :outbound_local_requests_allowlist_raw, placeholder: "example.com, 192.168.1.1", class: 'form-control', rows: 8
%span.form-text.text-muted %span.form-text.text-muted
= _('Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com.') = _('Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com.')
......
...@@ -28,33 +28,33 @@ ...@@ -28,33 +28,33 @@
.form-text.text-muted .form-text.text-muted
= _("See GitLab's %{password_policy_guidelines}").html_safe % { password_policy_guidelines: password_policy_guidelines_link } = _("See GitLab's %{password_policy_guidelines}").html_safe % { password_policy_guidelines: password_policy_guidelines_link }
.form-group .form-group
= f.label :domain_whitelist, 'Whitelisted domains for sign-ups', class: 'label-bold' = f.label :domain_whitelist, _('Allowed domains for sign-ups'), class: 'label-bold'
= f.text_area :domain_whitelist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8 = f.text_area :domain_allowlist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
.form-text.text-muted ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com .form-text.text-muted ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group .form-group
= f.label :domain_blacklist_enabled, 'Domain Blacklist', class: 'label-bold' = f.label :domain_blacklist_enabled, _('Domain denylist'), class: 'label-bold'
.form-check .form-check
= f.check_box :domain_blacklist_enabled, class: 'form-check-input' = f.check_box :domain_blacklist_enabled, class: 'form-check-input'
= f.label :domain_blacklist_enabled, class: 'form-check-label' do = f.label :domain_blacklist_enabled, class: 'form-check-label' do
Enable domain blacklist for sign ups Enable domain denylist for sign ups
.form-group .form-group
.form-check .form-check
= radio_button_tag :blacklist_type, :file, false, class: 'form-check-input' = radio_button_tag :denylist_type, :file, false, class: 'form-check-input'
= label_tag :blacklist_type_file, class: 'form-check-label' do = label_tag :denylist_type_file, class: 'form-check-label' do
.option-title .option-title
Upload blacklist file Upload denylist file
.form-check .form-check
= radio_button_tag :blacklist_type, :raw, @application_setting.domain_blacklist.present? || @application_setting.domain_blacklist.blank?, class: 'form-check-input' = radio_button_tag :denylist_type, :raw, @application_setting.domain_blacklist.present? || @application_setting.domain_blacklist.blank?, class: 'form-check-input'
= label_tag :blacklist_type_raw, class: 'form-check-label' do = label_tag :denylist_type_raw, class: 'form-check-label' do
.option-title .option-title
Enter blacklist manually Enter denylist manually
.form-group.blacklist-file .form-group.js-denylist-file
= f.label :domain_blacklist_file, 'Blacklist file', class: 'label-bold' = f.label :domain_denylist_file, _('Denylist file'), class: 'label-bold'
= f.file_field :domain_blacklist_file, class: 'form-control', accept: '.txt,.conf' = f.file_field :domain_denylist_file, class: 'form-control', accept: '.txt,.conf'
.form-text.text-muted Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines or commas for multiple entries. .form-text.text-muted Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines or commas for multiple entries.
.form-group.blacklist-raw .form-group.js-denylist-raw
= f.label :domain_blacklist, 'Blacklisted domains for sign-ups', class: 'label-bold' = f.label :domain_blacklist, _('Denied domains for sign-ups'), class: 'label-bold'
= f.text_area :domain_blacklist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8 = f.text_area :domain_denylist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
.form-text.text-muted Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com .form-text.text-muted Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group .form-group
= f.label :email_restrictions_enabled, _('Email restrictions'), class: 'label-bold' = f.label :email_restrictions_enabled, _('Email restrictions'), class: 'label-bold'
......
---
title: Update whitelist/blacklist to allowlist/denylist in Signup restrictions window
merge_request: 46168
author:
type: changed
...@@ -49,7 +49,7 @@ module Gitlab ...@@ -49,7 +49,7 @@ module Gitlab
return [uri, nil] unless address_info return [uri, nil] unless address_info
ip_address = ip_address(address_info) ip_address = ip_address(address_info)
return [uri, nil] if domain_whitelisted?(uri) || ip_whitelisted?(ip_address, port: get_port(uri)) return [uri, nil] if domain_allowed?(uri) || ip_allowed?(ip_address, port: get_port(uri))
protected_uri_with_hostname = enforce_uri_hostname(ip_address, uri, dns_rebind_protection) protected_uri_with_hostname = enforce_uri_hostname(ip_address, uri, dns_rebind_protection)
...@@ -114,7 +114,7 @@ module Gitlab ...@@ -114,7 +114,7 @@ module Gitlab
rescue SocketError rescue SocketError
# If the dns rebinding protection is not enabled or the domain # If the dns rebinding protection is not enabled or the domain
# is whitelisted we avoid the dns rebinding checks # is whitelisted we avoid the dns rebinding checks
return if domain_whitelisted?(uri) || !dns_rebind_protection return if domain_allowed?(uri) || !dns_rebind_protection
# In the test suite we use a lot of mocked urls that are either invalid or # In the test suite we use a lot of mocked urls that are either invalid or
# don't exist. In order to avoid modifying a ton of tests and factories # don't exist. In order to avoid modifying a ton of tests and factories
...@@ -253,12 +253,12 @@ module Gitlab ...@@ -253,12 +253,12 @@ module Gitlab
(uri.port.blank? || uri.port == config.gitlab_shell.ssh_port) (uri.port.blank? || uri.port == config.gitlab_shell.ssh_port)
end end
def domain_whitelisted?(uri) def domain_allowed?(uri)
Gitlab::UrlBlockers::UrlWhitelist.domain_whitelisted?(uri.normalized_host, port: get_port(uri)) Gitlab::UrlBlockers::UrlAllowlist.domain_allowed?(uri.normalized_host, port: get_port(uri))
end end
def ip_whitelisted?(ip_address, port: nil) def ip_allowed?(ip_address, port: nil)
Gitlab::UrlBlockers::UrlWhitelist.ip_whitelisted?(ip_address, port: port) Gitlab::UrlBlockers::UrlAllowlist.ip_allowed?(ip_address, port: port)
end end
def config def config
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Gitlab module Gitlab
module UrlBlockers module UrlBlockers
class DomainWhitelistEntry class DomainAllowlistEntry
attr_reader :domain, :port attr_reader :domain, :port
def initialize(domain, port: nil) def initialize(domain, port: nil)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Gitlab module Gitlab
module UrlBlockers module UrlBlockers
class IpWhitelistEntry class IpAllowlistEntry
attr_reader :ip, :port attr_reader :ip, :port
# Argument ip should be an IPAddr object # Argument ip should be an IPAddr object
......
...@@ -2,43 +2,41 @@ ...@@ -2,43 +2,41 @@
module Gitlab module Gitlab
module UrlBlockers module UrlBlockers
class UrlWhitelist class UrlAllowlist
class << self class << self
def ip_whitelisted?(ip_string, port: nil) def ip_allowed?(ip_string, port: nil)
return false if ip_string.blank? return false if ip_string.blank?
ip_whitelist, _ = outbound_local_requests_whitelist_arrays ip_allowlist, _ = outbound_local_requests_allowlist_arrays
ip_obj = Gitlab::Utils.string_to_ip_object(ip_string) ip_obj = Gitlab::Utils.string_to_ip_object(ip_string)
ip_whitelist.any? do |ip_whitelist_entry| ip_allowlist.any? do |ip_allowlist_entry|
ip_whitelist_entry.match?(ip_obj, port) ip_allowlist_entry.match?(ip_obj, port)
end end
end end
def domain_whitelisted?(domain_string, port: nil) def domain_allowed?(domain_string, port: nil)
return false if domain_string.blank? return false if domain_string.blank?
_, domain_whitelist = outbound_local_requests_whitelist_arrays _, domain_allowlist = outbound_local_requests_allowlist_arrays
domain_whitelist.any? do |domain_whitelist_entry| domain_allowlist.any? do |domain_allowlist_entry|
domain_whitelist_entry.match?(domain_string, port) domain_allowlist_entry.match?(domain_string, port)
end end
end end
private private
attr_reader :ip_whitelist, :domain_whitelist
# We cannot use Gitlab::CurrentSettings as ApplicationSetting itself # We cannot use Gitlab::CurrentSettings as ApplicationSetting itself
# calls this class. This ends up in a cycle where # calls this class. This ends up in a cycle where
# Gitlab::CurrentSettings creates an ApplicationSetting which then # Gitlab::CurrentSettings creates an ApplicationSetting which then
# calls this method. # calls this method.
# #
# See https://gitlab.com/gitlab-org/gitlab/issues/9833 # See https://gitlab.com/gitlab-org/gitlab/issues/9833
def outbound_local_requests_whitelist_arrays def outbound_local_requests_allowlist_arrays
return [[], []] unless ApplicationSetting.current return [[], []] unless ApplicationSetting.current
ApplicationSetting.current.outbound_local_requests_whitelist_arrays ApplicationSetting.current.outbound_local_requests_allowlist_arrays
end end
end end
end end
......
...@@ -2753,6 +2753,9 @@ msgstr "" ...@@ -2753,6 +2753,9 @@ msgstr ""
msgid "Allowed Geo IP" msgid "Allowed Geo IP"
msgstr "" msgstr ""
msgid "Allowed domains for sign-ups"
msgstr ""
msgid "Allowed email domain restriction only permitted for top-level groups" msgid "Allowed email domain restriction only permitted for top-level groups"
msgstr "" msgstr ""
...@@ -8698,12 +8701,18 @@ msgstr "" ...@@ -8698,12 +8701,18 @@ msgstr ""
msgid "Denied authorization of chat nickname %{user_name}." msgid "Denied authorization of chat nickname %{user_name}."
msgstr "" msgstr ""
msgid "Denied domains for sign-ups"
msgstr ""
msgid "Deny" msgid "Deny"
msgstr "" msgstr ""
msgid "Deny access request" msgid "Deny access request"
msgstr "" msgstr ""
msgid "Denylist file"
msgstr ""
msgid "Dependencies" msgid "Dependencies"
msgstr "" msgstr ""
...@@ -9462,6 +9471,9 @@ msgstr "" ...@@ -9462,6 +9471,9 @@ msgstr ""
msgid "Domain cannot be deleted while associated to one or more clusters." msgid "Domain cannot be deleted while associated to one or more clusters."
msgstr "" msgstr ""
msgid "Domain denylist"
msgstr ""
msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled" msgid "Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled"
msgstr "" msgstr ""
......
...@@ -2,57 +2,57 @@ ...@@ -2,57 +2,57 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::UrlBlockers::DomainWhitelistEntry do RSpec.describe Gitlab::UrlBlockers::DomainAllowlistEntry do
let(:domain) { 'www.example.com' } let(:domain) { 'www.example.com' }
describe '#initialize' do describe '#initialize' do
it 'initializes without port' do it 'initializes without port' do
domain_whitelist_entry = described_class.new(domain) domain_allowlist_entry = described_class.new(domain)
expect(domain_whitelist_entry.domain).to eq(domain) expect(domain_allowlist_entry.domain).to eq(domain)
expect(domain_whitelist_entry.port).to be(nil) expect(domain_allowlist_entry.port).to be(nil)
end end
it 'initializes with port' do it 'initializes with port' do
port = 8080 port = 8080
domain_whitelist_entry = described_class.new(domain, port: port) domain_allowlist_entry = described_class.new(domain, port: port)
expect(domain_whitelist_entry.domain).to eq(domain) expect(domain_allowlist_entry.domain).to eq(domain)
expect(domain_whitelist_entry.port).to eq(port) expect(domain_allowlist_entry.port).to eq(port)
end end
end end
describe '#match?' do describe '#match?' do
it 'matches when domain and port are equal' do it 'matches when domain and port are equal' do
port = 8080 port = 8080
domain_whitelist_entry = described_class.new(domain, port: port) domain_allowlist_entry = described_class.new(domain, port: port)
expect(domain_whitelist_entry).to be_match(domain, port) expect(domain_allowlist_entry).to be_match(domain, port)
end end
it 'matches any port when port is nil' do it 'matches any port when port is nil' do
domain_whitelist_entry = described_class.new(domain) domain_allowlist_entry = described_class.new(domain)
expect(domain_whitelist_entry).to be_match(domain, 8080) expect(domain_allowlist_entry).to be_match(domain, 8080)
expect(domain_whitelist_entry).to be_match(domain, 9090) expect(domain_allowlist_entry).to be_match(domain, 9090)
end end
it 'does not match when port is present but requested_port is nil' do it 'does not match when port is present but requested_port is nil' do
domain_whitelist_entry = described_class.new(domain, port: 8080) domain_allowlist_entry = described_class.new(domain, port: 8080)
expect(domain_whitelist_entry).not_to be_match(domain, nil) expect(domain_allowlist_entry).not_to be_match(domain, nil)
end end
it 'matches when port and requested_port are nil' do it 'matches when port and requested_port are nil' do
domain_whitelist_entry = described_class.new(domain) domain_allowlist_entry = described_class.new(domain)
expect(domain_whitelist_entry).to be_match(domain) expect(domain_allowlist_entry).to be_match(domain)
end end
it 'does not match if domain is not equal' do it 'does not match if domain is not equal' do
domain_whitelist_entry = described_class.new(domain) domain_allowlist_entry = described_class.new(domain)
expect(domain_whitelist_entry).not_to be_match('www.gitlab.com', 8080) expect(domain_allowlist_entry).not_to be_match('www.gitlab.com', 8080)
end end
end end
end end
...@@ -2,74 +2,74 @@ ...@@ -2,74 +2,74 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::UrlBlockers::IpWhitelistEntry do RSpec.describe Gitlab::UrlBlockers::IpAllowlistEntry do
let(:ipv4) { IPAddr.new('192.168.1.1') } let(:ipv4) { IPAddr.new('192.168.1.1') }
describe '#initialize' do describe '#initialize' do
it 'initializes without port' do it 'initializes without port' do
ip_whitelist_entry = described_class.new(ipv4) ip_allowlist_entry = described_class.new(ipv4)
expect(ip_whitelist_entry.ip).to eq(ipv4) expect(ip_allowlist_entry.ip).to eq(ipv4)
expect(ip_whitelist_entry.port).to be(nil) expect(ip_allowlist_entry.port).to be(nil)
end end
it 'initializes with port' do it 'initializes with port' do
port = 8080 port = 8080
ip_whitelist_entry = described_class.new(ipv4, port: port) ip_allowlist_entry = described_class.new(ipv4, port: port)
expect(ip_whitelist_entry.ip).to eq(ipv4) expect(ip_allowlist_entry.ip).to eq(ipv4)
expect(ip_whitelist_entry.port).to eq(port) expect(ip_allowlist_entry.port).to eq(port)
end end
end end
describe '#match?' do describe '#match?' do
it 'matches with equivalent IP and port' do it 'matches with equivalent IP and port' do
port = 8080 port = 8080
ip_whitelist_entry = described_class.new(ipv4, port: port) ip_allowlist_entry = described_class.new(ipv4, port: port)
expect(ip_whitelist_entry).to be_match(ipv4.to_s, port) expect(ip_allowlist_entry).to be_match(ipv4.to_s, port)
end end
it 'matches any port when port is nil' do it 'matches any port when port is nil' do
ip_whitelist_entry = described_class.new(ipv4) ip_allowlist_entry = described_class.new(ipv4)
expect(ip_whitelist_entry).to be_match(ipv4.to_s, 8080) expect(ip_allowlist_entry).to be_match(ipv4.to_s, 8080)
expect(ip_whitelist_entry).to be_match(ipv4.to_s, 9090) expect(ip_allowlist_entry).to be_match(ipv4.to_s, 9090)
end end
it 'does not match when port is present but requested_port is nil' do it 'does not match when port is present but requested_port is nil' do
ip_whitelist_entry = described_class.new(ipv4, port: 8080) ip_allowlist_entry = described_class.new(ipv4, port: 8080)
expect(ip_whitelist_entry).not_to be_match(ipv4.to_s, nil) expect(ip_allowlist_entry).not_to be_match(ipv4.to_s, nil)
end end
it 'matches when port and requested_port are nil' do it 'matches when port and requested_port are nil' do
ip_whitelist_entry = described_class.new(ipv4) ip_allowlist_entry = described_class.new(ipv4)
expect(ip_whitelist_entry).to be_match(ipv4.to_s) expect(ip_allowlist_entry).to be_match(ipv4.to_s)
end end
it 'works with ipv6' do it 'works with ipv6' do
ipv6 = IPAddr.new('fe80::c800:eff:fe74:8') ipv6 = IPAddr.new('fe80::c800:eff:fe74:8')
ip_whitelist_entry = described_class.new(ipv6) ip_allowlist_entry = described_class.new(ipv6)
expect(ip_whitelist_entry).to be_match(ipv6.to_s, 8080) expect(ip_allowlist_entry).to be_match(ipv6.to_s, 8080)
end end
it 'matches ipv4 within IPv4 range' do it 'matches ipv4 within IPv4 range' do
ipv4_range = IPAddr.new('127.0.0.0/28') ipv4_range = IPAddr.new('127.0.0.0/28')
ip_whitelist_entry = described_class.new(ipv4_range) ip_allowlist_entry = described_class.new(ipv4_range)
expect(ip_whitelist_entry).to be_match(ipv4_range.to_range.last.to_s, 8080) expect(ip_allowlist_entry).to be_match(ipv4_range.to_range.last.to_s, 8080)
expect(ip_whitelist_entry).not_to be_match('127.0.1.1', 8080) expect(ip_allowlist_entry).not_to be_match('127.0.1.1', 8080)
end end
it 'matches IPv6 within IPv6 range' do it 'matches IPv6 within IPv6 range' do
ipv6_range = IPAddr.new('fd84:6d02:f6d8:c89e::/124') ipv6_range = IPAddr.new('fd84:6d02:f6d8:c89e::/124')
ip_whitelist_entry = described_class.new(ipv6_range) ip_allowlist_entry = described_class.new(ipv6_range)
expect(ip_whitelist_entry).to be_match(ipv6_range.to_range.last.to_s, 8080) expect(ip_allowlist_entry).to be_match(ipv6_range.to_range.last.to_s, 8080)
expect(ip_whitelist_entry).not_to be_match('fd84:6d02:f6d8:f::f', 8080) expect(ip_allowlist_entry).not_to be_match('fd84:6d02:f6d8:f::f', 8080)
end end
end end
end end
...@@ -2,62 +2,62 @@ ...@@ -2,62 +2,62 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::UrlBlockers::UrlWhitelist do RSpec.describe Gitlab::UrlBlockers::UrlAllowlist do
include StubRequests include StubRequests
let(:whitelist) { [] } let(:allowlist) { [] }
before do before do
allow(ApplicationSetting).to receive(:current).and_return(ApplicationSetting.new) allow(ApplicationSetting).to receive(:current).and_return(ApplicationSetting.new)
stub_application_setting(outbound_local_requests_whitelist: whitelist) stub_application_setting(outbound_local_requests_whitelist: allowlist)
end end
describe '#domain_whitelisted?' do describe '#domain_allowed?' do
let(:whitelist) { ['www.example.com', 'example.com'] } let(:allowlist) { %w[www.example.com example.com] }
it 'returns true if domains present in whitelist' do it 'returns true if domains present in allowlist' do
not_whitelisted = ['subdomain.example.com', 'example.org'] not_allowed = %w[subdomain.example.com example.org]
aggregate_failures do aggregate_failures do
whitelist.each do |domain| allowlist.each do |domain|
expect(described_class).to be_domain_whitelisted(domain) expect(described_class).to be_domain_allowed(domain)
end end
not_whitelisted.each do |domain| not_allowed.each do |domain|
expect(described_class).not_to be_domain_whitelisted(domain) expect(described_class).not_to be_domain_allowed(domain)
end end
end end
end end
it 'returns false when domain is blank' do it 'returns false when domain is blank' do
expect(described_class).not_to be_domain_whitelisted(nil) expect(described_class).not_to be_domain_allowed(nil)
end end
context 'with ports' do context 'with ports' do
let(:whitelist) { ['example.io:3000'] } let(:allowlist) { ['example.io:3000'] }
it 'returns true if domain and ports present in whitelist' do it 'returns true if domain and ports present in allowlist' do
parsed_whitelist = [['example.io', { port: 3000 }]] parsed_allowlist = [['example.io', { port: 3000 }]]
not_whitelisted = [ not_allowed = [
'example.io', 'example.io',
['example.io', { port: 3001 }] ['example.io', { port: 3001 }]
] ]
aggregate_failures do aggregate_failures do
parsed_whitelist.each do |domain_and_port| parsed_allowlist.each do |domain_and_port|
expect(described_class).to be_domain_whitelisted(*domain_and_port) expect(described_class).to be_domain_allowed(*domain_and_port)
end end
not_whitelisted.each do |domain_and_port| not_allowed.each do |domain_and_port|
expect(described_class).not_to be_domain_whitelisted(*domain_and_port) expect(described_class).not_to be_domain_allowed(*domain_and_port)
end end
end end
end end
end end
end end
describe '#ip_whitelisted?' do describe '#ip_allowed?' do
let(:whitelist) do let(:allowlist) do
[ [
'0.0.0.0', '0.0.0.0',
'127.0.0.1', '127.0.0.1',
...@@ -72,77 +72,77 @@ RSpec.describe Gitlab::UrlBlockers::UrlWhitelist do ...@@ -72,77 +72,77 @@ RSpec.describe Gitlab::UrlBlockers::UrlWhitelist do
] ]
end end
it 'returns true if ips present in whitelist' do it 'returns true if ips present in allowlist' do
aggregate_failures do aggregate_failures do
whitelist.each do |ip_address| allowlist.each do |ip_address|
expect(described_class).to be_ip_whitelisted(ip_address) expect(described_class).to be_ip_allowed(ip_address)
end end
['172.16.2.2', '127.0.0.2', 'fe80::c800:eff:fe74:9'].each do |ip_address| %w[172.16.2.2 127.0.0.2 fe80::c800:eff:fe74:9].each do |ip_address|
expect(described_class).not_to be_ip_whitelisted(ip_address) expect(described_class).not_to be_ip_allowed(ip_address)
end end
end end
end end
it 'returns false when ip is blank' do it 'returns false when ip is blank' do
expect(described_class).not_to be_ip_whitelisted(nil) expect(described_class).not_to be_ip_allowed(nil)
end end
context 'with ip ranges in whitelist' do context 'with ip ranges in allowlist' do
let(:ipv4_range) { '127.0.0.0/28' } let(:ipv4_range) { '127.0.0.0/28' }
let(:ipv6_range) { 'fd84:6d02:f6d8:c89e::/124' } let(:ipv6_range) { 'fd84:6d02:f6d8:c89e::/124' }
let(:whitelist) do let(:allowlist) do
[ [
ipv4_range, ipv4_range,
ipv6_range ipv6_range
] ]
end end
it 'does not whitelist ipv4 range when not in whitelist' do it 'does not allowlist ipv4 range when not in allowlist' do
stub_application_setting(outbound_local_requests_whitelist: []) stub_application_setting(outbound_local_requests_whitelist: [])
IPAddr.new(ipv4_range).to_range.to_a.each do |ip| IPAddr.new(ipv4_range).to_range.to_a.each do |ip|
expect(described_class).not_to be_ip_whitelisted(ip.to_s) expect(described_class).not_to be_ip_allowed(ip.to_s)
end end
end end
it 'whitelists all ipv4s in the range when in whitelist' do it 'allowlists all ipv4s in the range when in allowlist' do
IPAddr.new(ipv4_range).to_range.to_a.each do |ip| IPAddr.new(ipv4_range).to_range.to_a.each do |ip|
expect(described_class).to be_ip_whitelisted(ip.to_s) expect(described_class).to be_ip_allowed(ip.to_s)
end end
end end
it 'does not whitelist ipv6 range when not in whitelist' do it 'does not allowlist ipv6 range when not in allowlist' do
stub_application_setting(outbound_local_requests_whitelist: []) stub_application_setting(outbound_local_requests_whitelist: [])
IPAddr.new(ipv6_range).to_range.to_a.each do |ip| IPAddr.new(ipv6_range).to_range.to_a.each do |ip|
expect(described_class).not_to be_ip_whitelisted(ip.to_s) expect(described_class).not_to be_ip_allowed(ip.to_s)
end end
end end
it 'whitelists all ipv6s in the range when in whitelist' do it 'allowlists all ipv6s in the range when in allowlist' do
IPAddr.new(ipv6_range).to_range.to_a.each do |ip| IPAddr.new(ipv6_range).to_range.to_a.each do |ip|
expect(described_class).to be_ip_whitelisted(ip.to_s) expect(described_class).to be_ip_allowed(ip.to_s)
end end
end end
it 'does not whitelist IPs outside the range' do it 'does not allowlist IPs outside the range' do
expect(described_class).not_to be_ip_whitelisted("fd84:6d02:f6d8:c89e:0:0:1:f") expect(described_class).not_to be_ip_allowed("fd84:6d02:f6d8:c89e:0:0:1:f")
expect(described_class).not_to be_ip_whitelisted("127.0.1.15") expect(described_class).not_to be_ip_allowed("127.0.1.15")
end end
end end
context 'with ports' do context 'with ports' do
let(:whitelist) { ['127.0.0.9:3000', '[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443'] } let(:allowlist) { %w[127.0.0.9:3000 [2001:db8:85a3:8d3:1319:8a2e:370:7348]:443] }
it 'returns true if ip and ports present in whitelist' do it 'returns true if ip and ports present in allowlist' do
parsed_whitelist = [ parsed_allowlist = [
['127.0.0.9', { port: 3000 }], ['127.0.0.9', { port: 3000 }],
['[2001:db8:85a3:8d3:1319:8a2e:370:7348]', { port: 443 }] ['[2001:db8:85a3:8d3:1319:8a2e:370:7348]', { port: 443 }]
] ]
not_whitelisted = [ not_allowed = [
'127.0.0.9', '127.0.0.9',
['127.0.0.9', { port: 3001 }], ['127.0.0.9', { port: 3001 }],
'[2001:db8:85a3:8d3:1319:8a2e:370:7348]', '[2001:db8:85a3:8d3:1319:8a2e:370:7348]',
...@@ -150,12 +150,12 @@ RSpec.describe Gitlab::UrlBlockers::UrlWhitelist do ...@@ -150,12 +150,12 @@ RSpec.describe Gitlab::UrlBlockers::UrlWhitelist do
] ]
aggregate_failures do aggregate_failures do
parsed_whitelist.each do |ip_and_port| parsed_allowlist.each do |ip_and_port|
expect(described_class).to be_ip_whitelisted(*ip_and_port) expect(described_class).to be_ip_allowed(*ip_and_port)
end end
not_whitelisted.each do |ip_and_port| not_allowed.each do |ip_and_port|
expect(described_class).not_to be_ip_whitelisted(*ip_and_port) expect(described_class).not_to be_ip_allowed(*ip_and_port)
end end
end end
end end
......
...@@ -91,12 +91,12 @@ RSpec.describe ApplicationSettings::UpdateService do ...@@ -91,12 +91,12 @@ RSpec.describe ApplicationSettings::UpdateService do
end end
end end
context 'when param outbound_local_requests_whitelist_raw is passed' do context 'when param outbound_local_requests_allowlist_raw is passed' do
before do before do
application_settings.outbound_local_requests_whitelist = ['127.0.0.1'] application_settings.outbound_local_requests_whitelist = ['127.0.0.1']
end end
let(:params) { { outbound_local_requests_whitelist_raw: 'example.com;gitlab.com' } } let(:params) { { outbound_local_requests_allowlist_raw: 'example.com;gitlab.com' } }
it 'overwrites the existing whitelist' do it 'overwrites the existing whitelist' do
expect { subject.execute }.to change { expect { subject.execute }.to change {
......
# frozen_string_literal: true # frozen_string_literal: true
RSpec.shared_examples 'string of domains' do |attribute| RSpec.shared_examples 'string of domains' do |mapped_name, attribute|
it 'sets single domain' do it 'sets single domain' do
setting.method("#{attribute}_raw=").call('example.com') setting.method("#{mapped_name}_raw=").call('example.com')
expect(setting.method(attribute).call).to eq(['example.com']) expect(setting.method(attribute).call).to eq(['example.com'])
end end
it 'sets multiple domains with spaces' do it 'sets multiple domains with spaces' do
setting.method("#{attribute}_raw=").call('example.com *.example.com') setting.method("#{mapped_name}_raw=").call('example.com *.example.com')
expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) expect(setting.method(attribute).call).to eq(['example.com', '*.example.com'])
end end
it 'sets multiple domains with newlines and a space' do it 'sets multiple domains with newlines and a space' do
setting.method("#{attribute}_raw=").call("example.com\n *.example.com") setting.method("#{mapped_name}_raw=").call("example.com\n *.example.com")
expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) expect(setting.method(attribute).call).to eq(['example.com', '*.example.com'])
end end
it 'sets multiple domains with commas' do it 'sets multiple domains with commas' do
setting.method("#{attribute}_raw=").call("example.com, *.example.com") setting.method("#{mapped_name}_raw=").call("example.com, *.example.com")
expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) expect(setting.method(attribute).call).to eq(['example.com', '*.example.com'])
end end
it 'sets multiple domains with semicolon' do it 'sets multiple domains with semicolon' do
setting.method("#{attribute}_raw=").call("example.com; *.example.com") setting.method("#{mapped_name}_raw=").call("example.com; *.example.com")
expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com') expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com')
end end
it 'sets multiple domains with mixture of everything' do it 'sets multiple domains with mixture of everything' do
setting.method("#{attribute}_raw=").call("example.com; *.example.com\n test.com\sblock.com yes.com") setting.method("#{mapped_name}_raw=").call("example.com; *.example.com\n test.com\sblock.com yes.com")
expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com', 'test.com', 'block.com', 'yes.com') expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com', 'test.com', 'block.com', 'yes.com')
end end
it 'removes duplicates' do it 'removes duplicates' do
setting.method("#{attribute}_raw=").call("example.com; example.com; 127.0.0.1; 127.0.0.1") setting.method("#{mapped_name}_raw=").call("example.com; example.com; 127.0.0.1; 127.0.0.1")
expect(setting.method(attribute).call).to contain_exactly('example.com', '127.0.0.1') expect(setting.method(attribute).call).to contain_exactly('example.com', '127.0.0.1')
end end
it 'does not fail with garbage values' do it 'does not fail with garbage values' do
setting.method("#{attribute}_raw=").call("example;34543:garbage:fdh5654;") setting.method("#{mapped_name}_raw=").call("example;34543:garbage:fdh5654;")
expect(setting.method(attribute).call).to contain_exactly('example', '34543:garbage:fdh5654') expect(setting.method(attribute).call).to contain_exactly('example', '34543:garbage:fdh5654')
end end
it 'does not raise error with nil' do it 'does not raise error with nil' do
setting.method("#{attribute}_raw=").call(nil) setting.method("#{mapped_name}_raw=").call(nil)
expect(setting.method(attribute).call).to eq([]) expect(setting.method(attribute).call).to eq([])
end end
end end
RSpec.shared_examples 'application settings examples' do RSpec.shared_examples 'application settings examples' do
context 'restricted signup domains' do context 'restricted signup domains' do
it_behaves_like 'string of domains', :domain_whitelist it_behaves_like 'string of domains', :domain_allowlist, :domain_whitelist
end end
context 'blacklisted signup domains' do context 'blacklisted signup domains' do
it_behaves_like 'string of domains', :domain_blacklist it_behaves_like 'string of domains', :domain_denylist, :domain_blacklist
it 'sets multiple domain with file' do it 'sets multiple domain with file' do
setting.domain_blacklist_file = File.open(Rails.root.join('spec/fixtures/', 'domain_blacklist.txt')) setting.domain_denylist_file = File.open(Rails.root.join('spec/fixtures/', 'domain_denylist.txt'))
expect(setting.domain_blacklist).to contain_exactly('example.com', 'test.com', 'foo.bar') expect(setting.domain_blacklist).to contain_exactly('example.com', 'test.com', 'foo.bar')
end end
end end
context 'outbound_local_requests_whitelist' do context 'outbound_local_requests_whitelist' do
it_behaves_like 'string of domains', :outbound_local_requests_whitelist it_behaves_like 'string of domains', :outbound_local_requests_allowlist, :outbound_local_requests_whitelist
it 'clears outbound_local_requests_whitelist_arrays memoization' do it 'clears outbound_local_requests_allowlist_arrays memoization' do
setting.outbound_local_requests_whitelist_raw = 'example.com' setting.outbound_local_requests_allowlist_raw = 'example.com'
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( expect(setting.outbound_local_requests_allowlist_arrays).to contain_exactly(
[], [an_object_having_attributes(domain: 'example.com')] [], [an_object_having_attributes(domain: 'example.com')]
) )
setting.outbound_local_requests_whitelist_raw = 'gitlab.com' setting.outbound_local_requests_allowlist_raw = 'gitlab.com'
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( expect(setting.outbound_local_requests_allowlist_arrays).to contain_exactly(
[], [an_object_having_attributes(domain: 'gitlab.com')] [], [an_object_having_attributes(domain: 'gitlab.com')]
) )
end end
end end
context 'outbound_local_requests_whitelist_arrays' do context 'outbound_local_requests_allowlist_arrays' do
it 'separates the IPs and domains' do it 'separates the IPs and domains' do
setting.outbound_local_requests_whitelist = [ setting.outbound_local_requests_whitelist = [
'192.168.1.1', '192.168.1.1',
...@@ -118,7 +118,7 @@ RSpec.shared_examples 'application settings examples' do ...@@ -118,7 +118,7 @@ RSpec.shared_examples 'application settings examples' do
an_object_having_attributes(domain: 'example.com', port: 8080) an_object_having_attributes(domain: 'example.com', port: 8080)
] ]
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( expect(setting.outbound_local_requests_allowlist_arrays).to contain_exactly(
ip_whitelist, domain_whitelist ip_whitelist, domain_whitelist
) )
end end
...@@ -139,10 +139,10 @@ RSpec.shared_examples 'application settings examples' do ...@@ -139,10 +139,10 @@ RSpec.shared_examples 'application settings examples' do
) )
end end
it 'clears outbound_local_requests_whitelist_arrays memoization' do it 'clears outbound_local_requests_allowlist_arrays memoization' do
setting.outbound_local_requests_whitelist = ['example.com'] setting.outbound_local_requests_whitelist = ['example.com']
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( expect(setting.outbound_local_requests_allowlist_arrays).to contain_exactly(
[], [],
[an_object_having_attributes(domain: 'example.com')] [an_object_having_attributes(domain: 'example.com')]
) )
...@@ -151,7 +151,7 @@ RSpec.shared_examples 'application settings examples' do ...@@ -151,7 +151,7 @@ RSpec.shared_examples 'application settings examples' do
['example.com', 'gitlab.com'] ['example.com', 'gitlab.com']
) )
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( expect(setting.outbound_local_requests_allowlist_arrays).to contain_exactly(
[], [],
[an_object_having_attributes(domain: 'example.com'), an_object_having_attributes(domain: 'gitlab.com')] [an_object_having_attributes(domain: 'example.com'), an_object_having_attributes(domain: 'gitlab.com')]
) )
...@@ -163,7 +163,7 @@ RSpec.shared_examples 'application settings examples' do ...@@ -163,7 +163,7 @@ RSpec.shared_examples 'application settings examples' do
setting.add_to_outbound_local_requests_whitelist(['gitlab.com']) setting.add_to_outbound_local_requests_whitelist(['gitlab.com'])
expect(setting.outbound_local_requests_whitelist).to contain_exactly('gitlab.com') expect(setting.outbound_local_requests_whitelist).to contain_exactly('gitlab.com')
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( expect(setting.outbound_local_requests_allowlist_arrays).to contain_exactly(
[], [an_object_having_attributes(domain: 'gitlab.com')] [], [an_object_having_attributes(domain: 'gitlab.com')]
) )
end end
...@@ -171,7 +171,7 @@ RSpec.shared_examples 'application settings examples' do ...@@ -171,7 +171,7 @@ RSpec.shared_examples 'application settings examples' do
it 'does not raise error with nil' do it 'does not raise error with nil' do
setting.outbound_local_requests_whitelist = nil setting.outbound_local_requests_whitelist = nil
expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly([], []) expect(setting.outbound_local_requests_allowlist_arrays).to contain_exactly([], [])
end end
end end
......
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