Commit 7945b2c3 authored by Tim Zallmann's avatar Tim Zallmann

Merge branch 'add_option_for_switching_between_block_log' into 'master'

Add option for switching between block log

See merge request gitlab-org/gitlab!27133
parents 58f6d52e ef0e0286
...@@ -256,7 +256,8 @@ export default class Clusters { ...@@ -256,7 +256,8 @@ export default class Clusters {
eventHub.$on('uninstallApplication', data => this.uninstallApplication(data)); eventHub.$on('uninstallApplication', data => this.uninstallApplication(data));
eventHub.$on('setCrossplaneProviderStack', data => this.setCrossplaneProviderStack(data)); eventHub.$on('setCrossplaneProviderStack', data => this.setCrossplaneProviderStack(data));
eventHub.$on('setIngressModSecurityEnabled', data => this.setIngressModSecurityEnabled(data)); eventHub.$on('setIngressModSecurityEnabled', data => this.setIngressModSecurityEnabled(data));
eventHub.$on('resetIngressModSecurityEnabled', id => this.resetIngressModSecurityEnabled(id)); eventHub.$on('setIngressModSecurityMode', data => this.setIngressModSecurityMode(data));
eventHub.$on('resetIngressModSecurityChanges', id => this.resetIngressModSecurityChanges(id));
// Add event listener to all the banner close buttons // Add event listener to all the banner close buttons
this.addBannerCloseHandler(this.unreachableContainer, 'unreachable'); this.addBannerCloseHandler(this.unreachableContainer, 'unreachable');
this.addBannerCloseHandler(this.authenticationFailureContainer, 'authentication_failure'); this.addBannerCloseHandler(this.authenticationFailureContainer, 'authentication_failure');
...@@ -271,7 +272,8 @@ export default class Clusters { ...@@ -271,7 +272,8 @@ export default class Clusters {
eventHub.$off('setCrossplaneProviderStack'); eventHub.$off('setCrossplaneProviderStack');
eventHub.$off('uninstallApplication'); eventHub.$off('uninstallApplication');
eventHub.$off('setIngressModSecurityEnabled'); eventHub.$off('setIngressModSecurityEnabled');
eventHub.$off('resetIngressModSecurityEnabled'); eventHub.$off('setIngressModSecurityMode');
eventHub.$off('resetIngressModSecurityChanges');
} }
initPolling(method, successCallback, errorCallback) { initPolling(method, successCallback, errorCallback) {
...@@ -525,8 +527,14 @@ export default class Clusters { ...@@ -525,8 +527,14 @@ export default class Clusters {
this.store.updateAppProperty(id, 'modsecurity_enabled', modSecurityEnabled); this.store.updateAppProperty(id, 'modsecurity_enabled', modSecurityEnabled);
} }
resetIngressModSecurityEnabled(id) { setIngressModSecurityMode({ id, modSecurityMode }) {
this.store.updateAppProperty(id, 'isEditingModSecurityMode', true);
this.store.updateAppProperty(id, 'modsecurity_mode', modSecurityMode);
}
resetIngressModSecurityChanges(id) {
this.store.updateAppProperty(id, 'isEditingModSecurityEnabled', false); this.store.updateAppProperty(id, 'isEditingModSecurityEnabled', false);
this.store.updateAppProperty(id, 'isEditingModSecurityMode', false);
} }
destroy() { destroy() {
......
...@@ -313,6 +313,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity ...@@ -313,6 +313,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity
:install-failed="applications.ingress.installFailed" :install-failed="applications.ingress.installFailed"
:install-application-request-params="{ :install-application-request-params="{
modsecurity_enabled: applications.ingress.modsecurity_enabled, modsecurity_enabled: applications.ingress.modsecurity_enabled,
modsecurity_mode: applications.ingress.modsecurity_mode,
}" }"
:uninstallable="applications.ingress.uninstallable" :uninstallable="applications.ingress.uninstallable"
:uninstall-successful="applications.ingress.uninstallSuccessful" :uninstall-successful="applications.ingress.uninstallSuccessful"
......
<script> <script>
import _ from 'lodash'; import { escape as esc } from 'lodash';
import { __ } from '../../locale'; import { s__, __ } from '../../locale';
import { APPLICATION_STATUS, INGRESS } from '~/clusters/constants'; import { APPLICATION_STATUS, INGRESS, LOGGING_MODE, BLOCKING_MODE } from '~/clusters/constants';
import { GlAlert, GlSprintf, GlLink, GlToggle, GlButton } from '@gitlab/ui'; import {
GlAlert,
GlSprintf,
GlLink,
GlToggle,
GlButton,
GlDropdown,
GlDropdownItem,
GlIcon,
} from '@gitlab/ui';
import eventHub from '~/clusters/event_hub'; import eventHub from '~/clusters/event_hub';
import modSecurityLogo from 'images/cluster_app_logos/modsecurity.png'; import modSecurityLogo from 'images/cluster_app_logos/modsecurity.png';
...@@ -17,6 +26,9 @@ export default { ...@@ -17,6 +26,9 @@ export default {
GlLink, GlLink,
GlToggle, GlToggle,
GlButton, GlButton,
GlDropdown,
GlDropdownItem,
GlIcon,
}, },
props: { props: {
ingress: { ingress: {
...@@ -28,10 +40,23 @@ export default { ...@@ -28,10 +40,23 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
modes: {
type: Object,
required: false,
default: () => ({
[LOGGING_MODE]: {
name: s__('ClusterIntegration|Logging mode'),
},
[BLOCKING_MODE]: {
name: s__('ClusterIntegration|Blocking mode'),
},
}),
},
}, },
data: () => ({ data: () => ({
modSecurityLogo, modSecurityLogo,
hasValueChanged: false, initialValue: null,
initialMode: null,
}), }),
computed: { computed: {
modSecurityEnabled: { modSecurityEnabled: {
...@@ -39,19 +64,30 @@ export default { ...@@ -39,19 +64,30 @@ export default {
return this.ingress.modsecurity_enabled; return this.ingress.modsecurity_enabled;
}, },
set(isEnabled) { set(isEnabled) {
if (this.initialValue === null) {
this.initialValue = this.ingress.modsecurity_enabled;
}
eventHub.$emit('setIngressModSecurityEnabled', { eventHub.$emit('setIngressModSecurityEnabled', {
id: INGRESS, id: INGRESS,
modSecurityEnabled: isEnabled, modSecurityEnabled: isEnabled,
}); });
if (this.hasValueChanged) {
this.resetStatus();
} else {
this.hasValueChanged = true;
}
}, },
}, },
hasValueChanged() {
return this.modSecurityEnabledChanged || this.modSecurityModeChanged;
},
modSecurityEnabledChanged() {
return this.initialValue !== null && this.initialValue !== this.ingress.modsecurity_enabled;
},
modSecurityModeChanged() {
return (
this.ingress.modsecurity_enabled &&
this.initialMode !== null &&
this.initialMode !== this.ingress.modsecurity_mode
);
},
ingressModSecurityDescription() { ingressModSecurityDescription() {
return _.escape(this.ingressModSecurityHelpPath); return esc(this.ingressModSecurityHelpPath);
}, },
saving() { saving() {
return [UPDATING].includes(this.ingress.status); return [UPDATING].includes(this.ingress.status);
...@@ -73,18 +109,40 @@ export default { ...@@ -73,18 +109,40 @@ export default {
this.saving || (this.hasValueChanged && [INSTALLED, UPDATED].includes(this.ingress.status)) this.saving || (this.hasValueChanged && [INSTALLED, UPDATED].includes(this.ingress.status))
); );
}, },
modSecurityModeName() {
return this.modes[this.ingress.modsecurity_mode].name;
},
}, },
methods: { methods: {
updateApplication() { updateApplication() {
eventHub.$emit('updateApplication', { eventHub.$emit('updateApplication', {
id: INGRESS, id: INGRESS,
params: { modsecurity_enabled: this.ingress.modsecurity_enabled }, params: {
modsecurity_enabled: this.ingress.modsecurity_enabled,
modsecurity_mode: this.ingress.modsecurity_mode,
},
}); });
this.resetStatus(); this.resetStatus();
}, },
resetStatus() { resetStatus() {
eventHub.$emit('resetIngressModSecurityEnabled', INGRESS); if (this.initialMode !== null) {
this.hasValueChanged = false; this.ingress.modsecurity_mode = this.initialMode;
}
if (this.initialValue !== null) {
this.ingress.modsecurity_enabled = this.initialValue;
}
this.initialValue = null;
this.initialMode = null;
eventHub.$emit('resetIngressModSecurityChanges', INGRESS);
},
selectMode(modeKey) {
if (this.initialMode === null) {
this.initialMode = this.ingress.modsecurity_mode;
}
eventHub.$emit('setIngressModSecurityMode', {
id: INGRESS,
modSecurityMode: modeKey,
});
}, },
}, },
}; };
...@@ -144,7 +202,35 @@ export default { ...@@ -144,7 +202,35 @@ export default {
label-position="right" label-position="right"
/> />
</div> </div>
<div v-if="showButtons"> <div
v-if="ingress.modsecurity_enabled"
class="gl-responsive-table-row-layout mt-3"
role="row"
>
<div class="table-section section-wrap" role="gridcell">
<strong>
{{ s__('ClusterIntegration|Global default') }}
<gl-icon name="earth" class="align-text-bottom" />
</strong>
<div class="form-group">
<p class="form-text text-muted">
<strong>
{{
s__(
'ClusterIntegration|Set the global mode for the WAF in this cluster. This can be overridden at the environmental level.',
)
}}
</strong>
</p>
</div>
<gl-dropdown :text="modSecurityModeName" :disabled="saveButtonDisabled">
<gl-dropdown-item v-for="(mode, key) in modes" :key="key" @click="selectMode(key)">
{{ mode.name }}
</gl-dropdown-item>
</gl-dropdown>
</div>
</div>
<div v-if="showButtons" class="mt-3">
<gl-button <gl-button
class="btn-success inline mr-1" class="btn-success inline mr-1"
:loading="saving" :loading="saving"
......
...@@ -66,3 +66,6 @@ export const APPLICATIONS = [ ...@@ -66,3 +66,6 @@ export const APPLICATIONS = [
]; ];
export const INGRESS_DOMAIN_SUFFIX = '.nip.io'; export const INGRESS_DOMAIN_SUFFIX = '.nip.io';
export const LOGGING_MODE = 'logging';
export const BLOCKING_MODE = 'blocking';
...@@ -53,9 +53,11 @@ export default class ClusterStore { ...@@ -53,9 +53,11 @@ export default class ClusterStore {
...applicationInitialState, ...applicationInitialState,
title: s__('ClusterIntegration|Ingress'), title: s__('ClusterIntegration|Ingress'),
modsecurity_enabled: false, modsecurity_enabled: false,
modsecurity_mode: null,
externalIp: null, externalIp: null,
externalHostname: null, externalHostname: null,
isEditingModSecurityEnabled: false, isEditingModSecurityEnabled: false,
isEditingModSecurityMode: false,
updateFailed: false, updateFailed: false,
}, },
cert_manager: { cert_manager: {
...@@ -214,6 +216,9 @@ export default class ClusterStore { ...@@ -214,6 +216,9 @@ export default class ClusterStore {
if (!this.state.applications.ingress.isEditingModSecurityEnabled) { if (!this.state.applications.ingress.isEditingModSecurityEnabled) {
this.state.applications.ingress.modsecurity_enabled = serverAppEntry.modsecurity_enabled; this.state.applications.ingress.modsecurity_enabled = serverAppEntry.modsecurity_enabled;
} }
if (!this.state.applications.ingress.isEditingModSecurityMode) {
this.state.applications.ingress.modsecurity_mode = serverAppEntry.modsecurity_mode;
}
} else if (appId === CERT_MANAGER) { } else if (appId === CERT_MANAGER) {
this.state.applications.cert_manager.email = this.state.applications.cert_manager.email =
this.state.applications.cert_manager.email || serverAppEntry.email; this.state.applications.cert_manager.email || serverAppEntry.email;
......
...@@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController ...@@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController
end end
def cluster_application_params def cluster_application_params
params.permit(:application, :hostname, :email, :stack, :modsecurity_enabled) params.permit(:application, :hostname, :email, :stack, :modsecurity_enabled, :modsecurity_mode)
end end
def cluster_application_destroy_params def cluster_application_destroy_params
......
...@@ -6,6 +6,9 @@ module Clusters ...@@ -6,6 +6,9 @@ module Clusters
VERSION = '1.29.7' VERSION = '1.29.7'
INGRESS_CONTAINER_NAME = 'nginx-ingress-controller' INGRESS_CONTAINER_NAME = 'nginx-ingress-controller'
MODSECURITY_LOG_CONTAINER_NAME = 'modsecurity-log' MODSECURITY_LOG_CONTAINER_NAME = 'modsecurity-log'
MODSECURITY_MODE_LOGGING = "DetectionOnly"
MODSECURITY_MODE_BLOCKING = "On"
MODSECURITY_OWASP_RULES_FILE = "/etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf"
self.table_name = 'clusters_applications_ingress' self.table_name = 'clusters_applications_ingress'
...@@ -18,11 +21,14 @@ module Clusters ...@@ -18,11 +21,14 @@ module Clusters
default_value_for :ingress_type, :nginx default_value_for :ingress_type, :nginx
default_value_for :modsecurity_enabled, true default_value_for :modsecurity_enabled, true
default_value_for :version, VERSION default_value_for :version, VERSION
default_value_for :modsecurity_mode, :logging
enum ingress_type: { enum ingress_type: {
nginx: 1 nginx: 1
} }
enum modsecurity_mode: { logging: 0, blocking: 1 }
FETCH_IP_ADDRESS_DELAY = 30.seconds FETCH_IP_ADDRESS_DELAY = 30.seconds
MODSEC_SIDECAR_INITIAL_DELAY_SECONDS = 10 MODSEC_SIDECAR_INITIAL_DELAY_SECONDS = 10
...@@ -82,7 +88,8 @@ module Clusters ...@@ -82,7 +88,8 @@ module Clusters
"controller" => { "controller" => {
"config" => { "config" => {
"enable-modsecurity" => "true", "enable-modsecurity" => "true",
"enable-owasp-modsecurity-crs" => "true", "enable-owasp-modsecurity-crs" => "false",
"modsecurity-snippet" => modsecurity_snippet_content,
"modsecurity.conf" => modsecurity_config_content "modsecurity.conf" => modsecurity_config_content
}, },
"extraContainers" => [ "extraContainers" => [
...@@ -157,6 +164,11 @@ module Clusters ...@@ -157,6 +164,11 @@ module Clusters
def application_jupyter_nil_or_installable? def application_jupyter_nil_or_installable?
cluster.application_jupyter.nil? || cluster.application_jupyter&.installable? cluster.application_jupyter.nil? || cluster.application_jupyter&.installable?
end end
def modsecurity_snippet_content
sec_rule_engine = logging? ? MODSECURITY_MODE_LOGGING : MODSECURITY_MODE_BLOCKING
"SecRuleEngine #{sec_rule_engine}\nInclude #{MODSECURITY_OWASP_RULES_FILE}"
end
end end
end end
end end
...@@ -15,4 +15,5 @@ class ClusterApplicationEntity < Grape::Entity ...@@ -15,4 +15,5 @@ class ClusterApplicationEntity < Grape::Entity
expose :can_uninstall?, as: :can_uninstall expose :can_uninstall?, as: :can_uninstall
expose :available_domains, using: Serverless::DomainEntity, if: -> (e, _) { e.respond_to?(:available_domains) } expose :available_domains, using: Serverless::DomainEntity, if: -> (e, _) { e.respond_to?(:available_domains) }
expose :pages_domain, using: Serverless::DomainEntity, if: -> (e, _) { e.respond_to?(:pages_domain) } expose :pages_domain, using: Serverless::DomainEntity, if: -> (e, _) { e.respond_to?(:pages_domain) }
expose :modsecurity_mode, if: -> (e, _) { e.respond_to?(:modsecurity_mode) }
end end
...@@ -31,6 +31,10 @@ module Clusters ...@@ -31,6 +31,10 @@ module Clusters
application.modsecurity_enabled = params[:modsecurity_enabled] || false application.modsecurity_enabled = params[:modsecurity_enabled] || false
end end
if application.has_attribute?(:modsecurity_mode)
application.modsecurity_mode = params[:modsecurity_mode] || 0
end
if application.respond_to?(:oauth_application) if application.respond_to?(:oauth_application)
application.oauth_application = create_oauth_application(application, request) application.oauth_application = create_oauth_application(application, request)
end end
......
---
title: Add option for switching between blocking and logging for WAF
merge_request: 27133
author:
type: added
# frozen_string_literal: true
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddModsecurityModeToIngressApplication < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:clusters_applications_ingress, :modsecurity_mode, :smallint, default: 0, allow_null: false)
end
def down
remove_column :clusters_applications_ingress, :modsecurity_mode
end
end
...@@ -1199,6 +1199,7 @@ ActiveRecord::Schema.define(version: 2020_03_13_123934) do ...@@ -1199,6 +1199,7 @@ ActiveRecord::Schema.define(version: 2020_03_13_123934) do
t.string "external_ip" t.string "external_ip"
t.string "external_hostname" t.string "external_hostname"
t.boolean "modsecurity_enabled" t.boolean "modsecurity_enabled"
t.integer "modsecurity_mode", limit: 2, default: 0, null: false
t.index ["cluster_id"], name: "index_clusters_applications_ingress_on_cluster_id", unique: true t.index ["cluster_id"], name: "index_clusters_applications_ingress_on_cluster_id", unique: true
end end
......
...@@ -4126,6 +4126,9 @@ msgstr "" ...@@ -4126,6 +4126,9 @@ msgstr ""
msgid "ClusterIntegration|Base domain" msgid "ClusterIntegration|Base domain"
msgstr "" msgstr ""
msgid "ClusterIntegration|Blocking mode"
msgstr ""
msgid "ClusterIntegration|CA Certificate" msgid "ClusterIntegration|CA Certificate"
msgstr "" msgstr ""
...@@ -4324,6 +4327,9 @@ msgstr "" ...@@ -4324,6 +4327,9 @@ msgstr ""
msgid "ClusterIntegration|Gitlab Integration" msgid "ClusterIntegration|Gitlab Integration"
msgstr "" msgstr ""
msgid "ClusterIntegration|Global default"
msgstr ""
msgid "ClusterIntegration|Google Cloud Platform project" msgid "ClusterIntegration|Google Cloud Platform project"
msgstr "" msgstr ""
...@@ -4483,6 +4489,9 @@ msgstr "" ...@@ -4483,6 +4489,9 @@ msgstr ""
msgid "ClusterIntegration|Loading subnetworks" msgid "ClusterIntegration|Loading subnetworks"
msgstr "" msgstr ""
msgid "ClusterIntegration|Logging mode"
msgstr ""
msgid "ClusterIntegration|Machine type" msgid "ClusterIntegration|Machine type"
msgstr "" msgstr ""
...@@ -4711,6 +4720,9 @@ msgstr "" ...@@ -4711,6 +4720,9 @@ msgstr ""
msgid "ClusterIntegration|Set a prefix for your namespaces. If not set, defaults to your project path. If modified, existing environments will use their current namespaces until the cluster cache is cleared." msgid "ClusterIntegration|Set a prefix for your namespaces. If not set, defaults to your project path. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
msgstr "" msgstr ""
msgid "ClusterIntegration|Set the global mode for the WAF in this cluster. This can be overridden at the environmental level."
msgstr ""
msgid "ClusterIntegration|Show" msgid "ClusterIntegration|Show"
msgstr "" msgstr ""
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
"email": { "type": ["string", "null"] }, "email": { "type": ["string", "null"] },
"stack": { "type": ["string", "null"] }, "stack": { "type": ["string", "null"] },
"modsecurity_enabled": { "type": ["boolean", "null"] }, "modsecurity_enabled": { "type": ["boolean", "null"] },
"modsecurity_mode": {"type": ["integer", "0"]},
"update_available": { "type": ["boolean", "null"] }, "update_available": { "type": ["boolean", "null"] },
"can_uninstall": { "type": "boolean" }, "can_uninstall": { "type": "boolean" },
"available_domains": { "available_domains": {
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import IngressModsecuritySettings from '~/clusters/components/ingress_modsecurity_settings.vue'; import IngressModsecuritySettings from '~/clusters/components/ingress_modsecurity_settings.vue';
import { APPLICATION_STATUS, INGRESS } from '~/clusters/constants'; import { APPLICATION_STATUS, INGRESS } from '~/clusters/constants';
import { GlAlert, GlToggle } from '@gitlab/ui'; import { GlAlert, GlToggle, GlDropdown } from '@gitlab/ui';
import eventHub from '~/clusters/event_hub'; import eventHub from '~/clusters/event_hub';
const { UPDATING } = APPLICATION_STATUS; const { UPDATING } = APPLICATION_STATUS;
...@@ -13,6 +13,7 @@ describe('IngressModsecuritySettings', () => { ...@@ -13,6 +13,7 @@ describe('IngressModsecuritySettings', () => {
modsecurity_enabled: false, modsecurity_enabled: false,
status: 'installable', status: 'installable',
installed: false, installed: false,
modsecurity_mode: 'logging',
}; };
const createComponent = (props = defaultProps) => { const createComponent = (props = defaultProps) => {
...@@ -29,6 +30,7 @@ describe('IngressModsecuritySettings', () => { ...@@ -29,6 +30,7 @@ describe('IngressModsecuritySettings', () => {
const findSaveButton = () => wrapper.find('.btn-success'); const findSaveButton = () => wrapper.find('.btn-success');
const findCancelButton = () => wrapper.find('[variant="secondary"]'); const findCancelButton = () => wrapper.find('[variant="secondary"]');
const findModSecurityToggle = () => wrapper.find(GlToggle); const findModSecurityToggle = () => wrapper.find(GlToggle);
const findModSecurityDropdown = () => wrapper.find(GlDropdown);
describe('when ingress is installed', () => { describe('when ingress is installed', () => {
beforeEach(() => { beforeEach(() => {
...@@ -44,22 +46,50 @@ describe('IngressModsecuritySettings', () => { ...@@ -44,22 +46,50 @@ describe('IngressModsecuritySettings', () => {
describe('with toggle changed by the user', () => { describe('with toggle changed by the user', () => {
beforeEach(() => { beforeEach(() => {
findModSecurityToggle().vm.$emit('change'); findModSecurityToggle().vm.$emit('change');
wrapper.setProps({
ingress: {
...defaultProps,
installed: true,
status: 'installed',
modsecurity_enabled: true,
},
});
}); });
it('renders both save and cancel buttons', () => { it('renders save and cancel buttons', () => {
expect(findSaveButton().exists()).toBe(true); expect(findSaveButton().exists()).toBe(true);
expect(findCancelButton().exists()).toBe(true); expect(findCancelButton().exists()).toBe(true);
}); });
describe('and the save changes button is clicked', () => { describe('with dropdown changed by the user', () => {
beforeEach(() => { beforeEach(() => {
findSaveButton().vm.$emit('click'); findModSecurityDropdown().vm.$children[1].$emit('click');
wrapper.setProps({
ingress: {
...defaultProps,
installed: true,
status: 'installed',
modsecurity_enabled: true,
modsecurity_mode: 'blocking',
},
});
});
it('renders both save and cancel buttons', () => {
expect(findSaveButton().exists()).toBe(true);
expect(findCancelButton().exists()).toBe(true);
}); });
it('triggers save event and pass current modsecurity value', () => { describe('and the save changes button is clicked', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('updateApplication', { beforeEach(() => {
id: INGRESS, findSaveButton().vm.$emit('click');
params: { modsecurity_enabled: false }, });
it('triggers save event and pass current modsecurity value', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('updateApplication', {
id: INGRESS,
params: { modsecurity_enabled: true, modsecurity_mode: 'blocking' },
});
}); });
}); });
}); });
...@@ -70,7 +100,7 @@ describe('IngressModsecuritySettings', () => { ...@@ -70,7 +100,7 @@ describe('IngressModsecuritySettings', () => {
}); });
it('triggers reset event and hides both cancel and save changes button', () => { it('triggers reset event and hides both cancel and save changes button', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('resetIngressModSecurityEnabled', INGRESS); expect(eventHub.$emit).toHaveBeenCalledWith('resetIngressModSecurityChanges', INGRESS);
expect(findSaveButton().exists()).toBe(false); expect(findSaveButton().exists()).toBe(false);
expect(findCancelButton().exists()).toBe(false); expect(findCancelButton().exists()).toBe(false);
}); });
......
...@@ -82,6 +82,7 @@ describe('Clusters Store', () => { ...@@ -82,6 +82,7 @@ describe('Clusters Store', () => {
externalHostname: null, externalHostname: null,
installed: false, installed: false,
isEditingModSecurityEnabled: false, isEditingModSecurityEnabled: false,
isEditingModSecurityMode: false,
installFailed: true, installFailed: true,
uninstallable: false, uninstallable: false,
updateFailed: false, updateFailed: false,
...@@ -89,6 +90,7 @@ describe('Clusters Store', () => { ...@@ -89,6 +90,7 @@ describe('Clusters Store', () => {
uninstallFailed: false, uninstallFailed: false,
validationError: null, validationError: null,
modsecurity_enabled: false, modsecurity_enabled: false,
modsecurity_mode: undefined,
}, },
runner: { runner: {
title: 'GitLab Runner', title: 'GitLab Runner',
......
...@@ -140,13 +140,10 @@ describe Clusters::Applications::Ingress do ...@@ -140,13 +140,10 @@ describe Clusters::Applications::Ingress do
end end
describe '#values' do describe '#values' do
let(:project) { build(:project) } subject { ingress }
let(:cluster) { build(:cluster, projects: [project]) }
context 'when modsecurity_enabled is enabled' do context 'when modsecurity_enabled is enabled' do
before do before do
allow(subject).to receive(:cluster).and_return(cluster)
allow(subject).to receive(:modsecurity_enabled).and_return(true) allow(subject).to receive(:modsecurity_enabled).and_return(true)
end end
...@@ -154,8 +151,24 @@ describe Clusters::Applications::Ingress do ...@@ -154,8 +151,24 @@ describe Clusters::Applications::Ingress do
expect(subject.values).to include("enable-modsecurity: 'true'") expect(subject.values).to include("enable-modsecurity: 'true'")
end end
it 'includes modsecurity core ruleset enablement' do it 'includes modsecurity core ruleset enablement set to false' do
expect(subject.values).to include("enable-owasp-modsecurity-crs: 'true'") expect(subject.values).to include("enable-owasp-modsecurity-crs: 'false'")
end
it 'includes modsecurity snippet with information related to security rules' do
expect(subject.values).to include("SecRuleEngine DetectionOnly")
expect(subject.values).to include("Include #{described_class::MODSECURITY_OWASP_RULES_FILE}")
end
context 'when modsecurity_mode is set to :blocking' do
before do
subject.blocking!
end
it 'includes modsecurity snippet with information related to security rules' do
expect(subject.values).to include("SecRuleEngine On")
expect(subject.values).to include("Include #{described_class::MODSECURITY_OWASP_RULES_FILE}")
end
end end
it 'includes modsecurity.conf content' do it 'includes modsecurity.conf content' do
...@@ -176,7 +189,6 @@ describe Clusters::Applications::Ingress do ...@@ -176,7 +189,6 @@ describe Clusters::Applications::Ingress do
context 'when modsecurity_enabled is disabled' do context 'when modsecurity_enabled is disabled' do
before do before do
allow(subject).to receive(:cluster).and_return(cluster)
allow(subject).to receive(:modsecurity_enabled).and_return(false) allow(subject).to receive(:modsecurity_enabled).and_return(false)
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