Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-02 18:10:54 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-02 18:10:54 +0300
commit8e3523281051490ff696bfd85bea1195c046c87c (patch)
treee44c77aa24136950679151ae70ad6e186987602a /spec
parente2d4c85dec083d517822e3a21165cd373b162d9b (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/admin/applications_controller_spec.rb16
-rw-r--r--spec/controllers/admin/clusters_controller_spec.rb51
-rw-r--r--spec/controllers/application_controller_spec.rb9
-rw-r--r--spec/controllers/groups/clusters_controller_spec.rb33
-rw-r--r--spec/controllers/oauth/applications_controller_spec.rb23
-rw-r--r--spec/controllers/omniauth_callbacks_controller_spec.rb16
-rw-r--r--spec/controllers/profiles/active_sessions_controller_spec.rb23
-rw-r--r--spec/controllers/profiles/two_factor_auths_controller_spec.rb17
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb33
-rw-r--r--spec/controllers/search_controller_spec.rb12
-rw-r--r--spec/controllers/sessions_controller_spec.rb32
-rw-r--r--spec/features/admin/admin_manage_applications_spec.rb18
-rw-r--r--spec/features/issues/service_desk_spec.rb8
-rw-r--r--spec/features/markdown/copy_as_gfm_spec.rb56
-rw-r--r--spec/features/profiles/user_manages_applications_spec.rb13
-rw-r--r--spec/features/users/login_spec.rb12
-rw-r--r--spec/finders/ci/auth_job_finder_spec.rb64
-rw-r--r--spec/finders/user_recent_events_finder_spec.rb37
-rw-r--r--spec/graphql/gitlab_schema_spec.rb49
-rw-r--r--spec/graphql/mutations/boards/lists/create_spec.rb15
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb2
-rw-r--r--spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb12
-rw-r--r--spec/lib/gitlab/auth/auth_finders_spec.rb46
-rw-r--r--spec/lib/gitlab/auth/request_authenticator_spec.rb11
-rw-r--r--spec/lib/gitlab/auth/two_factor_auth_verifier_spec.rb112
-rw-r--r--spec/lib/gitlab/auth_spec.rb72
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb8
-rw-r--r--spec/lib/gitlab/git_access_spec.rb132
-rw-r--r--spec/lib/gitlab/regex_spec.rb9
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb2
-rw-r--r--spec/migrations/20200728182311_add_o_auth_paths_to_protected_paths_spec.rb52
-rw-r--r--spec/models/active_session_spec.rb53
-rw-r--r--spec/models/aws/role_spec.rb6
-rw-r--r--spec/models/member_spec.rb13
-rw-r--r--spec/models/user_spec.rb50
-rw-r--r--spec/requests/api/badges_spec.rb26
-rw-r--r--spec/requests/api/conan_packages_spec.rb45
-rw-r--r--spec/requests/api/generic_packages_spec.rb2
-rw-r--r--spec/requests/api/go_proxy_spec.rb9
-rw-r--r--spec/requests/api/graphql/mutations/boards/lists/create_spec.rb54
-rw-r--r--spec/requests/api/graphql/mutations/snippets/destroy_spec.rb25
-rw-r--r--spec/requests/api/helpers_spec.rb21
-rw-r--r--spec/requests/api/jobs_spec.rb6
-rw-r--r--spec/requests/api/maven_packages_spec.rb33
-rw-r--r--spec/requests/api/npm_packages_spec.rb11
-rw-r--r--spec/requests/api/nuget_packages_spec.rb2
-rw-r--r--spec/requests/api/releases_spec.rb10
-rw-r--r--spec/requests/api/terraform/state_spec.rb11
-rw-r--r--spec/services/applications/create_service_spec.rb19
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb13
-rw-r--r--spec/services/branches/delete_service_spec.rb15
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb18
-rw-r--r--spec/services/clusters/aws/authorize_role_service_spec.rb44
-rw-r--r--spec/services/members/destroy_service_spec.rb40
-rw-r--r--spec/services/notification_service_spec.rb10
-rw-r--r--spec/services/projects/update_remote_mirror_service_spec.rb33
-rw-r--r--spec/spec_helper.rb8
-rw-r--r--spec/support/helpers/stub_object_storage.rb2
-rw-r--r--spec/support/shared_examples/controllers/clusters_controller_shared_examples.rb29
59 files changed, 1354 insertions, 249 deletions
diff --git a/spec/controllers/admin/applications_controller_spec.rb b/spec/controllers/admin/applications_controller_spec.rb
index 732d20666cb..6c423097e70 100644
--- a/spec/controllers/admin/applications_controller_spec.rb
+++ b/spec/controllers/admin/applications_controller_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe Admin::ApplicationsController do
describe 'POST #create' do
it 'creates the application' do
- create_params = attributes_for(:application, trusted: true, confidential: false)
+ create_params = attributes_for(:application, trusted: true, confidential: false, scopes: ['api'])
expect do
post :create, params: { doorkeeper_application: create_params }
@@ -63,7 +63,7 @@ RSpec.describe Admin::ApplicationsController do
context 'when the params are for a confidential application' do
it 'creates a confidential application' do
- create_params = attributes_for(:application, confidential: true)
+ create_params = attributes_for(:application, confidential: true, scopes: ['read_user'])
expect do
post :create, params: { doorkeeper_application: create_params }
@@ -75,6 +75,18 @@ RSpec.describe Admin::ApplicationsController do
expect(application).to have_attributes(create_params.except(:uid, :owner_type))
end
end
+
+ context 'when scopes are not present' do
+ it 'renders the application form on errors' do
+ create_params = attributes_for(:application, trusted: true, confidential: false)
+
+ expect do
+ post :create, params: { doorkeeper_application: create_params }
+ end.not_to change { Doorkeeper::Application.count }
+
+ expect(response).to render_template :new
+ end
+ end
end
describe 'PATCH #update' do
diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb
index 2e0ee671d3f..d2a569a9d48 100644
--- a/spec/controllers/admin/clusters_controller_spec.rb
+++ b/spec/controllers/admin/clusters_controller_spec.rb
@@ -99,7 +99,9 @@ RSpec.describe Admin::ClustersController do
end
describe 'GET #new' do
- def get_new(provider: 'gcp')
+ let(:user) { admin }
+
+ def go(provider: 'gcp')
get :new, params: { provider: provider }
end
@@ -112,7 +114,7 @@ RSpec.describe Admin::ClustersController do
context 'when selected provider is gke and no valid gcp token exists' do
it 'redirects to gcp authorize_url' do
- get_new
+ go
expect(response).to redirect_to(assigns(:authorize_url))
end
@@ -125,7 +127,7 @@ RSpec.describe Admin::ClustersController do
end
it 'does not have authorize_url' do
- get_new
+ go
expect(assigns(:authorize_url)).to be_nil
end
@@ -137,7 +139,7 @@ RSpec.describe Admin::ClustersController do
end
it 'has new object' do
- get_new
+ go
expect(assigns(:gcp_cluster)).to be_an_instance_of(Clusters::ClusterPresenter)
end
@@ -158,16 +160,18 @@ RSpec.describe Admin::ClustersController do
describe 'functionality for existing cluster' do
it 'has new object' do
- get_new
+ go
expect(assigns(:user_cluster)).to be_an_instance_of(Clusters::ClusterPresenter)
end
end
+ include_examples 'GET new cluster shared examples'
+
describe 'security' do
- it { expect { get_new }.to be_allowed_for(:admin) }
- it { expect { get_new }.to be_denied_for(:user) }
- it { expect { get_new }.to be_denied_for(:external) }
+ it { expect { go }.to be_allowed_for(:admin) }
+ it { expect { go }.to be_denied_for(:user) }
+ it { expect { go }.to be_denied_for(:external) }
end
end
@@ -424,14 +428,13 @@ RSpec.describe Admin::ClustersController do
end
describe 'POST authorize AWS role for EKS cluster' do
- let(:role_arn) { 'arn:aws:iam::123456789012:role/role-name' }
- let(:role_external_id) { '12345' }
+ let!(:role) { create(:aws_role, user: admin) }
+ let(:role_arn) { 'arn:new-role' }
let(:params) do
{
cluster: {
- role_arn: role_arn,
- role_external_id: role_external_id
+ role_arn: role_arn
}
}
end
@@ -445,28 +448,32 @@ RSpec.describe Admin::ClustersController do
.and_return(double(execute: double))
end
- it 'creates an Aws::Role record' do
- expect { go }.to change { Aws::Role.count }
+ it 'updates the associated role with the supplied ARN' do
+ go
expect(response).to have_gitlab_http_status(:ok)
-
- role = Aws::Role.last
- expect(role.user).to eq admin
- expect(role.role_arn).to eq role_arn
- expect(role.role_external_id).to eq role_external_id
+ expect(role.reload.role_arn).to eq(role_arn)
end
- context 'role cannot be created' do
+ context 'supplied role is invalid' do
let(:role_arn) { 'invalid-role' }
- it 'does not create a record' do
- expect { go }.not_to change { Aws::Role.count }
+ it 'does not update the associated role' do
+ expect { go }.not_to change { role.role_arn }
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
describe 'security' do
+ before do
+ allow_next_instance_of(Clusters::Aws::AuthorizeRoleService) do |service|
+ response = double(status: :ok, body: double)
+
+ allow(service).to receive(:execute).and_return(response)
+ end
+ end
+
it { expect { go }.to be_allowed_for(:admin) }
it { expect { go }.to be_denied_for(:user) }
it { expect { go }.to be_denied_for(:external) }
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 357044a144c..f8d4690e9ce 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -229,6 +229,7 @@ RSpec.describe ApplicationController do
it 'does not redirect if 2FA is not required' do
allow(controller).to receive(:two_factor_authentication_required?).and_return(false)
+ allow(controller).to receive(:current_user).and_return(create(:user))
expect(controller).not_to receive(:redirect_to)
@@ -346,13 +347,17 @@ RSpec.describe ApplicationController do
let(:user) { create :user, otp_grace_period_started_at: 2.hours.ago }
it 'returns true if the grace period has expired' do
- allow(controller).to receive(:two_factor_grace_period).and_return(1)
+ allow_next_instance_of(Gitlab::Auth::TwoFactorAuthVerifier) do |verifier|
+ allow(verifier).to receive(:two_factor_grace_period).and_return(2)
+ end
expect(subject).to be_truthy
end
it 'returns false if the grace period is still active' do
- allow(controller).to receive(:two_factor_grace_period).and_return(3)
+ allow_next_instance_of(Gitlab::Auth::TwoFactorAuthVerifier) do |verifier|
+ allow(verifier).to receive(:two_factor_grace_period).and_return(3)
+ end
expect(subject).to be_falsey
end
diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb
index 1593e1290c4..81d5bc7770f 100644
--- a/spec/controllers/groups/clusters_controller_spec.rb
+++ b/spec/controllers/groups/clusters_controller_spec.rb
@@ -180,6 +180,8 @@ RSpec.describe Groups::ClustersController do
end
end
+ include_examples 'GET new cluster shared examples'
+
describe 'security' do
it { expect { go }.to be_allowed_for(:admin) }
it { expect { go }.to be_allowed_for(:owner).of(group) }
@@ -493,14 +495,13 @@ RSpec.describe Groups::ClustersController do
end
describe 'POST authorize AWS role for EKS cluster' do
- let(:role_arn) { 'arn:aws:iam::123456789012:role/role-name' }
- let(:role_external_id) { '12345' }
+ let!(:role) { create(:aws_role, user: user) }
+ let(:role_arn) { 'arn:new-role' }
let(:params) do
{
cluster: {
- role_arn: role_arn,
- role_external_id: role_external_id
+ role_arn: role_arn
}
}
end
@@ -514,28 +515,32 @@ RSpec.describe Groups::ClustersController do
.and_return(double(execute: double))
end
- it 'creates an Aws::Role record' do
- expect { go }.to change { Aws::Role.count }
+ it 'updates the associated role with the supplied ARN' do
+ go
expect(response).to have_gitlab_http_status(:ok)
-
- role = Aws::Role.last
- expect(role.user).to eq user
- expect(role.role_arn).to eq role_arn
- expect(role.role_external_id).to eq role_external_id
+ expect(role.reload.role_arn).to eq(role_arn)
end
- context 'role cannot be created' do
+ context 'supplied role is invalid' do
let(:role_arn) { 'invalid-role' }
- it 'does not create a record' do
- expect { go }.not_to change { Aws::Role.count }
+ it 'does not update the associated role' do
+ expect { go }.not_to change { role.role_arn }
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
describe 'security' do
+ before do
+ allow_next_instance_of(Clusters::Aws::AuthorizeRoleService) do |service|
+ response = double(status: :ok, body: double)
+
+ allow(service).to receive(:execute).and_return(response)
+ end
+ end
+
it { expect { go }.to be_allowed_for(:admin) }
it { expect { go }.to be_allowed_for(:owner).of(group) }
it { expect { go }.to be_allowed_for(:maintainer).of(group) }
diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb
index 0a7975b8c1b..f21ef324884 100644
--- a/spec/controllers/oauth/applications_controller_spec.rb
+++ b/spec/controllers/oauth/applications_controller_spec.rb
@@ -123,7 +123,8 @@ RSpec.describe Oauth::ApplicationsController do
invalid_uri_params = {
doorkeeper_application: {
name: 'foo',
- redirect_uri: 'javascript://alert()'
+ redirect_uri: 'javascript://alert()',
+ scopes: ['api']
}
}
@@ -133,6 +134,23 @@ RSpec.describe Oauth::ApplicationsController do
end
end
+ context 'when scopes are not present' do
+ render_views
+
+ it 'shows an error for blank scopes' do
+ invalid_uri_params = {
+ doorkeeper_application: {
+ name: 'foo',
+ redirect_uri: 'http://example.org'
+ }
+ }
+
+ post :create, params: invalid_uri_params
+
+ expect(response.body).to include 'Scopes can&#39;t be blank'
+ end
+ end
+
it_behaves_like 'redirects to login page when the user is not signed in'
it_behaves_like 'redirects to 2fa setup page when the user requires it'
end
@@ -172,7 +190,8 @@ RSpec.describe Oauth::ApplicationsController do
{
doorkeeper_application: {
name: 'foo',
- redirect_uri: 'http://example.org'
+ redirect_uri: 'http://example.org',
+ scopes: ['api']
}
}
end
diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb
index dce996b977d..3f7f0c55f38 100644
--- a/spec/controllers/omniauth_callbacks_controller_spec.rb
+++ b/spec/controllers/omniauth_callbacks_controller_spec.rb
@@ -40,6 +40,22 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
end
end
+ context 'when sign in is not valid' do
+ let(:provider) { :github }
+ let(:extern_uid) { 'my-uid' }
+
+ it 'renders omniauth error page' do
+ allow_next_instance_of(Gitlab::Auth::OAuth::User) do |instance|
+ allow(instance).to receive(:valid_sign_in?).and_return(false)
+ end
+
+ post provider
+
+ expect(response).to render_template("errors/omniauth_error")
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+ end
+
context 'when the user is on the last sign in attempt' do
let(:extern_uid) { 'my-uid' }
diff --git a/spec/controllers/profiles/active_sessions_controller_spec.rb b/spec/controllers/profiles/active_sessions_controller_spec.rb
new file mode 100644
index 00000000000..f54f69d853d
--- /dev/null
+++ b/spec/controllers/profiles/active_sessions_controller_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Profiles::ActiveSessionsController do
+ describe 'DELETE destroy' do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'invalidates all remember user tokens' do
+ ActiveSession.set(user, request)
+ session_id = request.session.id.public_id
+ user.remember_me!
+
+ delete :destroy, params: { id: session_id }
+
+ expect(user.reload.remember_created_at).to be_nil
+ end
+ end
+end
diff --git a/spec/controllers/profiles/two_factor_auths_controller_spec.rb b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
index e6839f54c5d..59eb33f4bc6 100644
--- a/spec/controllers/profiles/two_factor_auths_controller_spec.rb
+++ b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
@@ -14,10 +14,9 @@ RSpec.describe Profiles::TwoFactorAuthsController do
let(:user) { create(:user) }
it 'generates otp_secret for user' do
- expect(User).to receive(:generate_otp_secret).with(32).and_return('secret').once
+ expect(User).to receive(:generate_otp_secret).with(32).and_call_original.once
get :show
- get :show # Second hit shouldn't re-generate it
end
it 'assigns qr_code' do
@@ -27,6 +26,14 @@ RSpec.describe Profiles::TwoFactorAuthsController do
get :show
expect(assigns[:qr_code]).to eq code
end
+
+ it 'generates a unique otp_secret every time the page is loaded' do
+ expect(User).to receive(:generate_otp_secret).with(32).and_call_original.twice
+
+ 2.times do
+ get :show
+ end
+ end
end
describe 'POST create' do
@@ -57,6 +64,12 @@ RSpec.describe Profiles::TwoFactorAuthsController do
expect(assigns[:codes]).to match_array %w(a b c)
end
+ it 'calls to delete other sessions' do
+ expect(ActiveSession).to receive(:destroy_all_but_current)
+
+ go
+ end
+
it 'renders create' do
go
expect(response).to render_template(:create)
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index da4faad2a39..51a451570c5 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -183,6 +183,8 @@ RSpec.describe Projects::ClustersController do
end
end
+ include_examples 'GET new cluster shared examples'
+
describe 'security' do
it 'is allowed for admin when admin mode enabled', :enable_admin_mode do
expect { go }.to be_allowed_for(:admin)
@@ -521,14 +523,13 @@ RSpec.describe Projects::ClustersController do
end
describe 'POST authorize AWS role for EKS cluster' do
- let(:role_arn) { 'arn:aws:iam::123456789012:role/role-name' }
- let(:role_external_id) { '12345' }
+ let!(:role) { create(:aws_role, user: user) }
+ let(:role_arn) { 'arn:new-role' }
let(:params) do
{
cluster: {
- role_arn: role_arn,
- role_external_id: role_external_id
+ role_arn: role_arn
}
}
end
@@ -542,28 +543,32 @@ RSpec.describe Projects::ClustersController do
.and_return(double(execute: double))
end
- it 'creates an Aws::Role record' do
- expect { go }.to change { Aws::Role.count }
+ it 'updates the associated role with the supplied ARN' do
+ go
expect(response).to have_gitlab_http_status(:ok)
-
- role = Aws::Role.last
- expect(role.user).to eq user
- expect(role.role_arn).to eq role_arn
- expect(role.role_external_id).to eq role_external_id
+ expect(role.reload.role_arn).to eq(role_arn)
end
- context 'role cannot be created' do
+ context 'supplied role is invalid' do
let(:role_arn) { 'invalid-role' }
- it 'does not create a record' do
- expect { go }.not_to change { Aws::Role.count }
+ it 'does not update the associated role' do
+ expect { go }.not_to change { role.role_arn }
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
describe 'security' do
+ before do
+ allow_next_instance_of(Clusters::Aws::AuthorizeRoleService) do |service|
+ response = double(status: :ok, body: double)
+
+ allow(service).to receive(:execute).and_return(response)
+ end
+ end
+
it 'is allowed for admin when admin mode enabled', :enable_admin_mode do
expect { go }.to be_allowed_for(:admin)
end
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index d66a0246c2d..4d325f55fb0 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -149,9 +149,15 @@ RSpec.describe SearchController do
expect(assigns[:search_objects].first).to eq note
end
- it_behaves_like 'tracking unique hll events', :show do
- let(:request_params) { { scope: 'projects', search: 'term' } }
- let(:target_id) { 'i_search_total' }
+ context 'unique users tracking' do
+ before do
+ allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
+ end
+
+ it_behaves_like 'tracking unique hll events', :show do
+ let(:request_params) { { scope: 'projects', search: 'term' } }
+ let(:target_id) { 'i_search_total' }
+ end
end
context 'on restricted projects' do
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index 7754fac2fb2..acec1cf22fd 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -261,8 +261,8 @@ RSpec.describe SessionsController do
context 'when using two-factor authentication via OTP' do
let(:user) { create(:user, :two_factor) }
- def authenticate_2fa(user_params)
- post(:create, params: { user: user_params }, session: { otp_user_id: user.id })
+ def authenticate_2fa(user_params, otp_user_id: user.id)
+ post(:create, params: { user: user_params }, session: { otp_user_id: otp_user_id })
end
context 'remember_me field' do
@@ -299,8 +299,22 @@ RSpec.describe SessionsController do
end
end
+ # See issue gitlab-org/gitlab#20302.
+ context 'when otp_user_id is stale' do
+ render_views
+
+ it 'favors login over otp_user_id when password is present and does not authenticate the user' do
+ authenticate_2fa(
+ { login: 'random_username', password: user.password },
+ otp_user_id: user.id
+ )
+
+ expect(response).to set_flash.now[:alert].to /Invalid Login or password/
+ end
+ end
+
##
- # See #14900 issue
+ # See issue gitlab-org/gitlab-foss#14900
#
context 'when authenticating with login and OTP of another user' do
context 'when another user has 2FA enabled' do
@@ -386,18 +400,6 @@ RSpec.describe SessionsController do
end
end
end
-
- context 'when another user does not have 2FA enabled' do
- let(:another_user) { create(:user) }
-
- it 'does not leak that 2FA is disabled for another user' do
- authenticate_2fa(login: another_user.username,
- otp_attempt: 'invalid')
-
- expect(response).to set_flash.now[:alert]
- .to /Invalid two-factor code/
- end
- end
end
end
diff --git a/spec/features/admin/admin_manage_applications_spec.rb b/spec/features/admin/admin_manage_applications_spec.rb
index 3f3d71e842c..7a9a6f2ccb8 100644
--- a/spec/features/admin/admin_manage_applications_spec.rb
+++ b/spec/features/admin/admin_manage_applications_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'admin manage applications' do
sign_in(create(:admin))
end
- it do
+ it 'creates new oauth application' do
visit admin_applications_path
click_on 'New application'
@@ -16,6 +16,7 @@ RSpec.describe 'admin manage applications' do
fill_in :doorkeeper_application_name, with: 'test'
fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
check :doorkeeper_application_trusted
+ check :doorkeeper_application_scopes_read_user
click_on 'Submit'
expect(page).to have_content('Application: test')
expect(page).to have_content('Application ID')
@@ -43,4 +44,19 @@ RSpec.describe 'admin manage applications' do
end
expect(page.find('.oauth-applications')).not_to have_content('test_changed')
end
+
+ context 'when scopes are blank' do
+ it 'returns an error' do
+ visit admin_applications_path
+
+ click_on 'New application'
+ expect(page).to have_content('New application')
+
+ fill_in :doorkeeper_application_name, with: 'test'
+ fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
+ click_on 'Submit'
+
+ expect(page).to have_content("Scopes can't be blank")
+ end
+ end
end
diff --git a/spec/features/issues/service_desk_spec.rb b/spec/features/issues/service_desk_spec.rb
index 666fbe84fae..1512d539dec 100644
--- a/spec/features/issues/service_desk_spec.rb
+++ b/spec/features/issues/service_desk_spec.rb
@@ -109,6 +109,14 @@ RSpec.describe 'Service Desk Issue Tracker', :js do
find('.input-token .filtered-search').native.send_key(:backspace)
expect(page).to have_selector('.js-visual-token', count: 1)
end
+
+ it 'support bot author token has been properly added' do
+ within('.filtered-search-token') do
+ expect(page).to have_selector('.name', count: 1, visible: false)
+ expect(page).to have_selector('.operator', count: 1, visible: false)
+ expect(page).to have_selector('.value-container', count: 1, visible: false)
+ end
+ end
end
end
end
diff --git a/spec/features/markdown/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb
index 57362ed2d54..fbf4e531db1 100644
--- a/spec/features/markdown/copy_as_gfm_spec.rb
+++ b/spec/features/markdown/copy_as_gfm_spec.rb
@@ -30,13 +30,11 @@ RSpec.describe 'Copy as GFM', :js do
it 'works', :aggregate_failures do
verify(
'nesting',
-
'> 1. [x] **[$`2 + 2`$ {-=-}{+=+} 2^2 ~~:thumbsup:~~](http://google.com)**'
)
verify(
'a real world example from the gitlab-ce README',
-
<<~GFM
# GitLab
@@ -103,19 +101,16 @@ RSpec.describe 'Copy as GFM', :js do
verify(
'InlineDiffFilter',
-
'{-Deleted text-}',
'{+Added text+}'
)
verify(
'TaskListFilter',
-
<<~GFM,
* [ ] Unchecked task
* [x] Checked task
GFM
-
<<~GFM
1. [ ] Unchecked ordered task
1. [x] Checked ordered task
@@ -124,7 +119,6 @@ RSpec.describe 'Copy as GFM', :js do
verify(
'ReferenceFilter',
-
# issue reference
@feat.issue.to_reference,
# full issue reference
@@ -141,13 +135,11 @@ RSpec.describe 'Copy as GFM', :js do
verify(
'AutolinkFilter',
-
'https://example.com'
)
verify(
'TableOfContentsFilter',
-
<<~GFM,
[[_TOC_]]
@@ -155,64 +147,53 @@ RSpec.describe 'Copy as GFM', :js do
## Heading 2
GFM
-
pipeline: :wiki,
wiki: @project.wiki
)
verify(
'EmojiFilter',
-
':thumbsup:'
)
verify(
'ImageLinkFilter',
-
'![Image](https://example.com/image.png)'
)
verify_media_with_partial_path(
'[test.txt](/uploads/a123/image.txt)',
-
project_media_uri(@project, '/uploads/a123/image.txt')
)
verify_media_with_partial_path(
'![Image](/uploads/a123/image.png)',
-
project_media_uri(@project, '/uploads/a123/image.png')
)
verify(
'VideoLinkFilter',
-
'![Video](https://example.com/video.mp4)'
)
verify_media_with_partial_path(
'![Video](/uploads/a123/video.mp4)',
-
project_media_uri(@project, '/uploads/a123/video.mp4')
)
verify(
'AudioLinkFilter',
-
'![Audio](https://example.com/audio.wav)'
)
verify_media_with_partial_path(
'![Audio](/uploads/a123/audio.wav)',
-
project_media_uri(@project, '/uploads/a123/audio.wav')
)
verify(
'MathFilter: math as converted from GFM to HTML',
-
'$`c = \pm\sqrt{a^2 + b^2}`$',
-
# math block
<<~GFM
```math
@@ -334,7 +315,6 @@ RSpec.describe 'Copy as GFM', :js do
verify(
'MermaidFilter: mermaid as converted from GFM to HTML',
-
<<~GFM
```mermaid
graph TD;
@@ -429,7 +409,6 @@ RSpec.describe 'Copy as GFM', :js do
verify(
'SuggestionFilter: suggestion as converted from GFM to HTML',
-
<<~GFM
```suggestion
New
@@ -491,7 +470,6 @@ RSpec.describe 'Copy as GFM', :js do
verify(
'SanitizationFilter',
-
<<~GFM
<sub>sub</sub>
@@ -527,13 +505,11 @@ RSpec.describe 'Copy as GFM', :js do
verify(
'SanitizationFilter',
-
<<~GFM,
```
Plain text
```
GFM
-
<<~GFM,
```ruby
def foo
@@ -541,7 +517,6 @@ RSpec.describe 'Copy as GFM', :js do
end
```
GFM
-
<<~GFM
Foo
@@ -553,27 +528,19 @@ RSpec.describe 'Copy as GFM', :js do
verify(
'MarkdownFilter',
-
"Line with two spaces at the end \nto insert a linebreak",
-
'`code`',
'`` code with ` ticks ``',
-
'> Quote',
-
# multiline quote
<<~GFM,
> Multiline Quote
>
> With multiple paragraphs
GFM
-
'![Image](https://example.com/image.png)',
-
'# Heading with no anchor link',
-
'[Link](https://example.com)',
-
<<~GFM,
* List item
* List item 2
@@ -598,7 +565,6 @@ RSpec.describe 'Copy as GFM', :js do
> Blockquote
GFM
-
<<~GFM,
1. Ordered list item
1. Ordered list item 2
@@ -623,22 +589,16 @@ RSpec.describe 'Copy as GFM', :js do
---
GFM
-
'# Heading',
'## Heading',
'### Heading',
'#### Heading',
'##### Heading',
'###### Heading',
-
'**Bold**',
-
'*Italics*',
-
'~~Strikethrough~~',
-
'---',
-
# table
<<~GFM,
| Centered | Right | Left |
@@ -696,9 +656,7 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as inline code' do
verify(
'[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"] .line .no',
-
'`RuntimeError`',
-
target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'
)
end
@@ -708,9 +666,7 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as inline code' do
verify(
'[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]',
-
'`raise RuntimeError, "System commands must be given as an array of strings"`',
-
target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'
)
end
@@ -720,14 +676,12 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as a code block' do
verify(
'[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"]',
-
<<~GFM,
```ruby
raise RuntimeError, "System commands must be given as an array of strings"
end
```
GFM
-
target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'
)
end
@@ -755,7 +709,6 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as a code block' do
verify(
'[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"]',
-
<<~GFM,
```ruby
unless cmd.is_a?(Array)
@@ -763,7 +716,6 @@ RSpec.describe 'Copy as GFM', :js do
end
```
GFM
-
target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"].left-side'
)
end
@@ -773,7 +725,6 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as a code block' do
verify(
'[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"]',
-
<<~GFM,
```ruby
unless cmd.is_a?(Array)
@@ -781,7 +732,6 @@ RSpec.describe 'Copy as GFM', :js do
end
```
GFM
-
target: '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"].right-side'
)
end
@@ -799,7 +749,6 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as inline code' do
verify(
'.line[id="LC9"] .no',
-
'`RuntimeError`'
)
end
@@ -809,7 +758,6 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as inline code' do
verify(
'.line[id="LC9"]',
-
'`raise RuntimeError, "System commands must be given as an array of strings"`'
)
end
@@ -819,7 +767,6 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as a code block' do
verify(
'.line[id="LC9"], .line[id="LC10"]',
-
<<~GFM
```ruby
raise RuntimeError, "System commands must be given as an array of strings"
@@ -841,7 +788,6 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as inline code' do
verify(
'.line[id="LC27"] .nl',
-
'`"bio"`'
)
end
@@ -851,7 +797,6 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as inline code' do
verify(
'.line[id="LC27"]',
-
'`"bio": null,`'
)
end
@@ -861,7 +806,6 @@ RSpec.describe 'Copy as GFM', :js do
it 'copies as a code block with the correct language' do
verify(
'.line[id="LC27"], .line[id="LC28"]',
-
<<~GFM
```json
"bio": null,
diff --git a/spec/features/profiles/user_manages_applications_spec.rb b/spec/features/profiles/user_manages_applications_spec.rb
index d65365db880..22eed748c00 100644
--- a/spec/features/profiles/user_manages_applications_spec.rb
+++ b/spec/features/profiles/user_manages_applications_spec.rb
@@ -15,6 +15,7 @@ RSpec.describe 'User manages applications' do
fill_in :doorkeeper_application_name, with: 'test'
fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
+ check :doorkeeper_application_scopes_read_user
click_on 'Save application'
expect(page).to have_content 'Application: test'
@@ -41,4 +42,16 @@ RSpec.describe 'User manages applications' do
end
expect(page.find('.oauth-applications')).not_to have_content 'test_changed'
end
+
+ context 'when scopes are blank' do
+ it 'returns an error' do
+ expect(page).to have_content 'Add new application'
+
+ fill_in :doorkeeper_application_name, with: 'test'
+ fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
+ click_on 'Save application'
+
+ expect(page).to have_content("Scopes can't be blank")
+ end
+ end
end
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index a2fd1caf6a3..853c381fe6b 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -177,6 +177,14 @@ RSpec.describe 'Login' do
expect(page).not_to have_content(I18n.t('devise.failure.already_authenticated'))
end
+ it 'does not allow sign-in if the user password is updated before entering a one-time code' do
+ user.update!(password: 'new_password')
+
+ enter_code(user.current_otp)
+
+ expect(page).to have_content('An error occurred. Please sign in again.')
+ end
+
context 'using one-time code' do
it 'allows login with valid code' do
expect(authentication_metrics)
@@ -232,7 +240,7 @@ RSpec.describe 'Login' do
expect(codes.size).to eq 10
# Ensure the generated codes get saved
- user.save
+ user.save(touch: false)
end
context 'with valid code' do
@@ -290,7 +298,7 @@ RSpec.describe 'Login' do
code = codes.sample
expect(user.invalidate_otp_backup_code!(code)).to eq true
- user.save!
+ user.save!(touch: false)
expect(user.reload.otp_backup_codes.size).to eq 9
enter_code(code)
diff --git a/spec/finders/ci/auth_job_finder_spec.rb b/spec/finders/ci/auth_job_finder_spec.rb
new file mode 100644
index 00000000000..6cd58f5cd01
--- /dev/null
+++ b/spec/finders/ci/auth_job_finder_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Ci::AuthJobFinder do
+ let_it_be(:job, reload: true) { create(:ci_build, status: :running) }
+
+ let(:token) { job.token }
+
+ subject(:finder) do
+ described_class.new(token: token)
+ end
+
+ describe '#execute!' do
+ subject(:execute) { finder.execute! }
+
+ it { is_expected.to eq(job) }
+
+ it 'raises error if the job is not running' do
+ job.success!
+
+ expect { execute }.to raise_error described_class::NotRunningJobError, 'Job is not running'
+ end
+
+ it 'raises error if the job is erased' do
+ expect(::Ci::Build).to receive(:find_by_token).with(job.token).and_return(job)
+ expect(job).to receive(:erased?).and_return(true)
+
+ expect { execute }.to raise_error described_class::ErasedJobError, 'Job has been erased!'
+ end
+
+ it 'raises error if the the project is missing' do
+ expect(::Ci::Build).to receive(:find_by_token).with(job.token).and_return(job)
+ expect(job).to receive(:project).and_return(nil)
+
+ expect { execute }.to raise_error described_class::DeletedProjectError, 'Project has been deleted!'
+ end
+
+ it 'raises error if the the project is being removed' do
+ project = double(Project)
+
+ expect(::Ci::Build).to receive(:find_by_token).with(job.token).and_return(job)
+ expect(job).to receive(:project).twice.and_return(project)
+ expect(project).to receive(:pending_delete?).and_return(true)
+
+ expect { execute }.to raise_error described_class::DeletedProjectError, 'Project has been deleted!'
+ end
+
+ context 'with wrong job token' do
+ let(:token) { 'missing' }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '#execute' do
+ subject(:execute) { finder.execute }
+
+ before do
+ job.success!
+ end
+
+ it { is_expected.to be_nil }
+ end
+end
diff --git a/spec/finders/user_recent_events_finder_spec.rb b/spec/finders/user_recent_events_finder_spec.rb
index 559d1004b4b..ddba9b595a4 100644
--- a/spec/finders/user_recent_events_finder_spec.rb
+++ b/spec/finders/user_recent_events_finder_spec.rb
@@ -11,8 +11,10 @@ RSpec.describe UserRecentEventsFinder do
let!(:private_event) { create(:event, project: private_project, author: project_owner) }
let!(:internal_event) { create(:event, project: internal_project, author: project_owner) }
let!(:public_event) { create(:event, project: public_project, author: project_owner) }
+ let(:limit) { nil }
+ let(:params) { { limit: limit } }
- subject(:finder) { described_class.new(current_user, project_owner) }
+ subject(:finder) { described_class.new(current_user, project_owner, params) }
describe '#execute' do
context 'when profile is public' do
@@ -48,5 +50,38 @@ RSpec.describe UserRecentEventsFinder do
expect(events).to include(event_b)
end
end
+
+ context 'limits' do
+ before do
+ stub_const("#{described_class}::DEFAULT_LIMIT", 1)
+ stub_const("#{described_class}::MAX_LIMIT", 3)
+ end
+
+ context 'when limit is not set' do
+ it 'returns events limited to DEFAULT_LIMIT' do
+ expect(finder.execute.size).to eq(described_class::DEFAULT_LIMIT)
+ end
+ end
+
+ context 'when limit is set' do
+ let(:limit) { 2 }
+
+ it 'returns events limited to specified limit' do
+ expect(finder.execute.size).to eq(limit)
+ end
+ end
+
+ context 'when limit is set to a number that exceeds maximum limit' do
+ let(:limit) { 4 }
+
+ before do
+ create(:event, project: public_project, author: project_owner)
+ end
+
+ it 'returns events limited to MAX_LIMIT' do
+ expect(finder.execute.size).to eq(described_class::MAX_LIMIT)
+ end
+ end
+ end
end
end
diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb
index 5d6aa863994..4db12643069 100644
--- a/spec/graphql/gitlab_schema_spec.rb
+++ b/spec/graphql/gitlab_schema_spec.rb
@@ -212,6 +212,55 @@ RSpec.describe GitlabSchema do
end
end
+ describe '.parse_gid' do
+ let_it_be(:global_id) { 'gid://gitlab/TestOne/2147483647' }
+
+ before do
+ test_base = Class.new
+ test_one = Class.new(test_base)
+ test_two = Class.new(test_base)
+
+ stub_const('TestBase', test_base)
+ stub_const('TestOne', test_one)
+ stub_const('TestTwo', test_two)
+ end
+
+ it 'parses the gid' do
+ gid = described_class.parse_gid(global_id)
+
+ expect(gid.model_id).to eq '2147483647'
+ expect(gid.model_class).to eq TestOne
+ end
+
+ context 'when gid is malformed' do
+ let_it_be(:global_id) { 'malformed://gitlab/TestOne/2147483647' }
+
+ it 'raises an error' do
+ expect { described_class.parse_gid(global_id) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, "#{global_id} is not a valid GitLab ID.")
+ end
+ end
+
+ context 'when using expected_type' do
+ it 'accepts a single type' do
+ gid = described_class.parse_gid(global_id, expected_type: TestOne)
+
+ expect(gid.model_class).to eq TestOne
+ end
+
+ it 'accepts an ancestor type' do
+ gid = described_class.parse_gid(global_id, expected_type: TestBase)
+
+ expect(gid.model_class).to eq TestOne
+ end
+
+ it 'rejects an unknown type' do
+ expect { described_class.parse_gid(global_id, expected_type: TestTwo) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, "#{global_id} is not a valid ID for TestTwo.")
+ end
+ end
+ end
+
def field_instrumenters
described_class.instrumenters[:field] + described_class.instrumenters[:field_after_built_ins]
end
diff --git a/spec/graphql/mutations/boards/lists/create_spec.rb b/spec/graphql/mutations/boards/lists/create_spec.rb
index 1a881ac81e8..b1fe9911c7b 100644
--- a/spec/graphql/mutations/boards/lists/create_spec.rb
+++ b/spec/graphql/mutations/boards/lists/create_spec.rb
@@ -24,14 +24,12 @@ RSpec.describe Mutations::Boards::Lists::Create do
describe '#ready?' do
it 'raises an error if required arguments are missing' do
expect { mutation.ready?({ board_id: 'some id' }) }
- .to raise_error(Gitlab::Graphql::Errors::ArgumentError,
- 'one and only one of backlog or labelId is required')
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
end
it 'raises an error if too many required arguments are specified' do
expect { mutation.ready?({ board_id: 'some id', backlog: true, label_id: 'some label' }) }
- .to raise_error(Gitlab::Graphql::Errors::ArgumentError,
- 'one and only one of backlog or labelId is required')
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
end
end
@@ -66,6 +64,15 @@ RSpec.describe Mutations::Boards::Lists::Create do
expect(new_list.title).to eq dev_label.title
expect(new_list.position).to eq 0
end
+
+ context 'when label not found' do
+ let(:list_create_params) { { label_id: "gid://gitlab/Label/#{non_existing_record_id}" } }
+
+ it 'raises an error' do
+ expect { subject }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'Label not found!')
+ end
+ end
end
end
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index fcb9efa39d5..153dc19335b 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -75,7 +75,7 @@ RSpec.describe MergeRequestsHelper do
describe '#tab_link_for' do
let(:merge_request) { create(:merge_request, :simple) }
- let(:options) { Hash.new }
+ let(:options) { {} }
subject { tab_link_for(merge_request, :show, options) { 'Discussion' } }
diff --git a/spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb b/spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb
index 70a95d7ba7b..c19b7b63eec 100644
--- a/spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe API::Helpers::PackagesManagerClientsHelpers do
describe '#find_job_from_http_basic_auth' do
let_it_be(:user) { personal_access_token.user }
- let(:job) { create(:ci_build, user: user) }
+ let(:job) { create(:ci_build, user: user, status: :running) }
let(:password) { job.token }
subject { helper.find_job_from_http_basic_auth }
@@ -60,6 +60,16 @@ RSpec.describe API::Helpers::PackagesManagerClientsHelpers do
end
it_behaves_like 'invalid auth header'
+
+ context 'when the job is not running' do
+ before do
+ job.update!(status: :failed)
+ end
+
+ it_behaves_like 'valid auth header' do
+ let(:expected_result) { nil }
+ end
+ end
end
describe '#find_deploy_token_from_http_basic_auth' do
diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb
index a73ac0b34af..1ac8ebe1369 100644
--- a/spec/lib/gitlab/auth/auth_finders_spec.rb
+++ b/spec/lib/gitlab/auth/auth_finders_spec.rb
@@ -37,11 +37,29 @@ RSpec.describe Gitlab::Auth::AuthFinders do
expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError)
end
- it "return user if token is valid" do
- set_token(job.token)
+ context 'with a running job' do
+ before do
+ job.update!(status: :running)
+ end
+
+ it 'return user if token is valid' do
+ set_token(job.token)
+
+ expect(subject).to eq(user)
+ expect(@current_authenticated_job).to eq job
+ end
+ end
- expect(subject).to eq(user)
- expect(@current_authenticated_job).to eq job
+ context 'with a job that is not running' do
+ before do
+ job.update!(status: :failed)
+ end
+
+ it 'returns an Unauthorized exception' do
+ set_token(job.token)
+
+ expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError)
+ end
end
end
end
@@ -557,7 +575,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do
context 'with CI username' do
let(:username) { ::Gitlab::Auth::CI_JOB_USER }
let(:user) { create(:user) }
- let(:build) { create(:ci_build, user: user) }
+ let(:build) { create(:ci_build, user: user, status: :running) }
it 'returns nil without password' do
set_basic_auth_header(username, nil)
@@ -576,6 +594,13 @@ RSpec.describe Gitlab::Auth::AuthFinders do
expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError)
end
+
+ it 'returns exception if the job is not running' do
+ set_basic_auth_header(username, build.token)
+ build.success!
+
+ expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError)
+ end
end
end
@@ -586,7 +611,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do
context 'with a job token' do
let(:route_authentication_setting) { { job_token_allowed: true } }
- let(:job) { create(:ci_build, user: user) }
+ let(:job) { create(:ci_build, user: user, status: :running) }
before do
env['HTTP_AUTHORIZATION'] = "Bearer #{job.token}"
@@ -641,7 +666,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do
end
describe '#find_user_from_job_token' do
- let(:job) { create(:ci_build, user: user) }
+ let(:job) { create(:ci_build, user: user, status: :running) }
let(:route_authentication_setting) { { job_token_allowed: true } }
subject { find_user_from_job_token }
@@ -666,6 +691,13 @@ RSpec.describe Gitlab::Auth::AuthFinders do
expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError)
end
+ it 'returns exception if the job is not running' do
+ set_header(described_class::JOB_TOKEN_HEADER, job.token)
+ job.success!
+
+ expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError)
+ end
+
context 'when route is not allowed to be authenticated' do
let(:route_authentication_setting) { { job_token_allowed: false } }
diff --git a/spec/lib/gitlab/auth/request_authenticator_spec.rb b/spec/lib/gitlab/auth/request_authenticator_spec.rb
index ef83321cc0e..b89ceb37076 100644
--- a/spec/lib/gitlab/auth/request_authenticator_spec.rb
+++ b/spec/lib/gitlab/auth/request_authenticator_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do
describe '#find_user_from_job_token' do
let!(:user) { build(:user) }
- let!(:job) { build(:ci_build, user: user) }
+ let!(:job) { build(:ci_build, user: user, status: :running) }
before do
env[Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER] = 'token'
@@ -97,13 +97,18 @@ RSpec.describe Gitlab::Auth::RequestAuthenticator do
context 'with API requests' do
before do
env['SCRIPT_NAME'] = '/api/endpoint'
+ expect(::Ci::Build).to receive(:find_by_token).with('token').and_return(job)
end
it 'tries to find the user' do
- expect(::Ci::Build).to receive(:find_by_token).and_return(job)
-
expect(subject.find_sessionless_user([:api])).to eq user
end
+
+ it 'returns nil if the job is not running' do
+ job.status = :success
+
+ expect(subject.find_sessionless_user([:api])).to be_blank
+ end
end
context 'without API requests' do
diff --git a/spec/lib/gitlab/auth/two_factor_auth_verifier_spec.rb b/spec/lib/gitlab/auth/two_factor_auth_verifier_spec.rb
new file mode 100644
index 00000000000..f906870195a
--- /dev/null
+++ b/spec/lib/gitlab/auth/two_factor_auth_verifier_spec.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Auth::TwoFactorAuthVerifier do
+ let(:user) { create(:user) }
+
+ subject { described_class.new(user) }
+
+ describe '#two_factor_authentication_required?' do
+ describe 'when it is required on application level' do
+ it 'returns true' do
+ stub_application_setting require_two_factor_authentication: true
+
+ expect(subject.two_factor_authentication_required?).to be_truthy
+ end
+ end
+
+ describe 'when it is required on group level' do
+ it 'returns true' do
+ allow(user).to receive(:require_two_factor_authentication_from_group?).and_return(true)
+
+ expect(subject.two_factor_authentication_required?).to be_truthy
+ end
+ end
+
+ describe 'when it is not required' do
+ it 'returns false when not required on group level' do
+ allow(user).to receive(:require_two_factor_authentication_from_group?).and_return(false)
+
+ expect(subject.two_factor_authentication_required?).to be_falsey
+ end
+ end
+ end
+
+ describe '#current_user_needs_to_setup_two_factor?' do
+ it 'returns false when current_user is nil' do
+ expect(described_class.new(nil).current_user_needs_to_setup_two_factor?).to be_falsey
+ end
+
+ it 'returns false when current_user does not have temp email' do
+ allow(user).to receive(:two_factor_enabled?).and_return(false)
+ allow(user).to receive(:temp_oauth_email?).and_return(true)
+
+ expect(subject.current_user_needs_to_setup_two_factor?).to be_falsey
+ end
+
+ it 'returns false when current_user has 2fa disabled' do
+ allow(user).to receive(:temp_oauth_email?).and_return(false)
+ allow(user).to receive(:two_factor_enabled?).and_return(true)
+
+ expect(subject.current_user_needs_to_setup_two_factor?).to be_falsey
+ end
+
+ it 'returns true when user requires 2fa authentication' do
+ allow(user).to receive(:two_factor_enabled?).and_return(false)
+ allow(user).to receive(:temp_oauth_email?).and_return(false)
+
+ expect(subject.current_user_needs_to_setup_two_factor?).to be_truthy
+ end
+ end
+
+ describe '#two_factor_grace_period' do
+ it 'returns grace period from settings if there is no period from groups' do
+ stub_application_setting two_factor_grace_period: 2
+ allow(user).to receive(:require_two_factor_authentication_from_group?).and_return(false)
+
+ expect(subject.two_factor_grace_period).to eq(2)
+ end
+
+ it 'returns grace period from groups if there is no period from settings' do
+ allow(user).to receive(:require_two_factor_authentication_from_group?).and_return(true)
+ allow(user).to receive(:two_factor_grace_period).and_return(3)
+
+ expect(subject.two_factor_grace_period).to eq(3)
+ end
+
+ it 'returns minimal grace period if there is grace period from settings and from group' do
+ allow(user).to receive(:require_two_factor_authentication_from_group?).and_return(true)
+ allow(user).to receive(:two_factor_grace_period).and_return(3)
+ stub_application_setting two_factor_grace_period: 2
+
+ expect(subject.two_factor_grace_period).to eq(2)
+ end
+ end
+
+ describe '#two_factor_grace_period_expired?' do
+ before do
+ allow(user).to receive(:otp_grace_period_started_at).and_return(4.hours.ago)
+ end
+
+ it 'returns true if the grace period has expired' do
+ allow(subject).to receive(:two_factor_grace_period).and_return(2)
+
+ expect(subject.two_factor_grace_period_expired?).to be_truthy
+ end
+
+ it 'returns false if the grace period has not expired' do
+ allow(subject).to receive(:two_factor_grace_period).and_return(6)
+
+ expect(subject.two_factor_grace_period_expired?).to be_falsey
+ end
+
+ context 'when otp_grace_period_started_at is nil' do
+ it 'returns false' do
+ allow(user).to receive(:otp_grace_period_started_at).and_return(nil)
+
+ expect(subject.two_factor_grace_period_expired?).to be_falsey
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index dcaaa8d4188..b6a8ac31074 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -441,7 +441,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
end
end
- shared_examples 'deploy token with disabled registry' do
+ shared_examples 'deploy token with disabled feature' do
context 'when registry disabled' do
before do
stub_container_registry_config(enabled: false)
@@ -452,6 +452,15 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
.to eq(auth_failure)
end
end
+
+ context 'when repository is disabled' do
+ let(:project) { create(:project, :repository_disabled) }
+
+ it 'fails when login and token are valid' do
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+ end
end
context 'when deploy token and user have the same username' do
@@ -604,7 +613,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
it_behaves_like 'registry token scope'
end
- it_behaves_like 'deploy token with disabled registry'
+ it_behaves_like 'deploy token with disabled feature'
end
context 'when the deploy token has write_registry as a scope' do
@@ -626,7 +635,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
it_behaves_like 'registry token scope'
end
- it_behaves_like 'deploy token with disabled registry'
+ it_behaves_like 'deploy token with disabled feature'
end
end
end
@@ -682,12 +691,69 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
end
+ it 'does not find user in locked state' do
+ user.lock_access!
+
+ expect(gl_auth.find_with_user_password(username, password)).not_to eql user
+ end
+
it "does not find user in ldap_blocked state" do
user.ldap_block
expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
end
+ context 'with increment_failed_attempts' do
+ wrong_password = 'incorrect_password'
+
+ it 'increments failed_attempts when true and password is incorrect' do
+ expect do
+ gl_auth.find_with_user_password(username, wrong_password, increment_failed_attempts: true)
+ user.reload
+ end.to change(user, :failed_attempts).from(0).to(1)
+ end
+
+ it 'resets failed_attempts when true and password is correct' do
+ user.failed_attempts = 2
+ user.save
+
+ expect do
+ gl_auth.find_with_user_password(username, password, increment_failed_attempts: true)
+ user.reload
+ end.to change(user, :failed_attempts).from(2).to(0)
+ end
+
+ it 'does not increment failed_attempts by default' do
+ expect do
+ gl_auth.find_with_user_password(username, wrong_password)
+ user.reload
+ end.not_to change(user, :failed_attempts)
+ end
+
+ context 'when the database is read only' do
+ before do
+ allow(Gitlab::Database).to receive(:read_only?).and_return(true)
+ end
+
+ it 'does not increment failed_attempts when true and password is incorrect' do
+ expect do
+ gl_auth.find_with_user_password(username, wrong_password, increment_failed_attempts: true)
+ user.reload
+ end.not_to change(user, :failed_attempts)
+ end
+
+ it 'does not reset failed_attempts when true and password is correct' do
+ user.failed_attempts = 2
+ user.save
+
+ expect do
+ gl_auth.find_with_user_password(username, password, increment_failed_attempts: true)
+ user.reload
+ end.not_to change(user, :failed_attempts)
+ end
+ end
+ end
+
context "with ldap enabled" do
before do
allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 491437856d4..8961cdcae7d 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -192,7 +192,7 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
end
describe '.find with Gitaly enabled' do
- it_should_behave_like '.find'
+ it_behaves_like '.find'
end
describe '.find with Rugged enabled', :enable_rugged do
@@ -204,7 +204,7 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
described_class.find(repository, SeedRepo::Commit::ID)
end
- it_should_behave_like '.find'
+ it_behaves_like '.find'
end
describe '.last_for_path' do
@@ -474,7 +474,7 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
end
describe '.batch_by_oid with Gitaly enabled' do
- it_should_behave_like '.batch_by_oid'
+ it_behaves_like '.batch_by_oid'
context 'when oids is empty' do
it 'makes no Gitaly request' do
@@ -486,7 +486,7 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
end
describe '.batch_by_oid with Rugged enabled', :enable_rugged do
- it_should_behave_like '.batch_by_oid'
+ it_behaves_like '.batch_by_oid'
it 'calls out to the Rugged implementation' do
allow_next_instance_of(Rugged) do |instance|
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 8153886a2ab..85567ab2e55 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -472,31 +472,135 @@ RSpec.describe Gitlab::GitAccess do
let(:actor) { key }
context 'pull code' do
- context 'when project is authorized' do
- before do
- key.projects << project
+ context 'when project is public' do
+ let(:project) { create(:project, :public, :repository, *options) }
+
+ context 'when deploy key exists in the project' do
+ before do
+ key.projects << project
+ end
+
+ context 'when the repository is public' do
+ let(:options) { %i[repository_enabled] }
+
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'when the repository is private' do
+ let(:options) { %i[repository_private] }
+
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'when the repository is disabled' do
+ let(:options) { %i[repository_disabled] }
+
+ it { expect { pull_access_check }.to raise_error('You are not allowed to download code from this project.') }
+ end
end
- it { expect { pull_access_check }.not_to raise_error }
+ context 'when deploy key does not exist in the project' do
+ context 'when the repository is public' do
+ let(:options) { %i[repository_enabled] }
+
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'when the repository is private' do
+ let(:options) { %i[repository_private] }
+
+ it { expect { pull_access_check }.to raise_error('You are not allowed to download code from this project.') }
+ end
+
+ context 'when the repository is disabled' do
+ let(:options) { %i[repository_disabled] }
+
+ it { expect { pull_access_check }.to raise_error('You are not allowed to download code from this project.') }
+ end
+ end
end
- context 'when unauthorized' do
- context 'from public project' do
- let(:project) { create(:project, :public, :repository) }
+ context 'when project is internal' do
+ let(:project) { create(:project, :internal, :repository, *options) }
- it { expect { pull_access_check }.not_to raise_error }
+ context 'when deploy key exists in the project' do
+ before do
+ key.projects << project
+ end
+
+ context 'when the repository is public' do
+ let(:options) { %i[repository_enabled] }
+
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'when the repository is private' do
+ let(:options) { %i[repository_private] }
+
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'when the repository is disabled' do
+ let(:options) { %i[repository_disabled] }
+
+ it { expect { pull_access_check }.to raise_error('You are not allowed to download code from this project.') }
+ end
end
- context 'from internal project' do
- let(:project) { create(:project, :internal, :repository) }
+ context 'when deploy key does not exist in the project' do
+ context 'when the repository is public' do
+ let(:options) { %i[repository_enabled] }
- it { expect { pull_access_check }.to raise_not_found }
+ it { expect { pull_access_check }.to raise_error('The project you were looking for could not be found.') }
+ end
+
+ context 'when the repository is private' do
+ let(:options) { %i[repository_private] }
+
+ it { expect { pull_access_check }.to raise_error('The project you were looking for could not be found.') }
+ end
+
+ context 'when the repository is disabled' do
+ let(:options) { %i[repository_disabled] }
+
+ it { expect { pull_access_check }.to raise_error('The project you were looking for could not be found.') }
+ end
end
+ end
- context 'from private project' do
- let(:project) { create(:project, :private, :repository) }
+ context 'when project is private' do
+ let(:project) { create(:project, :private, :repository, *options) }
- it { expect { pull_access_check }.to raise_not_found }
+ context 'when deploy key exists in the project' do
+ before do
+ key.projects << project
+ end
+
+ context 'when the repository is private' do
+ let(:options) { %i[repository_private] }
+
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'when the repository is disabled' do
+ let(:options) { %i[repository_disabled] }
+
+ it { expect { pull_access_check }.to raise_error('You are not allowed to download code from this project.') }
+ end
+ end
+
+ context 'when deploy key does not exist in the project' do
+ context 'when the repository is private' do
+ let(:options) { %i[repository_private] }
+
+ it { expect { pull_access_check }.to raise_error('The project you were looking for could not be found.') }
+ end
+
+ context 'when the repository is disabled' do
+ let(:options) { %i[repository_disabled] }
+
+ it { expect { pull_access_check }.to raise_error('The project you were looking for could not be found.') }
+ end
end
end
end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index f736f19ca9a..88c3315150b 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -195,15 +195,6 @@ RSpec.describe Gitlab::Regex do
it { is_expected.not_to match('foo/bar') }
end
- describe '.conan_file_name_regex' do
- subject { described_class.conan_file_name_regex }
-
- it { is_expected.to match('conanfile.py') }
- it { is_expected.to match('conan_package.tgz') }
- it { is_expected.not_to match('foo.txt') }
- it { is_expected.not_to match('!!()()') }
- end
-
describe '.conan_package_reference_regex' do
subject { described_class.conan_package_reference_regex }
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index cac2c410132..e9733851590 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe Gitlab::Workhorse do
context "when the repository doesn't have an archive file path" do
before do
- allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
+ allow(project.repository).to receive(:archive_metadata).and_return({})
end
it "raises an error" do
diff --git a/spec/migrations/20200728182311_add_o_auth_paths_to_protected_paths_spec.rb b/spec/migrations/20200728182311_add_o_auth_paths_to_protected_paths_spec.rb
new file mode 100644
index 00000000000..e12519e15b8
--- /dev/null
+++ b/spec/migrations/20200728182311_add_o_auth_paths_to_protected_paths_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20200728182311_add_o_auth_paths_to_protected_paths.rb')
+
+RSpec.describe AddOAuthPathsToProtectedPaths do
+ subject(:migration) { described_class.new }
+
+ let(:application_settings) { table(:application_settings) }
+ let(:new_paths) do
+ [
+ '/oauth/authorize',
+ '/oauth/token'
+ ]
+ end
+
+ it 'appends new OAuth paths' do
+ application_settings.create!
+
+ protected_paths_before = application_settings.first.protected_paths
+ protected_paths_after = protected_paths_before + new_paths
+
+ expect { migrate! }.to change { application_settings.first.protected_paths }.from(protected_paths_before).to(protected_paths_after)
+ end
+
+ it 'new default includes new paths' do
+ settings_before = application_settings.create!
+
+ expect(settings_before.protected_paths).not_to include(*new_paths)
+
+ migrate!
+
+ application_settings.reset_column_information
+ settings_after = application_settings.create!
+
+ expect(settings_after.protected_paths).to include(*new_paths)
+ end
+
+ it 'does not change the value when the new paths are already included' do
+ application_settings.create!(protected_paths: %w(/users/sign_in /users/password) + new_paths)
+
+ expect { migrate! }.not_to change { application_settings.first.protected_paths }
+ end
+
+ it 'adds one value when the other is already present' do
+ application_settings.create!(protected_paths: %W(/users/sign_in /users/password #{new_paths.first}))
+
+ migrate!
+
+ expect(application_settings.first.protected_paths).to include(new_paths.second)
+ end
+end
diff --git a/spec/models/active_session_spec.rb b/spec/models/active_session_spec.rb
index 24b47be3c69..de39c8c7c5c 100644
--- a/spec/models/active_session_spec.rb
+++ b/spec/models/active_session_spec.rb
@@ -296,6 +296,59 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_shared_state do
end
end
+ describe '.destroy_all_but_current' do
+ it 'gracefully handles a nil session ID' do
+ expect(described_class).not_to receive(:destroy_sessions)
+
+ ActiveSession.destroy_all_but_current(user, nil)
+ end
+
+ context 'with user sessions' do
+ let(:current_session_id) { '6919a6f1bb119dd7396fadc38fd18d0d' }
+
+ before do
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.set(described_class.key_name(user.id, current_session_id),
+ Marshal.dump(ActiveSession.new(session_id: Rack::Session::SessionId.new(current_session_id))))
+ redis.set(described_class.key_name(user.id, '59822c7d9fcdfa03725eff41782ad97d'),
+ Marshal.dump(ActiveSession.new(session_id: Rack::Session::SessionId.new('59822c7d9fcdfa03725eff41782ad97d'))))
+ redis.set(described_class.key_name(9999, '5c8611e4f9c69645ad1a1492f4131358'),
+ Marshal.dump(ActiveSession.new(session_id: Rack::Session::SessionId.new('5c8611e4f9c69645ad1a1492f4131358'))))
+ redis.sadd(described_class.lookup_key_name(user.id), '59822c7d9fcdfa03725eff41782ad97d')
+ redis.sadd(described_class.lookup_key_name(user.id), current_session_id)
+ redis.sadd(described_class.lookup_key_name(9999), '5c8611e4f9c69645ad1a1492f4131358')
+ end
+ end
+
+ it 'removes the entry associated with the all user sessions but current' do
+ expect { ActiveSession.destroy_all_but_current(user, request.session) }.to change { ActiveSession.session_ids_for_user(user.id).size }.from(2).to(1)
+
+ expect(ActiveSession.session_ids_for_user(9999).size).to eq(1)
+ end
+
+ it 'removes the lookup entry of deleted sessions' do
+ ActiveSession.destroy_all_but_current(user, request.session)
+
+ Gitlab::Redis::SharedState.with do |redis|
+ expect(redis.smembers(described_class.lookup_key_name(user.id))).to eq [current_session_id]
+ end
+ end
+
+ it 'does not remove impersonated sessions' do
+ impersonated_session_id = '6919a6f1bb119dd7396fadc38fd18eee'
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.set(described_class.key_name(user.id, impersonated_session_id),
+ Marshal.dump(ActiveSession.new(session_id: Rack::Session::SessionId.new(impersonated_session_id), is_impersonated: true)))
+ redis.sadd(described_class.lookup_key_name(user.id), impersonated_session_id)
+ end
+
+ expect { ActiveSession.destroy_all_but_current(user, request.session) }.to change { ActiveSession.session_ids_for_user(user.id).size }.from(3).to(2)
+
+ expect(ActiveSession.session_ids_for_user(9999).size).to eq(1)
+ end
+ end
+ end
+
describe '.cleanup' do
before do
stub_const("ActiveSession::ALLOWED_NUMBER_OF_ACTIVE_SESSIONS", 5)
diff --git a/spec/models/aws/role_spec.rb b/spec/models/aws/role_spec.rb
index 612868f6eb0..ee93c9d6fad 100644
--- a/spec/models/aws/role_spec.rb
+++ b/spec/models/aws/role_spec.rb
@@ -29,6 +29,12 @@ RSpec.describe Aws::Role do
it { is_expected.to be_truthy }
end
+
+ context 'ARN is nil' do
+ let(:role_arn) { }
+
+ it { is_expected.to be_truthy }
+ end
end
end
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 8da164e041c..b83c769284a 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -195,6 +195,19 @@ RSpec.describe Member do
it { expect(described_class.non_request).to include @accepted_request_member }
end
+ describe '.not_accepted_invitations_by_user' do
+ let(:invited_by_user) { create(:project_member, :invited, project: project, created_by: @owner_user) }
+
+ before do
+ create(:project_member, :invited, invite_email: 'test@test.com', project: project, created_by: @owner_user, invite_accepted_at: Time.zone.now)
+ create(:project_member, :invited, invite_email: 'test2@test.com', project: project, created_by: @maintainer_user)
+ end
+
+ subject { described_class.not_accepted_invitations_by_user(@owner_user) }
+
+ it { is_expected.to contain_exactly(invited_by_user) }
+ end
+
describe '.search_invite_email' do
it 'returns only members the matching e-mail' do
create(:group_member, :invited)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 98f1c5bb2cc..74a36daa727 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -895,6 +895,20 @@ RSpec.describe User do
expect(described_class.without_ghosts).to match_array([user1, user2])
end
end
+
+ describe '.by_id_and_login' do
+ let_it_be(:user) { create(:user) }
+
+ it 'finds a user regardless of case' do
+ expect(described_class.by_id_and_login(user.id, user.username.upcase))
+ .to contain_exactly(user)
+ end
+
+ it 'finds a user when login is an email address regardless of case' do
+ expect(described_class.by_id_and_login(user.id, user.email.upcase))
+ .to contain_exactly(user)
+ end
+ end
end
describe "Respond to" do
@@ -3580,6 +3594,42 @@ RSpec.describe User do
end
end
+ describe '#source_groups_of_two_factor_authentication_requirement' do
+ let_it_be(:group_not_requiring_2FA) { create :group }
+ let(:user) { create :user }
+
+ before do
+ group.add_user(user, GroupMember::OWNER)
+ group_not_requiring_2FA.add_user(user, GroupMember::OWNER)
+ end
+
+ context 'when user is direct member of group requiring 2FA' do
+ let_it_be(:group) { create :group, require_two_factor_authentication: true }
+
+ it 'returns group requiring 2FA' do
+ expect(user.source_groups_of_two_factor_authentication_requirement).to contain_exactly(group)
+ end
+ end
+
+ context 'when user is member of group which parent requires 2FA' do
+ let_it_be(:parent_group) { create :group, require_two_factor_authentication: true }
+ let_it_be(:group) { create :group, parent: parent_group }
+
+ it 'returns group requiring 2FA' do
+ expect(user.source_groups_of_two_factor_authentication_requirement).to contain_exactly(group)
+ end
+ end
+
+ context 'when user is member of group which child requires 2FA' do
+ let_it_be(:group) { create :group }
+ let_it_be(:child_group) { create :group, require_two_factor_authentication: true, parent: group }
+
+ it 'returns group requiring 2FA' do
+ expect(user.source_groups_of_two_factor_authentication_requirement).to contain_exactly(group)
+ end
+ end
+ end
+
describe '.active' do
before do
described_class.ghost
diff --git a/spec/requests/api/badges_spec.rb b/spec/requests/api/badges_spec.rb
index 99d224cb8e9..d8a345a79b0 100644
--- a/spec/requests/api/badges_spec.rb
+++ b/spec/requests/api/badges_spec.rb
@@ -332,10 +332,32 @@ RSpec.describe API::Badges do
context 'when deleting a badge' do
context 'and the source is a project' do
+ let(:badge) { project.group.badges.first }
+
it 'cannot delete badges owned by the project group' do
- delete api("/projects/#{project.id}/badges/#{project_group.badges.first.id}", maintainer)
+ expect do
+ delete api("/projects/#{project.id}/badges/#{badge.id}", maintainer)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end.not_to change { badge.reload.persisted? }
+ end
+ end
+ end
+
+ context 'when updating a badge' do
+ context 'and the source is a project' do
+ let(:badge) { project.group.badges.first }
+ let(:example_name) { 'BadgeName' }
+ let(:example_url) { 'http://www.example.com' }
+ let(:example_url2) { 'http://www.example1.com' }
+
+ it 'cannot update badges owned by the project group' do
+ expect do
+ put api("/projects/#{project.id}/badges/#{badge.id}", maintainer),
+ params: { name: example_name, link_url: example_url, image_url: example_url2 }
- expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response).to have_gitlab_http_status(:not_found)
+ end.not_to change { badge.reload.updated_at }
end
end
end
diff --git a/spec/requests/api/conan_packages_spec.rb b/spec/requests/api/conan_packages_spec.rb
index 58c360d055b..d1ddaa277fc 100644
--- a/spec/requests/api/conan_packages_spec.rb
+++ b/spec/requests/api/conan_packages_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe API::ConanPackages do
let(:base_secret) { SecureRandom.base64(64) }
let(:auth_token) { personal_access_token.token }
- let(:job) { create(:ci_build, user: user) }
+ let(:job) { create(:ci_build, user: user, status: :running) }
let(:job_token) { job.token }
let(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
@@ -94,6 +94,14 @@ RSpec.describe API::ConanPackages do
expect(response).to have_gitlab_http_status(:unauthorized)
end
+ it 'responds with 401 Unauthorized when the job is not running' do
+ job.update!(status: :failed)
+ jwt = build_jwt_from_job(job)
+ get api('/packages/conan/v1/ping'), headers: build_token_auth_header(jwt.encoded)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
context 'packages feature disabled' do
it 'responds with 404 Not Found' do
stub_packages_setting(enabled: false)
@@ -234,6 +242,18 @@ RSpec.describe API::ConanPackages do
end
end
+ shared_examples 'rejects invalid file_name' do |invalid_file_name|
+ let(:file_name) { invalid_file_name }
+
+ context 'with invalid file_name' do
+ it 'returns 400' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+ end
+
shared_examples 'rejects recipe for invalid project' do
context 'with invalid recipe path' do
let(:recipe_path) { 'aa/bb/not-existing-project/ccc' }
@@ -717,8 +737,6 @@ RSpec.describe API::ConanPackages do
context 'without a file from workhorse' do
let(:params) { { file: nil } }
- it_behaves_like 'package workhorse uploads'
-
it 'rejects the request' do
subject
@@ -726,6 +744,10 @@ RSpec.describe API::ConanPackages do
end
end
+ context 'with a file' do
+ it_behaves_like 'package workhorse uploads'
+ end
+
context 'without a token' do
it 'rejects request without a token' do
headers_with_token.delete('HTTP_AUTHORIZATION')
@@ -884,16 +906,22 @@ RSpec.describe API::ConanPackages do
end
describe 'PUT /api/v4/packages/conan/v1/files/:package_name/package_version/:package_username/:package_channel/:recipe_revision/export/:file_name/authorize' do
- subject { put api("/packages/conan/v1/files/#{recipe_path}/0/export/conanfile.py/authorize"), headers: headers_with_token }
+ let(:file_name) { 'conanfile.py' }
+
+ subject { put api("/packages/conan/v1/files/#{recipe_path}/0/export/#{file_name}/authorize"), headers: headers_with_token }
it_behaves_like 'rejects invalid recipe'
+ it_behaves_like 'rejects invalid file_name', 'conanfile.py.git%2fgit-upload-pack'
it_behaves_like 'workhorse authorization'
end
describe 'PUT /api/v4/packages/conan/v1/files/:package_name/package_version/:package_username/:package_channel/:recipe_revision/export/:conan_package_reference/:package_revision/:file_name/authorize' do
- subject { put api("/packages/conan/v1/files/#{recipe_path}/0/package/123456789/0/conaninfo.txt/authorize"), headers: headers_with_token }
+ let(:file_name) { 'conaninfo.txt' }
+
+ subject { put api("/packages/conan/v1/files/#{recipe_path}/0/package/123456789/0/#{file_name}/authorize"), headers: headers_with_token }
it_behaves_like 'rejects invalid recipe'
+ it_behaves_like 'rejects invalid file_name', 'conaninfo.txttest'
it_behaves_like 'workhorse authorization'
end
@@ -907,11 +935,13 @@ RSpec.describe API::ConanPackages do
method: :put,
file_key: :file,
params: params,
+ send_rewritten_field: true,
headers: headers_with_token
)
end
it_behaves_like 'rejects invalid recipe'
+ it_behaves_like 'rejects invalid file_name', 'conanfile.py.git%2fgit-upload-pack'
it_behaves_like 'uploads a package file'
end
@@ -925,12 +955,15 @@ RSpec.describe API::ConanPackages do
method: :put,
file_key: :file,
params: params,
- headers: headers_with_token
+ headers: headers_with_token,
+ send_rewritten_field: true
)
end
it_behaves_like 'rejects invalid recipe'
+ it_behaves_like 'rejects invalid file_name', 'conaninfo.txttest'
it_behaves_like 'uploads a package file'
+
context 'tracking the conan_package.tgz upload' do
let(:file_name) { ::Packages::Conan::FileMetadatum::PACKAGE_BINARY }
diff --git a/spec/requests/api/generic_packages_spec.rb b/spec/requests/api/generic_packages_spec.rb
index e08637629cc..ed852fe75c7 100644
--- a/spec/requests/api/generic_packages_spec.rb
+++ b/spec/requests/api/generic_packages_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe API::GenericPackages do
context 'authenticating using job token' do
it 'responds with 200 OK when valid job token is provided' do
- job_token = create(:ci_build, user: user).token
+ job_token = create(:ci_build, :running, user: user).token
ping(job_token: job_token)
diff --git a/spec/requests/api/go_proxy_spec.rb b/spec/requests/api/go_proxy_spec.rb
index 2d7e319b0be..9d422ebbce2 100644
--- a/spec/requests/api/go_proxy_spec.rb
+++ b/spec/requests/api/go_proxy_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe API::GoProxy do
let_it_be(:base) { "#{Settings.build_gitlab_go_url}/#{project.full_path}" }
let_it_be(:oauth) { create :oauth_access_token, scopes: 'api', resource_owner: user }
- let_it_be(:job) { create :ci_build, user: user }
+ let_it_be(:job) { create :ci_build, user: user, status: :running }
let_it_be(:pa_token) { create :personal_access_token, user: user }
let_it_be(:modules) do
@@ -393,6 +393,13 @@ RSpec.describe API::GoProxy do
expect(response).to have_gitlab_http_status(:ok)
end
+ it 'returns unauthorized with a failed job token' do
+ job.update!(status: :failed)
+ get_resource(oauth_access_token: job)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
it 'returns unauthorized with no authentication' do
get_resource
diff --git a/spec/requests/api/graphql/mutations/boards/lists/create_spec.rb b/spec/requests/api/graphql/mutations/boards/lists/create_spec.rb
new file mode 100644
index 00000000000..328f4fb7b6e
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/boards/lists/create_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Create a label or backlog board list' do
+ include GraphqlHelpers
+
+ let_it_be(:group) { create(:group, :private) }
+ let_it_be(:board) { create(:board, group: group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:dev_label) do
+ create(:group_label, title: 'Development', color: '#FFAABB', group: group)
+ end
+
+ let(:current_user) { user }
+ let(:mutation) { graphql_mutation(:board_list_create, input) }
+ let(:mutation_response) { graphql_mutation_response(:board_list_create) }
+
+ context 'the user is not allowed to read board lists' do
+ let(:input) { { board_id: board.to_global_id.to_s, backlog: true } }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user has permissions to admin board lists' do
+ before do
+ group.add_reporter(current_user)
+ end
+
+ describe 'backlog list' do
+ let(:input) { { board_id: board.to_global_id.to_s, backlog: true } }
+
+ it 'creates the list' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['list'])
+ .to include('position' => nil, 'listType' => 'backlog')
+ end
+ end
+
+ describe 'label list' do
+ let(:input) { { board_id: board.to_global_id.to_s, label_id: dev_label.to_global_id.to_s } }
+
+ it 'creates the list' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['list'])
+ .to include('position' => 0, 'listType' => 'label', 'label' => include('title' => 'Development'))
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb b/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
index 8ade72635af..b71f87d2702 100644
--- a/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
@@ -46,6 +46,31 @@ RSpec.describe 'Destroying a Snippet' do
expect(mutation_response).to have_key('snippet')
expect(mutation_response['snippet']).to be_nil
end
+
+ context 'when a bad gid is given' do
+ let!(:project) { create(:project, :private) }
+ let!(:snippet) { create(:project_snippet, :private, project: project, author: create(:user)) }
+ let!(:snippet_gid) { project.to_gid.to_s }
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors)
+ .to include(a_hash_including('message' => "#{snippet_gid} is not a valid ID for Snippet."))
+ end
+
+ it 'does not destroy the Snippet' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { Snippet.count }
+ end
+
+ it 'does not destroy the Project' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { Project.count }
+ end
+ end
end
end
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 090ff3c1b5a..9c0ea14e3e3 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -85,6 +85,27 @@ RSpec.describe API::Helpers do
end
it { is_expected.to eq(user) }
+
+ context 'when user should have 2fa enabled' do
+ before do
+ allow(user).to receive(:require_two_factor_authentication_from_group?).and_return(true)
+ allow_next_instance_of(Gitlab::Auth::TwoFactorAuthVerifier) do |verifier|
+ allow(verifier).to receive(:two_factor_grace_period_expired?).and_return(true)
+ end
+ end
+
+ context 'when 2fa is not enabled' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'when 2fa is enabled' do
+ before do
+ allow(user).to receive(:two_factor_enabled?).and_return(true)
+ end
+
+ it { is_expected.to eq(user) }
+ end
+ end
end
context "PUT request" do
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index 6555a055678..f90e04bbd2e 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe API::Jobs do
end
describe 'GET /projects/:id/jobs' do
- let(:query) { Hash.new }
+ let(:query) { {} }
before do |example|
unless example.metadata[:skip_before_request]
@@ -167,7 +167,7 @@ RSpec.describe API::Jobs do
end
describe 'GET /projects/:id/pipelines/:pipeline_id/jobs' do
- let(:query) { Hash.new }
+ let(:query) { {} }
before do |example|
unless example.metadata[:skip_before_request]
@@ -296,7 +296,7 @@ RSpec.describe API::Jobs do
project: downstream_pipeline.project)
end
- let(:query) { Hash.new }
+ let(:query) { {} }
before do |example|
unless example.metadata[:skip_before_request]
diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb
index 99588694bab..04d1d2cf1e8 100644
--- a/spec/requests/api/maven_packages_spec.rb
+++ b/spec/requests/api/maven_packages_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe API::MavenPackages do
let_it_be(:package_file) { package.package_files.with_file_name_like('%.xml').first }
let_it_be(:jar_file) { package.package_files.with_file_name_like('%.jar').first }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
- let_it_be(:job) { create(:ci_build, user: user) }
+ let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
@@ -102,11 +102,25 @@ RSpec.describe API::MavenPackages do
end
shared_examples 'downloads with a job token' do
- it 'allows download with job token' do
- download_file(package_file.file_name, job_token: job.token)
+ context 'with a running job' do
+ it 'allows download with job token' do
+ download_file(package_file.file_name, job_token: job.token)
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.media_type).to eq('application/octet-stream')
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.media_type).to eq('application/octet-stream')
+ end
+ end
+
+ context 'with a finished job' do
+ before do
+ job.update!(status: :failed)
+ end
+
+ it 'returns unauthorized error' do
+ download_file(package_file.file_name, job_token: job.token)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
end
end
@@ -569,13 +583,20 @@ RSpec.describe API::MavenPackages do
expect(jar_file.file_name).to eq(file_upload.original_filename)
end
- it 'allows upload with job token' do
+ it 'allows upload with running job token' do
upload_file(params.merge(job_token: job.token))
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload.packages.last.build_info.pipeline).to eq job.pipeline
end
+ it 'rejects upload without running job token' do
+ job.update!(status: :failed)
+ upload_file(params.merge(job_token: job.token))
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
it 'allows upload with deploy token' do
upload_file(params, headers_with_deploy_token)
diff --git a/spec/requests/api/npm_packages_spec.rb b/spec/requests/api/npm_packages_spec.rb
index 94647123df0..108ea84b7e6 100644
--- a/spec/requests/api/npm_packages_spec.rb
+++ b/spec/requests/api/npm_packages_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe API::NpmPackages do
let_it_be(:package, reload: true) { create(:npm_package, project: project) }
let_it_be(:token) { create(:oauth_access_token, scopes: 'api', resource_owner: user) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
- let_it_be(:job) { create(:ci_build, user: user) }
+ let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
@@ -27,12 +27,19 @@ RSpec.describe API::NpmPackages do
expect_a_valid_package_response
end
- it 'returns the package info with job token' do
+ it 'returns the package info with running job token' do
get_package_with_job_token(package)
expect_a_valid_package_response
end
+ it 'denies request without running job token' do
+ job.update!(status: :success)
+ get_package_with_job_token(package)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
it 'denies request without oauth token' do
get_package(package)
diff --git a/spec/requests/api/nuget_packages_spec.rb b/spec/requests/api/nuget_packages_spec.rb
index 37170592b60..62f244c433b 100644
--- a/spec/requests/api/nuget_packages_spec.rb
+++ b/spec/requests/api/nuget_packages_spec.rb
@@ -80,7 +80,7 @@ RSpec.describe API::NugetPackages do
end
with_them do
- let(:job) { user_token ? create(:ci_build, project: project, user: user) : double(token: 'wrong') }
+ let(:job) { user_token ? create(:ci_build, project: project, user: user, status: :running) : double(token: 'wrong') }
let(:headers) { user_role == :anonymous ? {} : job_basic_auth_header(job) }
subject { get api(url), headers: headers }
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
index a9a92a4d3cd..779ae983886 100644
--- a/spec/requests/api/releases_spec.rb
+++ b/spec/requests/api/releases_spec.rb
@@ -671,12 +671,20 @@ RSpec.describe API::Releases do
end
context 'when a valid token is provided' do
- it 'creates the release' do
+ it 'creates the release for a running job' do
+ job.update!(status: :running)
post api("/projects/#{project.id}/releases"), params: params.merge(job_token: job.token)
expect(response).to have_gitlab_http_status(:created)
expect(project.releases.last.description).to eq('Another nice release')
end
+
+ it 'returns an :unauthorized error for a completed job' do
+ job.success!
+ post api("/projects/#{project.id}/releases"), params: params.merge(job_token: job.token)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
end
end
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index c6cba39314b..c47a12456c3 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe API::Terraform::State do
let(:auth_header) { job_basic_auth_header(job) }
context 'with maintainer permissions' do
- let(:job) { create(:ci_build, project: project, user: maintainer) }
+ let(:job) { create(:ci_build, status: :running, project: project, user: maintainer) }
it 'returns terraform state belonging to a project of given state name' do
request
@@ -81,6 +81,13 @@ RSpec.describe API::Terraform::State do
expect(response.body).to eq(state.file.read)
end
+ it 'returns unauthorized if the the job is not running' do
+ job.update!(status: :failed)
+ request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
context 'for a project that does not exist' do
let(:project_id) { '0000' }
@@ -93,7 +100,7 @@ RSpec.describe API::Terraform::State do
end
context 'with developer permissions' do
- let(:job) { create(:ci_build, project: project, user: developer) }
+ let(:job) { create(:ci_build, status: :running, project: project, user: developer) }
it 'returns terraform state belonging to a project of given state name' do
request
diff --git a/spec/services/applications/create_service_spec.rb b/spec/services/applications/create_service_spec.rb
index 58ac723ee55..8b8beb057a9 100644
--- a/spec/services/applications/create_service_spec.rb
+++ b/spec/services/applications/create_service_spec.rb
@@ -6,9 +6,24 @@ RSpec.describe ::Applications::CreateService do
include TestRequestHelpers
let(:user) { create(:user) }
- let(:params) { attributes_for(:application) }
subject { described_class.new(user, params) }
- it { expect { subject.execute(test_request) }.to change { Doorkeeper::Application.count }.by(1) }
+ context 'when scopes are present' do
+ let(:params) { attributes_for(:application, scopes: ['read_user']) }
+
+ it { expect { subject.execute(test_request) }.to change { Doorkeeper::Application.count }.by(1) }
+ end
+
+ context 'when scopes are missing' do
+ let(:params) { attributes_for(:application) }
+
+ it { expect { subject.execute(test_request) }.not_to change { Doorkeeper::Application.count } }
+
+ it 'includes blank scopes error message' do
+ application = subject.execute(test_request)
+
+ expect(application.errors.full_messages).to include "Scopes can't be blank"
+ end
+ end
end
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 8d58c4b27e1..bc85f4f0087 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -654,6 +654,19 @@ RSpec.describe Auth::ContainerRegistryAuthenticationService do
it_behaves_like 'not a container repository factory'
end
end
+
+ context 'for project that disables repository' do
+ let(:project) { create(:project, :public, :repository_disabled) }
+
+ context 'disallow when pulling' do
+ let(:current_params) do
+ { scopes: ["repository:#{project.full_path}:pull"] }
+ end
+
+ it_behaves_like 'an inaccessible'
+ it_behaves_like 'not a container repository factory'
+ end
+ end
end
context 'registry catalog browsing authorized as admin' do
diff --git a/spec/services/branches/delete_service_spec.rb b/spec/services/branches/delete_service_spec.rb
index f1e7c9340b1..291431c1723 100644
--- a/spec/services/branches/delete_service_spec.rb
+++ b/spec/services/branches/delete_service_spec.rb
@@ -37,6 +37,21 @@ RSpec.describe Branches::DeleteService do
end
it_behaves_like 'a deleted branch', 'feature'
+
+ context 'when Gitlab::Git::CommandError is raised' do
+ before do
+ allow(repository).to receive(:rm_branch) do
+ raise Gitlab::Git::CommandError.new('Could not update patch')
+ end
+ end
+
+ it 'handles and returns error' do
+ result = service.execute('feature')
+
+ expect(result.status).to eq(:error)
+ expect(result.message).to eq('Could not update patch')
+ end
+ end
end
context 'when user does not have access to push to repository' do
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
index 18fab9623ec..ac077e3c30e 100644
--- a/spec/services/ci/pipeline_trigger_service_spec.rb
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -106,9 +106,23 @@ RSpec.describe Ci::PipelineTriggerService do
let(:params) { { token: job.token, ref: 'master', variables: nil } }
let(:job) { create(:ci_build, :success, pipeline: pipeline, user: user) }
- it 'does nothing' do
+ it 'does nothing', :aggregate_failures do
+ expect { result }.not_to change { Ci::Pipeline.count }
+ expect(result[:message]).to eq('Job is not running')
+ expect(result[:http_status]).to eq(401)
+ end
+ end
+
+ context 'when job does not have a project' do
+ let(:params) { { token: job.token, ref: 'master', variables: nil } }
+ let(:job) { create(:ci_build, status: :running, pipeline: pipeline, user: user) }
+
+ it 'does nothing', :aggregate_failures do
+ job.update!(project: nil)
+
expect { result }.not_to change { Ci::Pipeline.count }
- expect(result[:message]).to eq('400 Job has to be running')
+ expect(result[:message]).to eq('Project has been deleted!')
+ expect(result[:http_status]).to eq(401)
end
end
diff --git a/spec/services/clusters/aws/authorize_role_service_spec.rb b/spec/services/clusters/aws/authorize_role_service_spec.rb
index 3d12400a47b..5b47cf0ecde 100644
--- a/spec/services/clusters/aws/authorize_role_service_spec.rb
+++ b/spec/services/clusters/aws/authorize_role_service_spec.rb
@@ -3,47 +3,34 @@
require 'spec_helper'
RSpec.describe Clusters::Aws::AuthorizeRoleService do
- let(:user) { create(:user) }
+ subject { described_class.new(user, params: params).execute }
+
+ let(:role) { create(:aws_role) }
+ let(:user) { role.user }
let(:credentials) { instance_double(Aws::Credentials) }
let(:credentials_service) { instance_double(Clusters::Aws::FetchCredentialsService, execute: credentials) }
+ let(:role_arn) { 'arn:my-role' }
let(:params) do
params = ActionController::Parameters.new({
cluster: {
- role_arn: 'arn:my-role',
- role_external_id: 'external-id'
+ role_arn: role_arn
}
})
- params.require(:cluster).permit(:role_arn, :role_external_id)
+ params.require(:cluster).permit(:role_arn)
end
- subject { described_class.new(user, params: params).execute }
-
before do
allow(Clusters::Aws::FetchCredentialsService).to receive(:new)
.with(instance_of(Aws::Role)).and_return(credentials_service)
end
- context 'role does not exist' do
- it 'creates an Aws::Role record and returns a set of credentials' do
- expect(user).to receive(:create_aws_role!)
- .with(params).and_call_original
-
- expect(subject.status).to eq(:ok)
- expect(subject.body).to eq(credentials)
- end
- end
-
- context 'role already exists' do
- let(:role) { create(:aws_role, user: user) }
-
+ context 'role exists' do
it 'updates the existing Aws::Role record and returns a set of credentials' do
- expect(role).to receive(:update!)
- .with(params).and_call_original
-
expect(subject.status).to eq(:ok)
expect(subject.body).to eq(credentials)
+ expect(role.reload.role_arn).to eq(role_arn)
end
end
@@ -61,11 +48,14 @@ RSpec.describe Clusters::Aws::AuthorizeRoleService do
end
end
- context 'cannot create role' do
- before do
- allow(user).to receive(:create_aws_role!)
- .and_raise(ActiveRecord::RecordInvalid.new(user))
- end
+ context 'role does not exist' do
+ let(:user) { create(:user) }
+
+ include_examples 'bad request'
+ end
+
+ context 'supplied ARN is invalid' do
+ let(:role_arn) { 'invalid' }
include_examples 'bad request'
end
diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb
index 13e7b4c1006..5c90f1f54ea 100644
--- a/spec/services/members/destroy_service_spec.rb
+++ b/spec/services/members/destroy_service_spec.rb
@@ -292,6 +292,10 @@ RSpec.describe Members::DestroyService do
before do
create(:group_member, :developer, group: subsubgroup, user: member_user)
+ create(:project_member, :invited, project: group_project, created_by: member_user)
+ create(:group_member, :invited, group: group, created_by: member_user)
+ create(:project_member, :invited, project: subsubproject, created_by: member_user)
+ create(:group_member, :invited, group: subgroup, created_by: member_user)
subsubproject.add_developer(member_user)
control_project.add_maintainer(user)
@@ -325,5 +329,41 @@ RSpec.describe Members::DestroyService do
it 'does not remove the user from the control project' do
expect(control_project.members.map(&:user)).to include(user)
end
+
+ it 'removes group members invited by deleted user' do
+ expect(group.members.not_accepted_invitations_by_user(member_user)).to be_empty
+ end
+
+ it 'removes project members invited by deleted user' do
+ expect(group_project.members.not_accepted_invitations_by_user(member_user)).to be_empty
+ end
+
+ it 'removes subgroup members invited by deleted user' do
+ expect(subgroup.members.not_accepted_invitations_by_user(member_user)).to be_empty
+ end
+
+ it 'removes subproject members invited by deleted user' do
+ expect(subsubproject.members.not_accepted_invitations_by_user(member_user)).to be_empty
+ end
+ end
+
+ context 'deletion of invitations created by deleted project member' do
+ let(:user) { project.owner }
+ let(:member_user) { create(:user) }
+ let(:opts) { {} }
+
+ let(:project) { create(:project) }
+
+ before do
+ create(:project_member, :invited, project: project, created_by: member_user)
+
+ project_member = create(:project_member, :maintainer, user: member_user, project: project)
+
+ described_class.new(user).execute(project_member, opts)
+ end
+
+ it 'removes project members invited by deleted user' do
+ expect(project.members.not_accepted_invitations_by_user(member_user)).to be_empty
+ end
end
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 47bc6bcd989..87d6f99e8aa 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -151,9 +151,9 @@ RSpec.describe NotificationService, :mailer do
end
shared_examples_for 'participating notifications' do
- it_should_behave_like 'participating by note notification'
- it_should_behave_like 'participating by author notification'
- it_should_behave_like 'participating by assignee notification'
+ it_behaves_like 'participating by note notification'
+ it_behaves_like 'participating by author notification'
+ it_behaves_like 'participating by assignee notification'
end
describe '#async' do
@@ -1682,13 +1682,13 @@ RSpec.describe NotificationService, :mailer do
end
context 'participating' do
- it_should_behave_like 'participating by assignee notification' do
+ it_behaves_like 'participating by assignee notification' do
let(:participant) { create(:user, username: 'user-participant')}
let(:issuable) { merge_request }
let(:notification_trigger) { notification.new_merge_request(merge_request, @u_disabled) }
end
- it_should_behave_like 'participating by note notification' do
+ it_behaves_like 'participating by note notification' do
let(:participant) { create(:user, username: 'user-participant')}
let(:issuable) { merge_request }
let(:notification_trigger) { notification.new_merge_request(merge_request, @u_disabled) }
diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb
index 09244db8010..a452f88c75f 100644
--- a/spec/services/projects/update_remote_mirror_service_spec.rb
+++ b/spec/services/projects/update_remote_mirror_service_spec.rb
@@ -56,6 +56,39 @@ RSpec.describe Projects::UpdateRemoteMirrorService do
expect(remote_mirror.last_error).to include('Badly broken')
end
+ context 'when the URL is blocked' do
+ before do
+ allow(Gitlab::UrlBlocker).to receive(:blocked_url?).and_return(true)
+ end
+
+ it 'fails and returns error status' do
+ expect(execute!).to eq(status: :error, message: 'The remote mirror URL is invalid.')
+ end
+ end
+
+ context "when given URLs containing escaped elements" do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:url, :result_status) do
+ "https://user:0a%23@test.example.com/project.git" | :success
+ "https://git.example.com:1%2F%2F@source.developers.google.com/project.git" | :success
+ CGI.escape("git://localhost:1234/some-path?some-query=some-val\#@example.com/") | :error
+ CGI.escape(CGI.escape("https://user:0a%23@test.example.com/project.git")) | :error
+ end
+
+ with_them do
+ before do
+ allow(remote_mirror).to receive(:url).and_return(url)
+ end
+
+ it "returns expected status" do
+ result = execute!
+
+ expect(result[:status]).to eq(result_status)
+ end
+ end
+ end
+
context 'when the update fails because of a `Gitlab::Git::CommandError`' do
before do
allow(remote_mirror).to receive(:update_repository)
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 395930c8cbc..06ec97d65b2 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -47,10 +47,10 @@ require_relative('../ee/spec/spec_helper') if Gitlab.ee?
require Rails.root.join("spec/support/helpers/git_helpers.rb")
# Then the rest
-Dir[Rails.root.join("spec/support/helpers/*.rb")].each { |f| require f }
-Dir[Rails.root.join("spec/support/shared_contexts/*.rb")].each { |f| require f }
-Dir[Rails.root.join("spec/support/shared_examples/*.rb")].each { |f| require f }
-Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
+Dir[Rails.root.join("spec/support/helpers/*.rb")].sort.each { |f| require f }
+Dir[Rails.root.join("spec/support/shared_contexts/*.rb")].sort.each { |f| require f }
+Dir[Rails.root.join("spec/support/shared_examples/*.rb")].sort.each { |f| require f }
+Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |f| require f }
quality_level = Quality::TestLevel.new
diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb
index 0486eccf48c..476b7d34ee5 100644
--- a/spec/support/helpers/stub_object_storage.rb
+++ b/spec/support/helpers/stub_object_storage.rb
@@ -21,7 +21,7 @@ module StubObjectStorage
proxy_download: false,
background_upload: false,
direct_upload: false
- )
+ )
allow(config).to receive(:enabled) { enabled }
allow(config).to receive(:proxy_download) { proxy_download }
allow(config).to receive(:background_upload) { background_upload }
diff --git a/spec/support/shared_examples/controllers/clusters_controller_shared_examples.rb b/spec/support/shared_examples/controllers/clusters_controller_shared_examples.rb
new file mode 100644
index 00000000000..aa17e72d08e
--- /dev/null
+++ b/spec/support/shared_examples/controllers/clusters_controller_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'GET new cluster shared examples' do
+ describe 'EKS cluster' do
+ context 'user already has an associated AWS role' do
+ let!(:role) { create(:aws_role, user: user) }
+
+ it 'does not create an Aws::Role record' do
+ expect { go(provider: 'aws') }.not_to change { Aws::Role.count }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(assigns(:aws_role)).to eq(role)
+ end
+ end
+
+ context 'user does not have an associated AWS role' do
+ it 'creates an Aws::Role record' do
+ expect { go(provider: 'aws') }.to change { Aws::Role.count }
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ role = assigns(:aws_role)
+ expect(role.user).to eq(user)
+ expect(role.role_arn).to be_nil
+ expect(role.role_external_id).to be_present
+ end
+ end
+ end
+end