summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-06-30 11:42:01 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-06-30 11:42:10 +0000
commit9e4089e7e30c0634eb4e308dae1c6a002f3bd62f (patch)
treef151914ef968efc85be7e7658941e16470ad6642
parent8f561611517aa1f62e7100b549ec580981c05140 (diff)
downloadgitlab-ce-9e4089e7e30c0634eb4e308dae1c6a002f3bd62f.tar.gz
Add latest changes from gitlab-org/security/gitlab@13-11-stable-ee
-rw-r--r--app/assets/javascripts/behaviors/markdown/copy_as_gfm.js3
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js24
-rw-r--r--app/assets/javascripts/releases/components/app_edit_new.vue24
-rw-r--r--app/models/audit_event.rb11
-rw-r--r--app/models/user.rb11
-rw-r--r--app/services/feature_flags/base_service.rb6
-rw-r--r--app/services/feature_flags/create_service.rb3
-rw-r--r--app/services/feature_flags/destroy_service.rb2
-rw-r--r--app/services/feature_flags/update_service.rb12
-rw-r--r--spec/features/snippets/notes_on_personal_snippets_spec.rb12
-rw-r--r--spec/frontend/behaviors/copy_as_gfm_spec.js48
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js34
-rw-r--r--spec/frontend/releases/components/app_edit_new_spec.js45
-rw-r--r--spec/models/audit_event_spec.rb12
-rw-r--r--spec/models/user_spec.rb21
-rw-r--r--spec/services/feature_flags/create_service_spec.rb12
-rw-r--r--spec/services/feature_flags/destroy_service_spec.rb2
-rw-r--r--spec/services/feature_flags/update_service_spec.rb28
18 files changed, 220 insertions, 90 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
index 9a8af79210e..19ebab36481 100644
--- a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { sanitize } from '~/lib/dompurify';
import { getSelectedFragment, insertText } from '~/lib/utils/common_utils';
export class CopyAsGFM {
@@ -69,7 +70,7 @@ export class CopyAsGFM {
} else {
// Due to the async copy call we are not able to produce gfm so we transform the cached HTML
const div = document.createElement('div');
- div.innerHTML = gfmHtml;
+ div.innerHTML = sanitize(gfmHtml);
CopyAsGFM.nodeToGFM(div)
.then((transformedGfm) => {
CopyAsGFM.insertPastedText(e.target, text, transformedGfm);
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 5b3aa3cf9dc..5ef39ded9cb 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -535,3 +535,27 @@ export function getURLOrigin(url) {
return null;
}
}
+
+/**
+ * Returns `true` if the given `url` resolves to the same origin the page is served
+ * from; otherwise, returns `false`.
+ *
+ * The `url` may be absolute or relative.
+ *
+ * @param {string} url The URL to check.
+ * @returns {boolean}
+ */
+export function isSameOriginUrl(url) {
+ if (typeof url !== 'string') {
+ return false;
+ }
+
+ const { origin } = window.location;
+
+ try {
+ return new URL(url, origin).origin === origin;
+ } catch {
+ // Invalid URLs cannot have the same origin
+ return false;
+ }
+}
diff --git a/app/assets/javascripts/releases/components/app_edit_new.vue b/app/assets/javascripts/releases/components/app_edit_new.vue
index aecd0d6371e..3a989fef8de 100644
--- a/app/assets/javascripts/releases/components/app_edit_new.vue
+++ b/app/assets/javascripts/releases/components/app_edit_new.vue
@@ -1,7 +1,14 @@
<script>
-import { GlButton, GlFormInput, GlFormGroup, GlSprintf } from '@gitlab/ui';
+import {
+ GlButton,
+ GlFormInput,
+ GlFormGroup,
+ GlSafeLinkDirective as SafeLink,
+ GlSprintf,
+} from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex';
import { getParameterByName } from '~/lib/utils/common_utils';
+import { isSameOriginUrl } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import MilestoneCombobox from '~/milestones/components/milestone_combobox.vue';
import { BACK_URL_PARAM } from '~/releases/constants';
@@ -21,6 +28,9 @@ export default {
MilestoneCombobox,
TagField,
},
+ directives: {
+ SafeLink,
+ },
computed: {
...mapState('editNew', [
'isFetchingRelease',
@@ -65,7 +75,13 @@ export default {
},
},
cancelPath() {
- return getParameterByName(BACK_URL_PARAM) || this.releasesPagePath;
+ const backUrl = getParameterByName(BACK_URL_PARAM);
+
+ if (isSameOriginUrl(backUrl)) {
+ return backUrl;
+ }
+
+ return this.releasesPagePath;
},
saveButtonLabel() {
return this.isExistingRelease ? __('Save changes') : __('Create release');
@@ -186,7 +202,9 @@ export default {
>
{{ saveButtonLabel }}
</gl-button>
- <gl-button :href="cancelPath" class="js-cancel-button">{{ __('Cancel') }}</gl-button>
+ <gl-button v-safe-link :href="cancelPath" class="js-cancel-button">{{
+ __('Cancel')
+ }}</gl-button>
</div>
</form>
</div>
diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb
index 32c9d44f836..1ec7b4f1850 100644
--- a/app/models/audit_event.rb
+++ b/app/models/audit_event.rb
@@ -32,6 +32,9 @@ class AuditEvent < ApplicationRecord
scope :by_author_id, -> (author_id) { where(author_id: author_id) }
after_initialize :initialize_details
+
+ before_validation :sanitize_message
+
# Note: The intention is to remove this once refactoring of AuditEvent
# has proceeded further.
#
@@ -83,6 +86,14 @@ class AuditEvent < ApplicationRecord
private
+ def sanitize_message
+ message = details[:custom_message]
+
+ return unless message
+
+ self.details = details.merge(custom_message: Sanitize.clean(message))
+ end
+
def default_author_value
::Gitlab::Audit::NullAuthor.for(author_id, (self[:author_name] || details[:author_name]))
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 507e8cc2cf5..2736bbc10a2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1223,12 +1223,23 @@ class User < ApplicationRecord
end
def sanitize_attrs
+ sanitize_links
+ sanitize_name
+ end
+
+ def sanitize_links
%i[skype linkedin twitter].each do |attr|
value = self[attr]
self[attr] = Sanitize.clean(value) if value.present?
end
end
+ def sanitize_name
+ return unless self.name
+
+ self.name = self.name.gsub(%r{</?[^>]*>}, '')
+ end
+
def set_notification_email
if notification_email.blank? || all_emails.exclude?(notification_email)
self.notification_email = email
diff --git a/app/services/feature_flags/base_service.rb b/app/services/feature_flags/base_service.rb
index f48f95e2550..d041703803b 100644
--- a/app/services/feature_flags/base_service.rb
+++ b/app/services/feature_flags/base_service.rb
@@ -49,9 +49,9 @@ module FeatureFlags
end
def created_scope_message(scope)
- "Created rule <strong>#{scope.environment_scope}</strong> "\
- "and set it as <strong>#{scope.active ? "active" : "inactive"}</strong> "\
- "with strategies <strong>#{scope.strategies}</strong>."
+ "Created rule #{scope.environment_scope} "\
+ "and set it as #{scope.active ? "active" : "inactive"} "\
+ "with strategies #{scope.strategies}."
end
def feature_flag_by_name
diff --git a/app/services/feature_flags/create_service.rb b/app/services/feature_flags/create_service.rb
index de3a55d10fc..5c87af561d5 100644
--- a/app/services/feature_flags/create_service.rb
+++ b/app/services/feature_flags/create_service.rb
@@ -22,8 +22,7 @@ module FeatureFlags
private
def audit_message(feature_flag)
- message_parts = ["Created feature flag <strong>#{feature_flag.name}</strong>",
- "with description <strong>\"#{feature_flag.description}\"</strong>."]
+ message_parts = ["Created feature flag #{feature_flag.name} with description \"#{feature_flag.description}\"."]
message_parts += feature_flag.scopes.map do |scope|
created_scope_message(scope)
diff --git a/app/services/feature_flags/destroy_service.rb b/app/services/feature_flags/destroy_service.rb
index c77e3e03ec3..b131a349fc7 100644
--- a/app/services/feature_flags/destroy_service.rb
+++ b/app/services/feature_flags/destroy_service.rb
@@ -23,7 +23,7 @@ module FeatureFlags
end
def audit_message(feature_flag)
- "Deleted feature flag <strong>#{feature_flag.name}</strong>."
+ "Deleted feature flag #{feature_flag.name}."
end
def can_destroy?(feature_flag)
diff --git a/app/services/feature_flags/update_service.rb b/app/services/feature_flags/update_service.rb
index d956d4b3357..f5ab6f4005b 100644
--- a/app/services/feature_flags/update_service.rb
+++ b/app/services/feature_flags/update_service.rb
@@ -45,14 +45,14 @@ module FeatureFlags
return if changes.empty?
- "Updated feature flag <strong>#{feature_flag.name}</strong>. " + changes.join(" ")
+ "Updated feature flag #{feature_flag.name}. " + changes.join(" ")
end
def changed_attributes_messages(feature_flag)
feature_flag.changes.slice(*AUDITABLE_ATTRIBUTES).map do |attribute_name, changes|
"Updated #{attribute_name} "\
- "from <strong>\"#{changes.first}\"</strong> to "\
- "<strong>\"#{changes.second}\"</strong>."
+ "from \"#{changes.first}\" to "\
+ "\"#{changes.second}\"."
end
end
@@ -69,17 +69,17 @@ module FeatureFlags
end
def deleted_scope_message(scope)
- "Deleted rule <strong>#{scope.environment_scope}</strong>."
+ "Deleted rule #{scope.environment_scope}."
end
def updated_scope_message(scope)
changes = scope.changes.slice(*AUDITABLE_SCOPE_ATTRIBUTES_HUMAN_NAMES.keys)
return if changes.empty?
- message = "Updated rule <strong>#{scope.environment_scope}</strong> "
+ message = "Updated rule #{scope.environment_scope} "
message += changes.map do |attribute_name, change|
name = AUDITABLE_SCOPE_ATTRIBUTES_HUMAN_NAMES[attribute_name]
- "#{name} from <strong>#{change.first}</strong> to <strong>#{change.second}</strong>"
+ "#{name} from #{change.first} to #{change.second}"
end.join(' ')
message + '.'
diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb
index 47dad9bd88e..e03f71c5352 100644
--- a/spec/features/snippets/notes_on_personal_snippets_spec.rb
+++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb
@@ -65,18 +65,6 @@ RSpec.describe 'Comments on personal snippets', :js do
expect(page).to have_content(user_name)
end
end
-
- context 'when the author name contains HTML' do
- let(:user_name) { '<h1><a href="https://bad.link/malicious.exe" class="evil">Fake Content<img class="fake-icon" src="image.png"></a></h1>' }
-
- it 'renders the name as plain text' do
- visit snippet_path(snippet)
-
- content = find("#note_#{snippet_notes[0].id} .note-header-author-name").text
-
- expect(content).to eq user_name
- end
- end
end
context 'when submitting a note' do
diff --git a/spec/frontend/behaviors/copy_as_gfm_spec.js b/spec/frontend/behaviors/copy_as_gfm_spec.js
index acff990e84a..557b609f5f9 100644
--- a/spec/frontend/behaviors/copy_as_gfm_spec.js
+++ b/spec/frontend/behaviors/copy_as_gfm_spec.js
@@ -1,50 +1,54 @@
import initCopyAsGFM, { CopyAsGFM } from '~/behaviors/markdown/copy_as_gfm';
-import * as commonUtils from '~/lib/utils/common_utils';
describe('CopyAsGFM', () => {
describe('CopyAsGFM.pasteGFM', () => {
- function callPasteGFM() {
+ let target;
+
+ beforeEach(() => {
+ target = document.createElement('input');
+ target.value = 'This is code: ';
+ });
+
+ // When GFM code is copied, we put the regular plain text
+ // on the clipboard as `text/plain`, and the GFM as `text/x-gfm`.
+ // This emulates the behavior of `getData` with that data.
+ function callPasteGFM(data = { 'text/plain': 'code', 'text/x-gfm': '`code`' }) {
const e = {
originalEvent: {
clipboardData: {
getData(mimeType) {
- // When GFM code is copied, we put the regular plain text
- // on the clipboard as `text/plain`, and the GFM as `text/x-gfm`.
- // This emulates the behavior of `getData` with that data.
- if (mimeType === 'text/plain') {
- return 'code';
- }
- if (mimeType === 'text/x-gfm') {
- return '`code`';
- }
- return null;
+ return data[mimeType] || null;
},
},
},
preventDefault() {},
+ target,
};
CopyAsGFM.pasteGFM(e);
}
it('wraps pasted code when not already in code tags', () => {
- jest.spyOn(commonUtils, 'insertText').mockImplementation((el, textFunc) => {
- const insertedText = textFunc('This is code: ', '');
+ callPasteGFM();
- expect(insertedText).toEqual('`code`');
- });
+ expect(target.value).toBe('This is code: `code`');
+ });
+
+ it('does not wrap pasted code when already in code tags', () => {
+ target.value = 'This is code: `';
callPasteGFM();
+
+ expect(target.value).toBe('This is code: `code');
});
- it('does not wrap pasted code when already in code tags', () => {
- jest.spyOn(commonUtils, 'insertText').mockImplementation((el, textFunc) => {
- const insertedText = textFunc('This is code: `', '`');
+ it('does not allow xss in x-gfm-html', () => {
+ const testEl = document.createElement('div');
+ jest.spyOn(document, 'createElement').mockReturnValueOnce(testEl);
- expect(insertedText).toEqual('code');
- });
+ callPasteGFM({ 'text/plain': 'code', 'text/x-gfm-html': 'code<img/src/onerror=alert(1)>' });
- callPasteGFM();
+ expect(testEl.innerHTML).toBe('code<img src="">');
});
});
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index e12cd8b0e37..3b2852d08e6 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -1,3 +1,4 @@
+import { TEST_HOST } from 'helpers/test_constants';
import * as urlUtils from '~/lib/utils/url_utility';
const shas = {
@@ -921,4 +922,37 @@ describe('URL utility', () => {
expect(urlUtils.encodeSaferUrl(input)).toBe(input);
});
});
+
+ describe('isSameOriginUrl', () => {
+ // eslint-disable-next-line no-script-url
+ const javascriptUrl = 'javascript:alert(1)';
+
+ beforeEach(() => {
+ setWindowLocation({ origin: TEST_HOST });
+ });
+
+ it.each`
+ url | expected
+ ${TEST_HOST} | ${true}
+ ${`${TEST_HOST}/a/path`} | ${true}
+ ${'//test.host/no-protocol'} | ${true}
+ ${'/a/root/relative/path'} | ${true}
+ ${'a/relative/path'} | ${true}
+ ${'#hash'} | ${true}
+ ${'?param=foo'} | ${true}
+ ${''} | ${true}
+ ${'../../../'} | ${true}
+ ${`${TEST_HOST}:8080/wrong-port`} | ${false}
+ ${'ws://test.host/wrong-protocol'} | ${false}
+ ${'http://phishing.test'} | ${false}
+ ${'//phishing.test'} | ${false}
+ ${'//invalid:url'} | ${false}
+ ${javascriptUrl} | ${false}
+ ${'data:,Hello%2C%20World%21'} | ${false}
+ ${null} | ${false}
+ ${undefined} | ${false}
+ `('returns $expected given $url', ({ url, expected }) => {
+ expect(urlUtils.isSameOriginUrl(url)).toBe(expected);
+ });
+ });
});
diff --git a/spec/frontend/releases/components/app_edit_new_spec.js b/spec/frontend/releases/components/app_edit_new_spec.js
index 65ed6d6166f..748b48dacaa 100644
--- a/spec/frontend/releases/components/app_edit_new_spec.js
+++ b/spec/frontend/releases/components/app_edit_new_spec.js
@@ -4,6 +4,7 @@ import MockAdapter from 'axios-mock-adapter';
import { merge } from 'lodash';
import Vuex from 'vuex';
import { getJSONFixture } from 'helpers/fixtures';
+import { TEST_HOST } from 'helpers/test_constants';
import * as commonUtils from '~/lib/utils/common_utils';
import ReleaseEditNewApp from '~/releases/components/app_edit_new.vue';
import AssetLinksForm from '~/releases/components/asset_links_form.vue';
@@ -11,6 +12,7 @@ import { BACK_URL_PARAM } from '~/releases/constants';
const originalRelease = getJSONFixture('api/releases/release.json');
const originalMilestones = originalRelease.milestones;
+const releasesPagePath = 'path/to/releases/page';
describe('Release edit/new component', () => {
let wrapper;
@@ -24,7 +26,7 @@ describe('Release edit/new component', () => {
state = {
release,
markdownDocsPath: 'path/to/markdown/docs',
- releasesPagePath: 'path/to/releases/page',
+ releasesPagePath,
projectId: '8',
groupId: '42',
groupMilestonesAvailable: true,
@@ -75,6 +77,8 @@ describe('Release edit/new component', () => {
};
beforeEach(() => {
+ global.jsdom.reconfigure({ url: TEST_HOST });
+
mock = new MockAdapter(axios);
gon.api_version = 'v4';
@@ -146,22 +150,33 @@ describe('Release edit/new component', () => {
});
});
- describe(`when the URL contains a "${BACK_URL_PARAM}" parameter`, () => {
- const backUrl = 'https://example.gitlab.com/back/url';
-
- beforeEach(async () => {
- commonUtils.getParameterByName = jest
- .fn()
- .mockImplementation((paramToGet) => ({ [BACK_URL_PARAM]: backUrl }[paramToGet]));
+ // eslint-disable-next-line no-script-url
+ const xssBackUrl = 'javascript:alert(1)';
+ describe.each`
+ backUrl | expectedHref
+ ${`${TEST_HOST}/back/url`} | ${`${TEST_HOST}/back/url`}
+ ${`/back/url?page=2`} | ${`/back/url?page=2`}
+ ${`back/url?page=3`} | ${`back/url?page=3`}
+ ${'http://phishing.test/back/url'} | ${releasesPagePath}
+ ${'//phishing.test/back/url'} | ${releasesPagePath}
+ ${xssBackUrl} | ${releasesPagePath}
+ `(
+ `when the URL contains a "${BACK_URL_PARAM}=$backUrl" parameter`,
+ ({ backUrl, expectedHref }) => {
+ beforeEach(async () => {
+ global.jsdom.reconfigure({
+ url: `${TEST_HOST}?${BACK_URL_PARAM}=${encodeURIComponent(backUrl)}`,
+ });
- await factory();
- });
+ await factory();
+ });
- it('renders a "Cancel" button with an href pointing to the main Releases page', () => {
- const cancelButton = wrapper.find('.js-cancel-button');
- expect(cancelButton.attributes().href).toBe(backUrl);
- });
- });
+ it(`renders a "Cancel" button with an href pointing to ${expectedHref}`, () => {
+ const cancelButton = wrapper.find('.js-cancel-button');
+ expect(cancelButton.attributes().href).toBe(expectedHref);
+ });
+ },
+ );
describe('when creating a new release', () => {
beforeEach(async () => {
diff --git a/spec/models/audit_event_spec.rb b/spec/models/audit_event_spec.rb
index 5c87c2e68db..bc603bc5ab6 100644
--- a/spec/models/audit_event_spec.rb
+++ b/spec/models/audit_event_spec.rb
@@ -3,9 +3,6 @@
require 'spec_helper'
RSpec.describe AuditEvent do
- let_it_be(:audit_event) { create(:project_audit_event) }
- subject { audit_event }
-
describe 'validations' do
include_examples 'validates IP address' do
let(:attribute) { :ip_address }
@@ -13,6 +10,15 @@ RSpec.describe AuditEvent do
end
end
+ it 'sanitizes custom_message in the details hash' do
+ audit_event = create(:project_audit_event, details: { target_id: 678, custom_message: '<strong>Arnold</strong>' })
+
+ expect(audit_event.details).to include(
+ target_id: 678,
+ custom_message: 'Arnold'
+ )
+ end
+
describe '#as_json' do
context 'ip_address' do
subject { build(:group_audit_event, ip_address: '192.168.1.1').as_json }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 3abf2a651a0..51132e92be4 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2819,7 +2819,7 @@ RSpec.describe User do
end
describe '#sanitize_attrs' do
- let(:user) { build(:user, name: 'test & user', skype: 'test&user') }
+ let(:user) { build(:user, name: 'test <& user', skype: 'test&user') }
it 'encodes HTML entities in the Skype attribute' do
expect { user.sanitize_attrs }.to change { user.skype }.to('test&amp;user')
@@ -2828,6 +2828,25 @@ RSpec.describe User do
it 'does not encode HTML entities in the name attribute' do
expect { user.sanitize_attrs }.not_to change { user.name }
end
+
+ it 'sanitizes attr from html tags' do
+ user = create(:user, name: '<a href="//example.com">Test<a>', twitter: '<a href="//evil.com">https://twitter.com<a>')
+
+ expect(user.name).to eq('Test')
+ expect(user.twitter).to eq('https://twitter.com')
+ end
+
+ it 'sanitizes attr from js scripts' do
+ user = create(:user, name: '<script>alert("Test")</script>')
+
+ expect(user.name).to eq("alert(\"Test\")")
+ end
+
+ it 'sanitizes attr from iframe scripts' do
+ user = create(:user, name: 'User"><iframe src=javascript:alert()><iframe>')
+
+ expect(user.name).to eq('User">')
+ end
end
describe '#starred?' do
diff --git a/spec/services/feature_flags/create_service_spec.rb b/spec/services/feature_flags/create_service_spec.rb
index 128fab114fe..1aa14d5e000 100644
--- a/spec/services/feature_flags/create_service_spec.rb
+++ b/spec/services/feature_flags/create_service_spec.rb
@@ -67,12 +67,12 @@ RSpec.describe FeatureFlags::CreateService do
end
it 'creates audit event' do
- expected_message = 'Created feature flag <strong>feature_flag</strong> '\
- 'with description <strong>"description"</strong>. '\
- 'Created rule <strong>*</strong> and set it as <strong>active</strong> '\
- 'with strategies <strong>[{"name"=>"default", "parameters"=>{}}]</strong>. '\
- 'Created rule <strong>production</strong> and set it as <strong>inactive</strong> '\
- 'with strategies <strong>[{"name"=>"default", "parameters"=>{}}]</strong>.'
+ expected_message = 'Created feature flag feature_flag '\
+ 'with description "description". '\
+ 'Created rule * and set it as active '\
+ 'with strategies [{"name"=&gt;"default", "parameters"=&gt;{}}]. '\
+ 'Created rule production and set it as inactive '\
+ 'with strategies [{"name"=&gt;"default", "parameters"=&gt;{}}].'
expect { subject }.to change { AuditEvent.count }.by(1)
expect(AuditEvent.last.details[:custom_message]).to eq(expected_message)
diff --git a/spec/services/feature_flags/destroy_service_spec.rb b/spec/services/feature_flags/destroy_service_spec.rb
index b35de02c628..2dd7bc2d13c 100644
--- a/spec/services/feature_flags/destroy_service_spec.rb
+++ b/spec/services/feature_flags/destroy_service_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe FeatureFlags::DestroyService do
it 'creates audit log' do
expect { subject }.to change { AuditEvent.count }.by(1)
- expect(audit_event_message).to eq("Deleted feature flag <strong>#{feature_flag.name}</strong>.")
+ expect(audit_event_message).to eq("Deleted feature flag #{feature_flag.name}.")
end
context 'when user is reporter' do
diff --git a/spec/services/feature_flags/update_service_spec.rb b/spec/services/feature_flags/update_service_spec.rb
index 9639cf3081d..9d9f59dd46c 100644
--- a/spec/services/feature_flags/update_service_spec.rb
+++ b/spec/services/feature_flags/update_service_spec.rb
@@ -37,9 +37,9 @@ RSpec.describe FeatureFlags::UpdateService do
expect { subject }.to change { AuditEvent.count }.by(1)
expect(audit_event_message).to(
- eq("Updated feature flag <strong>new_name</strong>. "\
- "Updated name from <strong>\"#{name_was}\"</strong> "\
- "to <strong>\"new_name\"</strong>.")
+ eq("Updated feature flag new_name. "\
+ "Updated name from \"#{name_was}\" "\
+ "to \"new_name\".")
)
end
@@ -93,8 +93,8 @@ RSpec.describe FeatureFlags::UpdateService do
it 'creates audit event with changed description' do
expect { subject }.to change { AuditEvent.count }.by(1)
expect(audit_event_message).to(
- include("Updated description from <strong>\"\"</strong>"\
- " to <strong>\"new description\"</strong>.")
+ include("Updated description from \"\""\
+ " to \"new description\".")
)
end
end
@@ -109,7 +109,7 @@ RSpec.describe FeatureFlags::UpdateService do
it 'creates audit event about changing active state' do
expect { subject }.to change { AuditEvent.count }.by(1)
expect(audit_event_message).to(
- include('Updated active from <strong>"true"</strong> to <strong>"false"</strong>.')
+ include('Updated active from "true" to "false".')
)
end
@@ -131,8 +131,8 @@ RSpec.describe FeatureFlags::UpdateService do
it 'creates audit event about changing active state' do
expect { subject }.to change { AuditEvent.count }.by(1)
expect(audit_event_message).to(
- include("Updated rule <strong>*</strong> active state "\
- "from <strong>true</strong> to <strong>false</strong>.")
+ include("Updated rule * active state "\
+ "from true to false.")
)
end
end
@@ -148,8 +148,8 @@ RSpec.describe FeatureFlags::UpdateService do
it 'creates audit event with changed name' do
expect { subject }.to change { AuditEvent.count }.by(1)
expect(audit_event_message).to(
- include("Updated rule <strong>staging</strong> environment scope "\
- "from <strong>review</strong> to <strong>staging</strong>.")
+ include("Updated rule staging environment scope "\
+ "from review to staging.")
)
end
@@ -184,7 +184,7 @@ RSpec.describe FeatureFlags::UpdateService do
it 'creates audit event with deleted scope' do
expect { subject }.to change { AuditEvent.count }.by(1)
- expect(audit_event_message).to include("Deleted rule <strong>review</strong>.")
+ expect(audit_event_message).to include("Deleted rule review.")
end
context 'when scope can not be deleted' do
@@ -209,8 +209,8 @@ RSpec.describe FeatureFlags::UpdateService do
end
it 'creates audit event with new scope' do
- expected = 'Created rule <strong>review</strong> and set it as <strong>active</strong> '\
- 'with strategies <strong>[{"name"=>"default", "parameters"=>{}}]</strong>.'
+ expected = 'Created rule review and set it as active '\
+ 'with strategies [{"name"=&gt;"default", "parameters"=&gt;{}}].'
subject
@@ -259,7 +259,7 @@ RSpec.describe FeatureFlags::UpdateService do
end
it 'creates an audit event' do
- expected = %r{Updated rule <strong>sandbox</strong> strategies from <strong>.*</strong> to <strong>.*</strong>.}
+ expected = %r{Updated rule sandbox strategies from .* to .*.}
expect { subject }.to change { AuditEvent.count }.by(1)
expect(audit_event_message).to match(expected)