Commit 52dd7168 authored by Thong Kuah's avatar Thong Kuah

Merge branch '64023-disable-recaptcha' into 'master'

Add feature flag for disabling reCaptcha

See merge request gitlab-org/gitlab!17604
parents cde4a645 ec82bf09
...@@ -80,4 +80,9 @@ module Spammable ...@@ -80,4 +80,9 @@ module Spammable
def check_for_spam? def check_for_spam?
true true
end end
# Override in Spammable if differs
def allow_possible_spam?
Feature.enabled?(:allow_possible_spam, project)
end
end end
...@@ -14,6 +14,7 @@ class Snippet < ApplicationRecord ...@@ -14,6 +14,7 @@ class Snippet < ApplicationRecord
include Editable include Editable
include Gitlab::SQL::Pattern include Gitlab::SQL::Pattern
include FromUnion include FromUnion
extend ::Gitlab::Utils::Override
cache_markdown_field :title, pipeline: :single_line cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :description cache_markdown_field :description
...@@ -191,6 +192,12 @@ class Snippet < ApplicationRecord ...@@ -191,6 +192,12 @@ class Snippet < ApplicationRecord
(public? && (title_changed? || content_changed?)) (public? && (title_changed? || content_changed?))
end end
# snippers are the biggest sources of spam
override :allow_possible_spam?
def allow_possible_spam?
false
end
def spammable_entity_type def spammable_entity_type
'snippet' 'snippet'
end end
......
...@@ -37,7 +37,8 @@ class SpamService ...@@ -37,7 +37,8 @@ class SpamService
else else
# Otherwise, it goes to Akismet and check if it's a spam. If that's the # Otherwise, it goes to Akismet and check if it's a spam. If that's the
# case, it assigns spammable record as "spam" and create a SpamLog record. # case, it assigns spammable record as "spam" and create a SpamLog record.
spammable.spam = check(api) possible_spam = check(api)
spammable.spam = possible_spam unless spammable.allow_possible_spam?
spammable.spam_log = spam_log spammable.spam_log = spam_log
end end
end end
......
...@@ -408,6 +408,7 @@ describe Projects::IssuesController do ...@@ -408,6 +408,7 @@ describe Projects::IssuesController do
context 'when user has access to update issue' do context 'when user has access to update issue' do
before do before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
project.add_developer(user) project.add_developer(user)
end end
...@@ -421,14 +422,30 @@ describe Projects::IssuesController do ...@@ -421,14 +422,30 @@ describe Projects::IssuesController do
context 'when Akismet is enabled and the issue is identified as spam' do context 'when Akismet is enabled and the issue is identified as spam' do
before do before do
stub_application_setting(recaptcha_enabled: true) stub_application_setting(recaptcha_enabled: true)
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true) expect_next_instance_of(AkismetService) do |akismet_service|
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true) expect(akismet_service).to receive_messages(spam?: true)
end
end
context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
end
it 'renders json with recaptcha_html' do
subject
expect(json_response).to have_key('recaptcha_html')
end
end end
it 'renders json with recaptcha_html' do context 'when allow_possible_spam feature flag is true' do
subject it 'updates the issue' do
subject
expect(json_response).to have_key('recaptcha_html') expect(response).to have_http_status(:ok)
expect(issue.reload.title).to eq('New title')
end
end end
end end
end end
...@@ -681,13 +698,13 @@ describe Projects::IssuesController do ...@@ -681,13 +698,13 @@ describe Projects::IssuesController do
before do before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
stub_application_setting(recaptcha_enabled: true) stub_application_setting(recaptcha_enabled: true)
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true)
end end
context 'when an issue is not identified as spam' do context 'when an issue is not identified as spam' do
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) expect_next_instance_of(AkismetService) do |akismet_service|
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(false) expect(akismet_service).to receive_messages(spam?: false)
end
end end
it 'normally updates the issue' do it 'normally updates the issue' do
...@@ -696,45 +713,64 @@ describe Projects::IssuesController do ...@@ -696,45 +713,64 @@ describe Projects::IssuesController do
end end
context 'when an issue is identified as spam' do context 'when an issue is identified as spam' do
before do
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
end
context 'when captcha is not verified' do context 'when captcha is not verified' do
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end end
it 'rejects an issue recognized as a spam' do context 'when allow_possible_spam feature flag is false' do
expect { update_issue }.not_to change { issue.reload.title } before do
end stub_feature_flags(allow_possible_spam: false)
end
it 'rejects an issue recognized as a spam when recaptcha disabled' do it 'rejects an issue recognized as a spam' do
stub_application_setting(recaptcha_enabled: false) expect { update_issue }.not_to change { issue.reload.title }
end
expect { update_issue }.not_to change { issue.reload.title } it 'rejects an issue recognized as a spam when recaptcha disabled' do
end stub_application_setting(recaptcha_enabled: false)
it 'creates a spam log' do expect { update_issue }.not_to change { issue.reload.title }
update_issue(issue_params: { title: 'Spam title' }) end
spam_logs = SpamLog.all it 'creates a spam log' do
expect { update_issue(issue_params: { title: 'Spam title' }) }
.to log_spam(title: 'Spam title', noteable_type: 'Issue')
end
expect(spam_logs.count).to eq(1) it 'renders recaptcha_html json response' do
expect(spam_logs.first.title).to eq('Spam title') update_issue
expect(spam_logs.first.recaptcha_verified).to be_falsey
end expect(json_response).to have_key('recaptcha_html')
end
it 'renders recaptcha_html json response' do it 'returns 200 status' do
update_issue update_issue
expect(json_response).to have_key('recaptcha_html') expect(response).to have_gitlab_http_status(200)
end
end end
it 'returns 200 status' do context 'when allow_possible_spam feature flag is true' do
update_issue it 'updates the issue recognized as spam' do
expect { update_issue }.to change { issue.reload.title }
end
expect(response).to have_gitlab_http_status(200) it 'creates a spam log' do
expect { update_issue(issue_params: { title: 'Spam title' }) }
.to log_spam(
title: 'Spam title', description: issue.description,
noteable_type: 'Issue', recaptcha_verified: false
)
end
it 'returns 200 status' do
update_issue
expect(response).to have_gitlab_http_status(200)
end
end end
end end
...@@ -748,11 +784,6 @@ describe Projects::IssuesController do ...@@ -748,11 +784,6 @@ describe Projects::IssuesController do
additional_params: { spam_log_id: spam_logs.last.id, recaptcha_verification: true }) additional_params: { spam_log_id: spam_logs.last.id, recaptcha_verification: true })
end end
before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha)
.and_return(true)
end
it 'returns 200 status' do it 'returns 200 status' do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
end end
...@@ -917,55 +948,72 @@ describe Projects::IssuesController do ...@@ -917,55 +948,72 @@ describe Projects::IssuesController do
context 'Akismet is enabled' do context 'Akismet is enabled' do
before do before do
stub_application_setting(recaptcha_enabled: true) stub_application_setting(recaptcha_enabled: true)
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true)
end end
context 'when an issue is not identified as spam' do context 'when an issue is not identified as spam' do
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) stub_feature_flags(allow_possible_spam: false)
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(false)
expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: false)
end
end end
it 'does not create an issue' do it 'creates an issue' do
expect { post_new_issue(title: '') }.not_to change(Issue, :count) expect { post_new_issue(title: 'Some title') }.to change(Issue, :count)
end end
end end
context 'when an issue is identified as spam' do context 'when an issue is identified as spam' do
before do
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
end
context 'when captcha is not verified' do context 'when captcha is not verified' do
def post_spam_issue def post_spam_issue
post_new_issue(title: 'Spam Title', description: 'Spam lives here') post_new_issue(title: 'Spam Title', description: 'Spam lives here')
end end
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end end
it 'rejects an issue recognized as a spam' do context 'when allow_possible_spam feature flag is false' do
expect { post_spam_issue }.not_to change(Issue, :count) before do
end stub_feature_flags(allow_possible_spam: false)
end
it 'creates a spam log' do it 'rejects an issue recognized as a spam' do
post_spam_issue expect { post_spam_issue }.not_to change(Issue, :count)
spam_logs = SpamLog.all end
expect(spam_logs.count).to eq(1) it 'creates a spam log' do
expect(spam_logs.first.title).to eq('Spam Title') expect { post_spam_issue }
expect(spam_logs.first.recaptcha_verified).to be_falsey .to log_spam(title: 'Spam Title', noteable_type: 'Issue', recaptcha_verified: false)
end end
it 'does not create an issue when it is not valid' do it 'does not create an issue when it is not valid' do
expect { post_new_issue(title: '') }.not_to change(Issue, :count) expect { post_new_issue(title: '') }.not_to change(Issue, :count)
end
it 'does not create an issue when recaptcha is not enabled' do
stub_application_setting(recaptcha_enabled: false)
expect { post_spam_issue }.not_to change(Issue, :count)
end
end end
it 'does not create an issue when recaptcha is not enabled' do context 'when allow_possible_spam feature flag is true' do
stub_application_setting(recaptcha_enabled: false) it 'creates an issue recognized as spam' do
expect { post_spam_issue }.to change(Issue, :count)
end
expect { post_spam_issue }.not_to change(Issue, :count) it 'creates a spam log' do
expect { post_spam_issue }
.to log_spam(title: 'Spam Title', noteable_type: 'Issue', recaptcha_verified: false)
end
it 'does not create an issue when it is not valid' do
expect { post_new_issue(title: '') }.not_to change(Issue, :count)
end
end end
end end
...@@ -977,7 +1025,7 @@ describe Projects::IssuesController do ...@@ -977,7 +1025,7 @@ describe Projects::IssuesController do
end end
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(true) expect(controller).to receive_messages(verify_recaptcha: true)
end end
it 'accepts an issue after recaptcha is verified' do it 'accepts an issue after recaptcha is verified' do
...@@ -1030,8 +1078,12 @@ describe Projects::IssuesController do ...@@ -1030,8 +1078,12 @@ describe Projects::IssuesController do
describe 'POST #mark_as_spam' do describe 'POST #mark_as_spam' do
context 'properly submits to Akismet' do context 'properly submits to Akismet' do
before do before do
allow_any_instance_of(AkismetService).to receive_messages(submit_spam: true) expect_next_instance_of(AkismetService) do |akismet_service|
allow_any_instance_of(ApplicationSetting).to receive_messages(akismet_enabled: true) expect(akismet_service).to receive_messages(submit_spam: true)
end
expect_next_instance_of(ApplicationSetting) do |setting|
expect(setting).to receive_messages(akismet_enabled: true)
end
end end
def post_spam def post_spam
...@@ -1266,7 +1318,9 @@ describe Projects::IssuesController do ...@@ -1266,7 +1318,9 @@ describe Projects::IssuesController do
end end
it "shows error when upload fails" do it "shows error when upload fails" do
allow_any_instance_of(UploadService).to receive(:execute).and_return(nil) expect_next_instance_of(UploadService) do |upload_service|
expect(upload_service).to receive(:execute).and_return(nil)
end
import_csv import_csv
......
...@@ -111,7 +111,7 @@ describe Projects::SnippetsController do ...@@ -111,7 +111,7 @@ describe Projects::SnippetsController do
it 'creates a spam log' do it 'creates a spam log' do
expect { create_snippet(project, visibility_level: Snippet::PUBLIC) } expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Title', user_id: user.id, noteable_type: 'ProjectSnippet')
end end
it 'renders :new with recaptcha disabled' do it 'renders :new with recaptcha disabled' do
...@@ -192,7 +192,7 @@ describe Projects::SnippetsController do ...@@ -192,7 +192,7 @@ describe Projects::SnippetsController do
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo') } expect { update_snippet(title: 'Foo') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet')
end end
it 'renders :edit with recaptcha disabled' do it 'renders :edit with recaptcha disabled' do
...@@ -237,7 +237,7 @@ describe Projects::SnippetsController do ...@@ -237,7 +237,7 @@ describe Projects::SnippetsController do
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) } expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet')
end end
it 'renders :edit with recaptcha disabled' do it 'renders :edit with recaptcha disabled' do
......
...@@ -269,7 +269,7 @@ describe SnippetsController do ...@@ -269,7 +269,7 @@ describe SnippetsController do
it 'creates a spam log' do it 'creates a spam log' do
expect { create_snippet(visibility_level: Snippet::PUBLIC) } expect { create_snippet(visibility_level: Snippet::PUBLIC) }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Title', user: user, noteable_type: 'PersonalSnippet')
end end
it 'renders :new with recaptcha disabled' do it 'renders :new with recaptcha disabled' do
...@@ -345,7 +345,7 @@ describe SnippetsController do ...@@ -345,7 +345,7 @@ describe SnippetsController do
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) } expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user: user, noteable_type: 'PersonalSnippet')
end end
it 'renders :edit with recaptcha disabled' do it 'renders :edit with recaptcha disabled' do
...@@ -389,8 +389,8 @@ describe SnippetsController do ...@@ -389,8 +389,8 @@ describe SnippetsController do
end end
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo') } expect {update_snippet(title: 'Foo') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user: user, noteable_type: 'PersonalSnippet')
end end
it 'renders :edit with recaptcha disabled' do it 'renders :edit with recaptcha disabled' do
......
...@@ -30,21 +30,47 @@ describe 'New issue', :js do ...@@ -30,21 +30,47 @@ describe 'New issue', :js do
visit new_project_issue_path(project) visit new_project_issue_path(project)
end end
it 'creates an issue after solving reCaptcha' do context 'when allow_possible_spam feature flag is false' do
fill_in 'issue_title', with: 'issue title' before do
fill_in 'issue_description', with: 'issue description' stub_feature_flags(allow_possible_spam: false)
end
click_button 'Submit issue' it 'creates an issue after solving reCaptcha' do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
# it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha click_button 'Submit issue'
# recaptcha verification is skipped in test environment and it always returns true
expect(page).not_to have_content('issue title')
expect(page).to have_css('.recaptcha')
click_button 'Submit issue' # it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha
# recaptcha verification is skipped in test environment and it always returns true
expect(page).not_to have_content('issue title')
expect(page).to have_css('.recaptcha')
expect(page.find('.issue-details h2.title')).to have_content('issue title') click_button 'Submit issue'
expect(page.find('.issue-details .description')).to have_content('issue description')
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
end
context 'when allow_possible_spam feature flag is true' do
before do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
end
it 'creates an issue without a need to solve reCaptcha' do
click_button 'Submit issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
it 'creates a spam log record' do
expect { click_button 'Submit issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe 'User creates snippet', :js do
let(:user) { create(:user) }
before do
stub_feature_flags(allow_possible_spam: false)
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
Gitlab::CurrentSettings.update!(
akismet_enabled: true,
akismet_api_key: 'testkey',
recaptcha_enabled: true,
recaptcha_site_key: 'test site key',
recaptcha_private_key: 'test private key'
)
sign_in(user)
visit new_snippet_path
fill_in 'personal_snippet_title', with: 'My Snippet Title'
fill_in 'personal_snippet_description', with: 'My Snippet **Description**'
find('#personal_snippet_visibility_level_20').set(true)
page.within('.file-editor') do
find('.ace_text-input', visible: false).send_keys 'Hello World!'
end
end
shared_examples 'solve recaptcha' do
it 'creates a snippet after solving reCaptcha' do
click_button('Create snippet')
wait_for_requests
# it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha
# recaptcha verification is skipped in test environment and it always returns true
expect(page).not_to have_content('My Snippet Title')
expect(page).to have_css('.recaptcha')
click_button('Submit personal snippet')
expect(page).to have_content('My Snippet Title')
end
end
context 'when identified as a spam' do
before do
WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: "true", status: 200)
end
context 'when allow_possible_spam feature flag is false' do
it_behaves_like 'solve recaptcha'
end
context 'when allow_possible_spam feature flag is true' do
it_behaves_like 'solve recaptcha'
end
end
context 'when not identified as a spam' do
before do
WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: "false", status: 200)
end
it 'creates a snippet' do
click_button('Create snippet')
wait_for_requests
expect(page).not_to have_css('.recaptcha')
expect(page).to have_content('My Snippet Title')
end
end
end
...@@ -374,9 +374,17 @@ describe API::Issues do ...@@ -374,9 +374,17 @@ describe API::Issues do
end end
describe 'POST /projects/:id/issues with spam filtering' do describe 'POST /projects/:id/issues with spam filtering' do
def post_issue
post api("/projects/#{project.id}/issues", user), params: params
end
before do before do
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true) expect_next_instance_of(SpamService) do |spam_service|
allow_any_instance_of(AkismetService).to receive_messages(spam?: true) expect(spam_service).to receive_messages(check_for_spam?: true)
end
expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end end
let(:params) do let(:params) do
...@@ -387,17 +395,43 @@ describe API::Issues do ...@@ -387,17 +395,43 @@ describe API::Issues do
} }
end end
it 'does not create a new project issue' do context 'when allow_possible_spam feature flag is false' do
expect { post api("/projects/#{project.id}/issues", user), params: params }.not_to change(Issue, :count) before do
expect(response).to have_gitlab_http_status(400) stub_feature_flags(allow_possible_spam: false)
expect(json_response['message']).to eq({ 'error' => 'Spam detected' }) end
spam_logs = SpamLog.all it 'does not create a new project issue' do
expect(spam_logs.count).to eq(1) expect { post_issue }.not_to change(Issue, :count)
expect(spam_logs[0].title).to eq('new issue') end
expect(spam_logs[0].description).to eq('content here')
expect(spam_logs[0].user).to eq(user) it 'returns correct status and message' do
expect(spam_logs[0].noteable_type).to eq('Issue') post_issue
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']).to eq({ 'error' => 'Spam detected' })
end
it 'creates a new spam log entry' do
expect { post_issue }
.to log_spam(title: 'new issue', description: 'content here', user_id: user.id, noteable_type: 'Issue')
end
end
context 'when allow_possible_spam feature flag is true' do
it 'does creates a new project issue' do
expect { post_issue }.to change(Issue, :count).by(1)
end
it 'returns correct status' do
post_issue
expect(response).to have_gitlab_http_status(201)
end
it 'creates a new spam log entry' do
expect { post_issue }
.to log_spam(title: 'new issue', description: 'content here', user_id: user.id, noteable_type: 'Issue')
end
end end
end end
......
...@@ -181,6 +181,10 @@ describe API::Issues do ...@@ -181,6 +181,10 @@ describe API::Issues do
end end
describe 'PUT /projects/:id/issues/:issue_iid with spam filtering' do describe 'PUT /projects/:id/issues/:issue_iid with spam filtering' do
def update_issue
put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: params
end
let(:params) do let(:params) do
{ {
title: 'updated title', title: 'updated title',
...@@ -189,21 +193,52 @@ describe API::Issues do ...@@ -189,21 +193,52 @@ describe API::Issues do
} }
end end
it 'does not create a new project issue' do before do
allow_any_instance_of(SpamService).to receive_messages(check_for_spam?: true) expect_next_instance_of(SpamService) do |spam_service|
allow_any_instance_of(AkismetService).to receive_messages(spam?: true) expect(spam_service).to receive_messages(check_for_spam?: true)
end
expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end
put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: params context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
end
expect(response).to have_gitlab_http_status(400) it 'does not update a project issue' do
expect(json_response['message']).to eq({ 'error' => 'Spam detected' }) expect { update_issue }.not_to change { issue.reload.title }
end
spam_logs = SpamLog.all
expect(spam_logs.count).to eq(1) it 'returns correct status and message' do
expect(spam_logs[0].title).to eq('updated title') update_issue
expect(spam_logs[0].description).to eq('content here')
expect(spam_logs[0].user).to eq(user) expect(response).to have_gitlab_http_status(400)
expect(spam_logs[0].noteable_type).to eq('Issue') expect(json_response).to include('message' => { 'error' => 'Spam detected' })
end
it 'creates a new spam log entry' do
expect { update_issue }
.to log_spam(title: 'updated title', description: 'content here', user_id: user.id, noteable_type: 'Issue')
end
end
context 'when allow_possible_spam feature flag is true' do
it 'updates a project issue' do
expect { update_issue }.to change { issue.reload.title }
end
it 'returns correct status and message' do
update_issue
expect(response).to have_gitlab_http_status(200)
end
it 'creates a new spam log entry' do
expect { update_issue }
.to log_spam(title: 'updated title', description: 'content here', user_id: user.id, noteable_type: 'Issue')
end
end end
end end
......
...@@ -198,7 +198,7 @@ describe API::ProjectSnippets do ...@@ -198,7 +198,7 @@ describe API::ProjectSnippets do
it 'creates a spam log' do it 'creates a spam log' do
expect { create_snippet(project, visibility: 'public') } expect { create_snippet(project, visibility: 'public') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Test Title', user_id: user.id, noteable_type: 'ProjectSnippet')
end end
end end
end end
...@@ -289,7 +289,7 @@ describe API::ProjectSnippets do ...@@ -289,7 +289,7 @@ describe API::ProjectSnippets do
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo') } expect { update_snippet(title: 'Foo') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user_id: admin.id, noteable_type: 'ProjectSnippet')
end end
end end
...@@ -306,7 +306,7 @@ describe API::ProjectSnippets do ...@@ -306,7 +306,7 @@ describe API::ProjectSnippets do
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo', visibility: 'public') } expect { update_snippet(title: 'Foo', visibility: 'public') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user_id: admin.id, noteable_type: 'ProjectSnippet')
end end
end end
end end
......
...@@ -254,7 +254,7 @@ describe API::Snippets do ...@@ -254,7 +254,7 @@ describe API::Snippets do
it 'creates a spam log' do it 'creates a spam log' do
expect { create_snippet(visibility: 'public') } expect { create_snippet(visibility: 'public') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Test Title', user_id: user.id, noteable_type: 'PersonalSnippet')
end end
end end
end end
...@@ -344,8 +344,7 @@ describe API::Snippets do ...@@ -344,8 +344,7 @@ describe API::Snippets do
end end
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo') } expect { update_snippet(title: 'Foo') }.to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'PersonalSnippet')
.to change { SpamLog.count }.by(1)
end end
end end
...@@ -359,7 +358,7 @@ describe API::Snippets do ...@@ -359,7 +358,7 @@ describe API::Snippets do
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo', visibility: 'public') } expect { update_snippet(title: 'Foo', visibility: 'public') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'PersonalSnippet')
end end
end end
end end
......
...@@ -3,26 +3,28 @@ ...@@ -3,26 +3,28 @@
require 'spec_helper' require 'spec_helper'
describe CreateSnippetService do describe CreateSnippetService do
before do let(:user) { create(:user) }
@user = create :user let(:admin) { create(:user, :admin) }
@admin = create :user, admin: true let(:opts) { base_opts.merge(extra_opts) }
@opts = { let(:base_opts) do
{
title: 'Test snippet', title: 'Test snippet',
file_name: 'snippet.rb', file_name: 'snippet.rb',
content: 'puts "hello world"', content: 'puts "hello world"',
visibility_level: Gitlab::VisibilityLevel::PRIVATE visibility_level: Gitlab::VisibilityLevel::PRIVATE
} }
end end
let(:extra_opts) { {} }
context 'When public visibility is restricted' do context 'When public visibility is restricted' do
let(:extra_opts) { { visibility_level: Gitlab::VisibilityLevel::PUBLIC } }
before do before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
end end
it 'non-admins are not able to create a public snippet' do it 'non-admins are not able to create a public snippet' do
snippet = create_snippet(nil, @user, @opts) snippet = create_snippet(nil, user, opts)
expect(snippet.errors.messages).to have_key(:visibility_level) expect(snippet.errors.messages).to have_key(:visibility_level)
expect(snippet.errors.messages[:visibility_level].first).to( expect(snippet.errors.messages[:visibility_level].first).to(
match('has been restricted') match('has been restricted')
...@@ -30,37 +32,81 @@ describe CreateSnippetService do ...@@ -30,37 +32,81 @@ describe CreateSnippetService do
end end
it 'admins are able to create a public snippet' do it 'admins are able to create a public snippet' do
snippet = create_snippet(nil, @admin, @opts) snippet = create_snippet(nil, admin, opts)
expect(snippet.errors.any?).to be_falsey expect(snippet.errors.any?).to be_falsey
expect(snippet.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC) expect(snippet.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
end end
describe "when visibility level is passed as a string" do describe "when visibility level is passed as a string" do
let(:extra_opts) { { visibility: 'internal' } }
before do before do
@opts[:visibility] = 'internal' base_opts.delete(:visibility_level)
@opts.delete(:visibility_level)
end end
it "assigns the correct visibility level" do it "assigns the correct visibility level" do
snippet = create_snippet(nil, @user, @opts) snippet = create_snippet(nil, user, opts)
expect(snippet.errors.any?).to be_falsey expect(snippet.errors.any?).to be_falsey
expect(snippet.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) expect(snippet.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
end end
end end
end end
context 'checking spam' do
shared_examples 'marked as spam' do
let(:snippet) { create_snippet(nil, admin, opts) }
it 'marks a snippet as a spam ' do
expect(snippet).to be_spam
end
it 'invalidates the snippet' do
expect(snippet).to be_invalid
end
it 'creates a new spam_log' do
expect { snippet }
.to log_spam(title: snippet.title, noteable_type: 'PersonalSnippet')
end
it 'assigns a spam_log to an issue' do
expect(snippet.spam_log).to eq(SpamLog.last)
end
end
let(:extra_opts) do
{ visibility_level: Gitlab::VisibilityLevel::PUBLIC, request: double(:request, env: {}) }
end
before do
expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end
[true, false, nil].each do |allow_possible_spam|
context "when recaptcha_disabled flag is #{allow_possible_spam.inspect}" do
before do
stub_feature_flags(allow_possible_spam: allow_possible_spam) unless allow_possible_spam.nil?
end
it_behaves_like 'marked as spam'
end
end
end
describe 'usage counter' do describe 'usage counter' do
let(:counter) { Gitlab::UsageDataCounters::SnippetCounter } let(:counter) { Gitlab::UsageDataCounters::SnippetCounter }
it 'increments count' do it 'increments count' do
expect do expect do
create_snippet(nil, @admin, @opts) create_snippet(nil, admin, opts)
end.to change { counter.read(:create) }.by 1 end.to change { counter.read(:create) }.by 1
end end
it 'does not increment count if create fails' do it 'does not increment count if create fails' do
expect do expect do
create_snippet(nil, @admin, {}) create_snippet(nil, admin, {})
end.not_to change { counter.read(:create) } end.not_to change { counter.read(:create) }
end end
end end
......
...@@ -344,7 +344,7 @@ describe Issues::CreateService do ...@@ -344,7 +344,7 @@ describe Issues::CreateService do
end end
before do before do
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true) stub_feature_flags(allow_possible_spam: false)
end end
context 'when recaptcha was verified' do context 'when recaptcha was verified' do
...@@ -384,31 +384,67 @@ describe Issues::CreateService do ...@@ -384,31 +384,67 @@ describe Issues::CreateService do
end end
context 'when recaptcha was not verified' do context 'when recaptcha was not verified' do
before do
expect_next_instance_of(SpamService) do |spam_service|
expect(spam_service).to receive_messages(check_for_spam?: true)
end
end
context 'when akismet detects spam' do context 'when akismet detects spam' do
before do before do
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true) expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end end
it 'marks an issue as a spam ' do context 'when issuables_recaptcha_enabled feature flag is true' do
expect(issue).to be_spam it 'marks an issue as a spam ' do
end expect(issue).to be_spam
end
it 'an issue is not valid ' do it 'invalidates the issue' do
expect(issue.valid?).to be_falsey expect(issue).to be_invalid
end end
it 'creates a new spam_log' do
expect { issue }
.to log_spam(title: issue.title, description: issue.description, user_id: user.id, noteable_type: 'Issue')
end
it 'creates a new spam_log' do it 'assigns a spam_log to an issue' do
expect {issue}.to change {SpamLog.count}.from(0).to(1) expect(issue.spam_log).to eq(SpamLog.last)
end
end end
it 'assigns a spam_log to an issue' do context 'when issuable_recaptcha_enabled feature flag is false' do
expect(issue.spam_log).to eq(SpamLog.last) before do
stub_feature_flags(allow_possible_spam: true)
end
it 'does not mark an issue as a spam ' do
expect(issue).not_to be_spam
end
it 'accepts the ​issue as valid' do
expect(issue).to be_valid
end
it 'creates a new spam_log' do
expect { issue }
.to log_spam(title: issue.title, description: issue.description, user_id: user.id, noteable_type: 'Issue')
end
it 'assigns a spam_log to an issue' do
expect(issue.spam_log).to eq(SpamLog.last)
end
end end
end end
context 'when akismet does not detect spam' do context 'when akismet does not detect spam' do
before do before do
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(false) expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: false)
end
end end
it 'does not mark an issue as a spam ' do it 'does not mark an issue as a spam ' do
......
...@@ -44,30 +44,50 @@ describe SpamService do ...@@ -44,30 +44,50 @@ describe SpamService do
end end
context 'when indicated as spam by akismet' do context 'when indicated as spam by akismet' do
shared_examples 'akismet spam' do
it 'doesnt check as spam when request is missing' do
check_spam(issue, nil, false)
expect(issue).not_to be_spam
end
it 'creates a spam log' do
expect { check_spam(issue, request, false) }
.to log_spam(title: issue.title, description: issue.description, noteable_type: 'Issue')
end
it 'does not yield to the block' do
expect(check_spam(issue, request, false))
.to eql(SpamLog.last)
end
end
before do before do
allow(AkismetService).to receive(:new).and_return(double(spam?: true)) allow(AkismetService).to receive(:new).and_return(double(spam?: true))
end end
it 'doesnt check as spam when request is missing' do context 'when allow_possible_spam feature flag is false' do
check_spam(issue, nil, false) before do
stub_feature_flags(allow_possible_spam: false)
end
expect(issue.spam).to be_falsey it_behaves_like 'akismet spam'
end
it 'checks as spam' do it 'checks as spam' do
check_spam(issue, request, false) check_spam(issue, request, false)
expect(issue.spam).to be_truthy expect(issue.spam).to be_truthy
end
end end
it 'creates a spam log' do context 'when allow_possible_spam feature flag is true' do
expect { check_spam(issue, request, false) } it_behaves_like 'akismet spam'
.to change { SpamLog.count }.from(0).to(1)
end it 'does not check as spam' do
check_spam(issue, request, false)
it 'doesnt yield block' do expect(issue.spam).to be_nil
expect(check_spam(issue, request, false)) end
.to eql(SpamLog.last)
end end
end end
......
# frozen_string_literal: true
# This matcher checkes if one spam log with provided attributes was created
#
# Example:
#
# expect { create_issue }.to log_spam
RSpec::Matchers.define :log_spam do |expected|
def spam_logs
SpamLog.all
end
match do |block|
block.call
expect(spam_logs).to contain_exactly(
have_attributes(expected)
)
end
description do
count = spam_logs.count
if count == 1
keys = expected.keys.map(&:to_s)
actual = spam_logs.first.attributes.slice(*keys)
"create a spam log with #{expected} attributes. #{actual} created instead."
else
"create exactly 1 spam log with #{expected} attributes. #{count} spam logs created instead."
end
end
supports_block_expectations
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